[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