[nginx] Core: added cyclic memory buffer support for error_log.

Valentin Bartenev vbart at nginx.com
Fri Mar 20 16:29:07 UTC 2015


details:   http://hg.nginx.org/nginx/rev/8e66a83d16ae
branches:  
changeset: 6033:8e66a83d16ae
user:      Valentin Bartenev <vbart at nginx.com>
date:      Thu Mar 19 19:29:43 2015 +0300
description:
Core: added cyclic memory buffer support for error_log.

Example of usage:

  error_log memory:16m debug;

This allows to configure debug logging with minimum impact on performance.
It's especially useful when rare crashes are experienced under high load.

The log can be extracted from a coredump using the following gdb script:

  set $log = ngx_cycle->log

  while $log->writer != ngx_log_memory_writer
      set $log = $log->next
  end

  set $buf = (ngx_log_memory_buf_t *) $log->wdata
  dump binary memory debug_log.txt $buf->start $buf->end

diffstat:

 src/core/ngx_log.c |  120 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 120 insertions(+), 0 deletions(-)

diffs (141 lines):

diff -r ac7c7241ed8c -r 8e66a83d16ae src/core/ngx_log.c
--- a/src/core/ngx_log.c	Fri Mar 20 06:45:32 2015 +0300
+++ b/src/core/ngx_log.c	Thu Mar 19 19:29:43 2015 +0300
@@ -14,6 +14,23 @@ static char *ngx_log_set_levels(ngx_conf
 static void ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log);
 
 
+#if (NGX_DEBUG)
+
+static void ngx_log_memory_writer(ngx_log_t *log, ngx_uint_t level,
+    u_char *buf, size_t len);
+static void ngx_log_memory_cleanup(void *data);
+
+
+typedef struct {
+    u_char        *start;
+    u_char        *end;
+    u_char        *pos;
+    ngx_atomic_t   written;
+} ngx_log_memory_buf_t;
+
+#endif
+
+
 static ngx_command_t  ngx_errlog_commands[] = {
 
     {ngx_string("error_log"),
@@ -568,6 +585,64 @@ ngx_log_set_log(ngx_conf_t *cf, ngx_log_
             return NGX_CONF_ERROR;
         }
 
+     } else if (ngx_strncmp(value[1].data, "memory:", 7) == 0) {
+
+#if (NGX_DEBUG)
+        size_t                 size, needed;
+        ngx_pool_cleanup_t    *cln;
+        ngx_log_memory_buf_t  *buf;
+
+        value[1].len -= 7;
+        value[1].data += 7;
+
+        needed = sizeof("MEMLOG  :" NGX_LINEFEED)
+                 + cf->conf_file->file.name.len
+                 + NGX_SIZE_T_LEN
+                 + NGX_INT_T_LEN
+                 + NGX_MAX_ERROR_STR;
+
+        size = ngx_parse_size(&value[1]);
+
+        if (size == (size_t) NGX_ERROR || size < needed) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid buffer size \"%V\"", &value[1]);
+            return NGX_CONF_ERROR;
+        }
+
+        buf = ngx_palloc(cf->pool, sizeof(ngx_log_memory_buf_t));
+        if (buf == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        buf->start = ngx_pnalloc(cf->pool, size);
+        if (buf->start == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        buf->end = buf->start + size;
+
+        buf->pos = ngx_slprintf(buf->start, buf->end, "MEMLOG %uz %V:%ui%N",
+                                size, &cf->conf_file->file.name,
+                                cf->conf_file->line);
+
+        ngx_memset(buf->pos, ' ', buf->end - buf->pos);
+
+        cln = ngx_pool_cleanup_add(cf->pool, 0);
+        if (cln == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        cln->data = new_log;
+        cln->handler = ngx_log_memory_cleanup;
+
+        new_log->writer = ngx_log_memory_writer;
+        new_log->wdata = buf;
+
+#else
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "nginx was built without debug support");
+        return NGX_CONF_ERROR;
+#endif
 
      } else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {
         peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
@@ -633,3 +708,48 @@ ngx_log_insert(ngx_log_t *log, ngx_log_t
 
     log->next = new_log;
 }
+
+
+#if (NGX_DEBUG)
+
+static void
+ngx_log_memory_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
+    size_t len)
+{
+    u_char                *p;
+    size_t                 avail, written;
+    ngx_log_memory_buf_t  *mem;
+
+    mem = log->wdata;
+
+    if (mem == NULL) {
+        return;
+    }
+
+    written = ngx_atomic_fetch_add(&mem->written, len);
+
+    p = mem->pos + written % (mem->end - mem->pos);
+
+    avail = mem->end - p;
+
+    if (avail >= len) {
+        ngx_memcpy(p, buf, len);
+
+    } else {
+        ngx_memcpy(p, buf, avail);
+        ngx_memcpy(mem->pos, buf + avail, len - avail);
+    }
+}
+
+
+static void
+ngx_log_memory_cleanup(void *data)
+{
+    ngx_log_t *log = data;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "destroy memory log buffer");
+
+    log->wdata = NULL;
+}
+
+#endif



More information about the nginx-devel mailing list