diff --git a/build/Makefile b/build/Makefile
index 383c24a26929407b065e76e5cd7216b67674334d..09ceb6fb2905cdb59e1ce8181e8b7d2e061824ce 100644
--- a/build/Makefile
+++ b/build/Makefile
@@ -29,7 +29,7 @@ VERSION = $(shell perl -lne \
 SOURCES = src/internal.h src/util.c src/string.c src/parse_date.c \
           src/options.c src/crypto.c src/auth.c src/win32.c src/unix.c \
           src/mg_printf.c src/ssl.c src/http_client.c src/mime.c \
-          src/directory.c src/mongoose.c src/lua.c
+          src/directory.c src/log.c src/mongoose.c src/lua.c
 
 TINY_SOURCES = ../mongoose.c main.c
 LUA_SOURCES = $(TINY_SOURCES) sqlite3.c lsqlite3.c lua_5.2.1.c
diff --git a/build/src/log.c b/build/src/log.c
new file mode 100644
index 0000000000000000000000000000000000000000..07b7150e10ba8839cc8d5b3205622e054d1727bc
--- /dev/null
+++ b/build/src/log.c
@@ -0,0 +1,44 @@
+#include "internal.h"
+
+static void log_header(const struct mg_connection *conn, const char *header,
+                       FILE *fp) {
+  const char *header_value;
+
+  if ((header_value = mg_get_header(conn, header)) == NULL) {
+    (void) fprintf(fp, "%s", " -");
+  } else {
+    (void) fprintf(fp, " \"%s\"", header_value);
+  }
+}
+
+static void log_access(const struct mg_connection *conn) {
+  const struct mg_request_info *ri;
+  FILE *fp;
+  char date[64], src_addr[IP_ADDR_STR_LEN];
+
+  fp = conn->ctx->config[ACCESS_LOG_FILE] == NULL ?  NULL :
+    fopen(conn->ctx->config[ACCESS_LOG_FILE], "a+");
+
+  if (fp == NULL)
+    return;
+
+  strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z",
+           localtime(&conn->birth_time));
+
+  ri = &conn->request_info;
+  flockfile(fp);
+
+  sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
+  fprintf(fp, "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT,
+          src_addr, ri->remote_user == NULL ? "-" : ri->remote_user, date,
+          ri->request_method ? ri->request_method : "-",
+          ri->uri ? ri->uri : "-", ri->http_version,
+          conn->status_code, conn->num_bytes_sent);
+  log_header(conn, "Referer", fp);
+  log_header(conn, "User-Agent", fp);
+  fputc('\n', fp);
+  fflush(fp);
+
+  funlockfile(fp);
+  fclose(fp);
+}
diff --git a/build/src/mongoose.c b/build/src/mongoose.c
index b987aabe5fd962efe116cc8a6e8aa194ad9873b1..102ae60f0c5b70fd59e76057f5797ac58d68700d 100644
--- a/build/src/mongoose.c
+++ b/build/src/mongoose.c
@@ -28,21 +28,6 @@ static FILE *mg_fopen(const char *path, const char *mode) {
 #endif
 }
 
-static void sockaddr_to_string(char *buf, size_t len,
-                                     const union usa *usa) {
-  buf[0] = '\0';
-#if defined(USE_IPV6)
-  inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ?
-            (void *) &usa->sin.sin_addr :
-            (void *) &usa->sin6.sin6_addr, buf, len);
-#elif defined(_WIN32)
-  // Only Windoze Vista (and newer) have inet_ntop()
-  strncpy(buf, inet_ntoa(usa->sin.sin_addr), len);
-#else
-  inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
-#endif
-}
-
 // Print error message to the opened error log stream.
 static void cry(struct mg_connection *conn, const char *fmt, ...) {
   char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN];
@@ -2122,49 +2107,6 @@ static int set_ports_option(struct mg_context *ctx) {
   return success;
 }
 
-static void log_header(const struct mg_connection *conn, const char *header,
-                       FILE *fp) {
-  const char *header_value;
-
-  if ((header_value = mg_get_header(conn, header)) == NULL) {
-    (void) fprintf(fp, "%s", " -");
-  } else {
-    (void) fprintf(fp, " \"%s\"", header_value);
-  }
-}
-
-static void log_access(const struct mg_connection *conn) {
-  const struct mg_request_info *ri;
-  FILE *fp;
-  char date[64], src_addr[IP_ADDR_STR_LEN];
-
-  fp = conn->ctx->config[ACCESS_LOG_FILE] == NULL ?  NULL :
-    fopen(conn->ctx->config[ACCESS_LOG_FILE], "a+");
-
-  if (fp == NULL)
-    return;
-
-  strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z",
-           localtime(&conn->birth_time));
-
-  ri = &conn->request_info;
-  flockfile(fp);
-
-  sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
-  fprintf(fp, "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT,
-          src_addr, ri->remote_user == NULL ? "-" : ri->remote_user, date,
-          ri->request_method ? ri->request_method : "-",
-          ri->uri ? ri->uri : "-", ri->http_version,
-          conn->status_code, conn->num_bytes_sent);
-  log_header(conn, "Referer", fp);
-  log_header(conn, "User-Agent", fp);
-  fputc('\n', fp);
-  fflush(fp);
-
-  funlockfile(fp);
-  fclose(fp);
-}
-
 // Verify given socket address against the ACL.
 // Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
 static int check_acl(struct mg_context *ctx, uint32_t remote_ip) {
diff --git a/build/src/util.c b/build/src/util.c
index 0d0a05ed6608bba008f19383cc4033fb7acb2674..d1144c694a30292d8949a591ae6f601503fac0ea 100644
--- a/build/src/util.c
+++ b/build/src/util.c
@@ -9,3 +9,18 @@ static struct mg_connection *fc(struct mg_context *ctx) {
   fake_connection.event.user_data = ctx->user_data;
   return &fake_connection;
 }
+
+static void sockaddr_to_string(char *buf, size_t len,
+                                     const union usa *usa) {
+  buf[0] = '\0';
+#if defined(USE_IPV6)
+  inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ?
+            (void *) &usa->sin.sin_addr :
+            (void *) &usa->sin6.sin6_addr, buf, len);
+#elif defined(_WIN32)
+  // Only Windoze Vista (and newer) have inet_ntop()
+  strncpy(buf, inet_ntoa(usa->sin.sin_addr), len);
+#else
+  inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
+#endif
+}
diff --git a/mongoose.c b/mongoose.c
index a43b98e5bddb1154a711602e3f3522e91d8ac7c4..07017ba3b19619f1dce4fc2151d50432ee099284 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -480,6 +480,22 @@ static struct mg_connection *fc(struct mg_context *ctx) {
   return &fake_connection;
 }
 
+static void sockaddr_to_string(char *buf, size_t len,
+                                     const union usa *usa) {
+  buf[0] = '\0';
+#if defined(USE_IPV6)
+  inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ?
+            (void *) &usa->sin.sin_addr :
+            (void *) &usa->sin6.sin6_addr, buf, len);
+#elif defined(_WIN32)
+  // Only Windoze Vista (and newer) have inet_ntop()
+  strncpy(buf, inet_ntoa(usa->sin.sin_addr), len);
+#else
+  inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
+#endif
+}
+
+
 static void mg_strlcpy(register char *dst, register const char *src, size_t n) {
   for (; *src != '\0' && n > 1; n--) {
     *dst++ = *src++;
@@ -2594,6 +2610,49 @@ static void handle_directory_request(struct mg_connection *conn,
 }
 
 
+static void log_header(const struct mg_connection *conn, const char *header,
+                       FILE *fp) {
+  const char *header_value;
+
+  if ((header_value = mg_get_header(conn, header)) == NULL) {
+    (void) fprintf(fp, "%s", " -");
+  } else {
+    (void) fprintf(fp, " \"%s\"", header_value);
+  }
+}
+
+static void log_access(const struct mg_connection *conn) {
+  const struct mg_request_info *ri;
+  FILE *fp;
+  char date[64], src_addr[IP_ADDR_STR_LEN];
+
+  fp = conn->ctx->config[ACCESS_LOG_FILE] == NULL ?  NULL :
+    fopen(conn->ctx->config[ACCESS_LOG_FILE], "a+");
+
+  if (fp == NULL)
+    return;
+
+  strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z",
+           localtime(&conn->birth_time));
+
+  ri = &conn->request_info;
+  flockfile(fp);
+
+  sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
+  fprintf(fp, "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT,
+          src_addr, ri->remote_user == NULL ? "-" : ri->remote_user, date,
+          ri->request_method ? ri->request_method : "-",
+          ri->uri ? ri->uri : "-", ri->http_version,
+          conn->status_code, conn->num_bytes_sent);
+  log_header(conn, "Referer", fp);
+  log_header(conn, "User-Agent", fp);
+  fputc('\n', fp);
+  fflush(fp);
+
+  funlockfile(fp);
+  fclose(fp);
+}
+
 // Return number of bytes left to read for this connection
 static int64_t left_to_read(const struct mg_connection *conn) {
   return conn->content_len + conn->request_len - conn->num_bytes_read;
@@ -2622,21 +2681,6 @@ static FILE *mg_fopen(const char *path, const char *mode) {
 #endif
 }
 
-static void sockaddr_to_string(char *buf, size_t len,
-                                     const union usa *usa) {
-  buf[0] = '\0';
-#if defined(USE_IPV6)
-  inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ?
-            (void *) &usa->sin.sin_addr :
-            (void *) &usa->sin6.sin6_addr, buf, len);
-#elif defined(_WIN32)
-  // Only Windoze Vista (and newer) have inet_ntop()
-  strncpy(buf, inet_ntoa(usa->sin.sin_addr), len);
-#else
-  inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
-#endif
-}
-
 // Print error message to the opened error log stream.
 static void cry(struct mg_connection *conn, const char *fmt, ...) {
   char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN];
@@ -4716,49 +4760,6 @@ static int set_ports_option(struct mg_context *ctx) {
   return success;
 }
 
-static void log_header(const struct mg_connection *conn, const char *header,
-                       FILE *fp) {
-  const char *header_value;
-
-  if ((header_value = mg_get_header(conn, header)) == NULL) {
-    (void) fprintf(fp, "%s", " -");
-  } else {
-    (void) fprintf(fp, " \"%s\"", header_value);
-  }
-}
-
-static void log_access(const struct mg_connection *conn) {
-  const struct mg_request_info *ri;
-  FILE *fp;
-  char date[64], src_addr[IP_ADDR_STR_LEN];
-
-  fp = conn->ctx->config[ACCESS_LOG_FILE] == NULL ?  NULL :
-    fopen(conn->ctx->config[ACCESS_LOG_FILE], "a+");
-
-  if (fp == NULL)
-    return;
-
-  strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z",
-           localtime(&conn->birth_time));
-
-  ri = &conn->request_info;
-  flockfile(fp);
-
-  sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
-  fprintf(fp, "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT,
-          src_addr, ri->remote_user == NULL ? "-" : ri->remote_user, date,
-          ri->request_method ? ri->request_method : "-",
-          ri->uri ? ri->uri : "-", ri->http_version,
-          conn->status_code, conn->num_bytes_sent);
-  log_header(conn, "Referer", fp);
-  log_header(conn, "User-Agent", fp);
-  fputc('\n', fp);
-  fflush(fp);
-
-  funlockfile(fp);
-  fclose(fp);
-}
-
 // Verify given socket address against the ACL.
 // Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
 static int check_acl(struct mg_context *ctx, uint32_t remote_ip) {