configless vhost

Igor Sysoev is at rambler-co.ru
Fri Jun 27 00:40:10 MSD 2008


On Thu, Jun 26, 2008 at 04:26:54AM -0300, Marcos Neves wrote:

> I have virtualhost with configuration less feature that works like a charm!
> 
>     server {
>         server_name _;
>         set $host_without_www $host;
>         if ($host ~* www\.(.*)) {
>           set $host_without_www $1;
>         }
>         root /var/www/$host_without_www/;
>         access_log logs/$host_without_www.log;
> 
> unfortunately, access_log don?t parses variables, so a file named
> $host_without_www.log
> is created instead.
> 
> There?s any way to keep access logs separated by host, without need to
> configure one by one by hand?

The attached patch allows variables in access_log.

It's a proof-of-concept: for every log operation it opens/creates log,
writes, and then closes. It does not keep open frequently used logs.

It does not try to create log if a response status is 404 and there is
no root for the request.


-- 
Igor Sysoev
http://sysoev.ru/en/
-------------- next part --------------
Index: src/http/modules/ngx_http_log_module.c
===================================================================
--- src/http/modules/ngx_http_log_module.c	(revision 1389)
+++ src/http/modules/ngx_http_log_module.c	(working copy)
@@ -40,7 +40,14 @@
 
 
 typedef struct {
+    ngx_array_t                *lengths;
+    ngx_array_t                *values;
+} ngx_http_log_script_t;
+
+
+typedef struct {
     ngx_open_file_t            *file;
+    ngx_http_log_script_t      *script;
     time_t                      disk_full_time;
     time_t                      error_log_time;
     ngx_array_t                *ops;        /* array of ngx_http_log_op_t */
@@ -62,6 +69,8 @@
 
 static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
     u_char *buf, size_t len);
+static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
+    ngx_http_log_script_t *script, u_char *buf, size_t len);
 
 static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf,
     ngx_http_log_op_t *op);
@@ -235,7 +244,7 @@
 
         file = log[l].file;
 
-        if (file->buffer) {
+        if (file && file->buffer) {
 
             if (len > (size_t) (file->last - file->pos)) {
 
@@ -289,8 +298,13 @@
     ssize_t    n;
     ngx_err_t  err;
 
-    n = ngx_write_fd(log->file->fd, buf, len);
+    if (log->script == NULL) {
+        n = ngx_write_fd(log->file->fd, buf, len);
 
+    } else {
+        n = ngx_http_log_script_write(r, log->script, buf, len);
+    }
+
     if (n == (ssize_t) len) {
         return;
     }
@@ -325,6 +339,87 @@
 }
 
 
+static ssize_t
+ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
+    u_char *buf, size_t len)
+{
+    size_t                     root;
+    ssize_t                    n;
+    ngx_fd_t                   fd;
+    ngx_err_t                  err;
+    ngx_str_t                  name, path;
+    ngx_uint_t                 status;
+    ngx_open_file_info_t       of;
+    ngx_http_core_loc_conf_t  *clcf;
+
+    status = r->err_status ? r->err_status : r->headers_out.status;
+
+    if (status == NGX_HTTP_NOT_FOUND) {
+
+        /* test root directory existance */
+
+        if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
+            return -1;
+        }
+
+        path.data[root] = '\0';
+
+        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+        ngx_memzero(&of, sizeof(ngx_open_file_info_t));
+
+        of.valid = clcf->open_file_cache_valid;
+        of.min_uses = clcf->open_file_cache_min_uses;
+        of.errors = clcf->open_file_cache_errors;
+        of.events = clcf->open_file_cache_events;
+
+        if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
+                != NGX_OK
+            || !of.is_dir)
+        {
+            /* no root directory: simulate successfull logging */
+
+            return len;
+        }
+    }
+
+    if (ngx_http_script_run(r, &name, script->lengths->elts, 1,
+                            script->values->elts)
+        == NULL)
+    {
+        return -1;
+    }
+
+    name.data[name.len - 1] = '\0';
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http log \"%s\"", name.data);
+
+    fd = ngx_open_file(name.data, NGX_FILE_RDWR,
+                       NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND,
+                       NGX_FILE_DEFAULT_ACCESS);
+
+    if (fd == NGX_INVALID_FILE) {
+        ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+                      ngx_open_file_n " \"%s\" failed", name.data);
+        return -1;
+    }
+
+    n = ngx_write_fd(fd, buf, len);
+
+    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+        err = ngx_errno;
+
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+                      ngx_close_file_n " \"%s\" failed", name.data);
+
+        ngx_set_errno(err);
+    }
+
+    return n;
+}
+
+
 static u_char *
 ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
     ngx_http_log_op_t *op)
@@ -678,12 +773,13 @@
 {
     ngx_http_log_loc_conf_t *llcf = conf;
 
-    ssize_t                    buf;
-    ngx_uint_t                 i;
-    ngx_str_t                 *value, name;
-    ngx_http_log_t            *log;
-    ngx_http_log_fmt_t        *fmt;
-    ngx_http_log_main_conf_t  *lmcf;
+    ssize_t                     buf;
+    ngx_uint_t                  i, n;
+    ngx_str_t                  *value, name;
+    ngx_http_log_t             *log;
+    ngx_http_log_fmt_t         *fmt;
+    ngx_http_log_main_conf_t   *lmcf;
+    ngx_http_script_compile_t    sc;
 
     value = cf->args->elts;
 
@@ -706,14 +802,41 @@
         return NGX_CONF_ERROR;
     }
 
-    log->file = ngx_conf_open_file(cf->cycle, &value[1]);
-    if (log->file == NULL) {
-        return NGX_CONF_ERROR;
+    ngx_memzero(log, sizeof(ngx_http_log_t));
+
+    n = ngx_http_script_variables_count(&value[1]);
+
+    if (n == 0) {
+        log->file = ngx_conf_open_file(cf->cycle, &value[1]);
+        if (log->file == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+    } else {
+        if (ngx_conf_full_name(cf->cycle, &value[1], 0) == NGX_ERROR) {
+            return NGX_CONF_ERROR;
+        }
+
+        log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t));
+        if (log->script == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+        sc.cf = cf;
+        sc.source = &value[1];
+        sc.lengths = &log->script->lengths;
+        sc.values = &log->script->values;
+        sc.variables = n;
+        sc.complete_lengths = 1;
+        sc.complete_values = 1;
+
+        if (ngx_http_script_compile(&sc) != NGX_OK) {
+            return NGX_CONF_ERROR;
+        }
     }
 
-    log->disk_full_time = 0;
-    log->error_log_time = 0;
-
     if (cf->args->nelts >= 3) {
         name = value[2];
 
@@ -750,6 +873,12 @@
             return NGX_CONF_ERROR;
         }
 
+        if (log->script) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "buffered logs can not have variables in name");
+            return NGX_CONF_ERROR;
+        }
+
         name.len = value[3].len - 7;
         name.data = value[3].data + 7;
 


More information about the nginx mailing list