changeset 4986:3efc49b156d9

Access log: the "flush" parameter of the "access_log" directive.
author Valentin Bartenev <vbart@nginx.com>
date Sun, 23 Dec 2012 15:51:47 +0000
parents a0599b56e748
children 66d001c5378c
files src/http/modules/ngx_http_log_module.c
diffstat 1 files changed, 99 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -44,6 +44,9 @@ typedef struct {
     u_char                     *start;
     u_char                     *pos;
     u_char                     *last;
+
+    ngx_event_t                *event;
+    ngx_msec_t                  flush;
 } ngx_http_log_buf_t;
 
 
@@ -86,6 +89,7 @@ static ssize_t ngx_http_log_script_write
     ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len);
 
 static void ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log);
+static void ngx_http_log_flush_handler(ngx_event_t *ev);
 
 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
     ngx_http_log_op_t *op);
@@ -141,7 +145,7 @@ static ngx_command_t  ngx_http_log_comma
 
     { ngx_string("access_log"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
-                        |NGX_HTTP_LMT_CONF|NGX_CONF_TAKE123,
+                        |NGX_HTTP_LMT_CONF|NGX_CONF_1MORE,
       ngx_http_log_set_log,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -283,6 +287,10 @@ ngx_http_log_handler(ngx_http_request_t 
 
                 p = buffer->pos;
 
+                if (buffer->event && p == buffer->start) {
+                    ngx_add_timer(buffer->event, buffer->flush);
+                }
+
                 for (i = 0; i < log[l].format->ops->nelts; i++) {
                     p = op[i].run(r, p, &op[i]);
                 }
@@ -293,6 +301,10 @@ ngx_http_log_handler(ngx_http_request_t 
 
                 continue;
             }
+
+            if (buffer->event && buffer->event->timer_set) {
+                ngx_del_timer(buffer->event);
+            }
         }
 
         line = ngx_pnalloc(r->pool, len);
@@ -503,6 +515,20 @@ ngx_http_log_flush(ngx_open_file_t *file
     }
 
     buffer->pos = buffer->start;
+
+    if (buffer->event && buffer->event->timer_set) {
+        ngx_del_timer(buffer->event);
+    }
+}
+
+
+static void
+ngx_http_log_flush_handler(ngx_event_t *ev)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+                   "http log buffer flush handler");
+
+    ngx_http_log_flush(ev->data, ev->log);
 }
 
 
@@ -891,7 +917,8 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx
 
     ssize_t                     size;
     ngx_uint_t                  i, n;
-    ngx_str_t                  *value, name;
+    ngx_msec_t                  flush;
+    ngx_str_t                  *value, name, s;
     ngx_http_log_t             *log;
     ngx_http_log_buf_t         *buffer;
     ngx_http_log_fmt_t         *fmt;
@@ -978,47 +1005,81 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx
             && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
         {
             log->format = &fmt[i];
-            goto buffer;
+            break;
         }
     }
 
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "unknown log format \"%V\"", &name);
-    return NGX_CONF_ERROR;
+    if (log->format == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "unknown log format \"%V\"", &name);
+        return NGX_CONF_ERROR;
+    }
+
+    size = 0;
+    flush = 0;
+
+    for (i = 3; i < cf->args->nelts; i++) {
 
-buffer:
+        if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
+            s.len = value[i].len - 7;
+            s.data = value[i].data + 7;
+
+            size = ngx_parse_size(&s);
+
+            if (size == NGX_ERROR || size == 0) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid buffer size \"%V\"", &s);
+                return NGX_CONF_ERROR;
+            }
+
+            continue;
+        }
 
-    if (cf->args->nelts == 4) {
-        if (ngx_strncmp(value[3].data, "buffer=", 7) != 0) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "invalid parameter \"%V\"", &value[3]);
-            return NGX_CONF_ERROR;
+        if (ngx_strncmp(value[i].data, "flush=", 6) == 0) {
+            s.len = value[i].len - 6;
+            s.data = value[i].data + 6;
+
+            flush = ngx_parse_time(&s, 0);
+
+            if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid flush time \"%V\"", &s);
+                return NGX_CONF_ERROR;
+            }
+
+            continue;
         }
 
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid parameter \"%V\"", &value[i]);
+        return NGX_CONF_ERROR;
+    }
+
+    if (flush && size == 0) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "no buffer is defined for access_log \"%V\"",
+                           &value[1]);
+        return NGX_CONF_ERROR;
+    }
+
+    if (size) {
+
         if (log->script) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "buffered logs cannot have variables in name");
             return NGX_CONF_ERROR;
         }
 
-        name.len = value[3].len - 7;
-        name.data = value[3].data + 7;
-
-        size = ngx_parse_size(&name);
-
-        if (size == NGX_ERROR) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "invalid buffer value \"%V\"", &name);
-            return NGX_CONF_ERROR;
-        }
-
         if (log->file->data) {
             buffer = log->file->data;
 
-            if (buffer->last - buffer->start != size) {
+            if (buffer->last - buffer->start != size
+                || buffer->flush != flush)
+            {
                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                    "access_log \"%V\" already defined "
-                                   "with different buffer size", &value[1]);
+                                   "with conflicting parameters",
+                                   &value[1]);
                 return NGX_CONF_ERROR;
             }
 
@@ -1038,6 +1099,19 @@ buffer:
         buffer->pos = buffer->start;
         buffer->last = buffer->start + size;
 
+        if (flush) {
+            buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
+            if (buffer->event == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            buffer->event->data = log->file;
+            buffer->event->handler = ngx_http_log_flush_handler;
+            buffer->event->log = &cf->cycle->new_log;
+
+            buffer->flush = flush;
+        }
+
         log->file->flush = ngx_http_log_flush;
         log->file->data = buffer;
     }