comparison src/core/ngx_log.c @ 6033:8e66a83d16ae

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
author Valentin Bartenev <vbart@nginx.com>
date Thu, 19 Mar 2015 19:29:43 +0300
parents 93fee708f168
children 61d7ae76647d
comparison
equal deleted inserted replaced
6032:ac7c7241ed8c 6033:8e66a83d16ae
10 10
11 11
12 static char *ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 12 static char *ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
13 static char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log); 13 static char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log);
14 static void ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log); 14 static void ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log);
15
16
17 #if (NGX_DEBUG)
18
19 static void ngx_log_memory_writer(ngx_log_t *log, ngx_uint_t level,
20 u_char *buf, size_t len);
21 static void ngx_log_memory_cleanup(void *data);
22
23
24 typedef struct {
25 u_char *start;
26 u_char *end;
27 u_char *pos;
28 ngx_atomic_t written;
29 } ngx_log_memory_buf_t;
30
31 #endif
15 32
16 33
17 static ngx_command_t ngx_errlog_commands[] = { 34 static ngx_command_t ngx_errlog_commands[] = {
18 35
19 {ngx_string("error_log"), 36 {ngx_string("error_log"),
566 new_log->file = ngx_conf_open_file(cf->cycle, &name); 583 new_log->file = ngx_conf_open_file(cf->cycle, &name);
567 if (new_log->file == NULL) { 584 if (new_log->file == NULL) {
568 return NGX_CONF_ERROR; 585 return NGX_CONF_ERROR;
569 } 586 }
570 587
588 } else if (ngx_strncmp(value[1].data, "memory:", 7) == 0) {
589
590 #if (NGX_DEBUG)
591 size_t size, needed;
592 ngx_pool_cleanup_t *cln;
593 ngx_log_memory_buf_t *buf;
594
595 value[1].len -= 7;
596 value[1].data += 7;
597
598 needed = sizeof("MEMLOG :" NGX_LINEFEED)
599 + cf->conf_file->file.name.len
600 + NGX_SIZE_T_LEN
601 + NGX_INT_T_LEN
602 + NGX_MAX_ERROR_STR;
603
604 size = ngx_parse_size(&value[1]);
605
606 if (size == (size_t) NGX_ERROR || size < needed) {
607 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
608 "invalid buffer size \"%V\"", &value[1]);
609 return NGX_CONF_ERROR;
610 }
611
612 buf = ngx_palloc(cf->pool, sizeof(ngx_log_memory_buf_t));
613 if (buf == NULL) {
614 return NGX_CONF_ERROR;
615 }
616
617 buf->start = ngx_pnalloc(cf->pool, size);
618 if (buf->start == NULL) {
619 return NGX_CONF_ERROR;
620 }
621
622 buf->end = buf->start + size;
623
624 buf->pos = ngx_slprintf(buf->start, buf->end, "MEMLOG %uz %V:%ui%N",
625 size, &cf->conf_file->file.name,
626 cf->conf_file->line);
627
628 ngx_memset(buf->pos, ' ', buf->end - buf->pos);
629
630 cln = ngx_pool_cleanup_add(cf->pool, 0);
631 if (cln == NULL) {
632 return NGX_CONF_ERROR;
633 }
634
635 cln->data = new_log;
636 cln->handler = ngx_log_memory_cleanup;
637
638 new_log->writer = ngx_log_memory_writer;
639 new_log->wdata = buf;
640
641 #else
642 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
643 "nginx was built without debug support");
644 return NGX_CONF_ERROR;
645 #endif
571 646
572 } else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) { 647 } else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {
573 peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t)); 648 peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
574 if (peer == NULL) { 649 if (peer == NULL) {
575 return NGX_CONF_ERROR; 650 return NGX_CONF_ERROR;
631 log = log->next; 706 log = log->next;
632 } 707 }
633 708
634 log->next = new_log; 709 log->next = new_log;
635 } 710 }
711
712
713 #if (NGX_DEBUG)
714
715 static void
716 ngx_log_memory_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
717 size_t len)
718 {
719 u_char *p;
720 size_t avail, written;
721 ngx_log_memory_buf_t *mem;
722
723 mem = log->wdata;
724
725 if (mem == NULL) {
726 return;
727 }
728
729 written = ngx_atomic_fetch_add(&mem->written, len);
730
731 p = mem->pos + written % (mem->end - mem->pos);
732
733 avail = mem->end - p;
734
735 if (avail >= len) {
736 ngx_memcpy(p, buf, len);
737
738 } else {
739 ngx_memcpy(p, buf, avail);
740 ngx_memcpy(mem->pos, buf + avail, len - avail);
741 }
742 }
743
744
745 static void
746 ngx_log_memory_cleanup(void *data)
747 {
748 ngx_log_t *log = data;
749
750 ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "destroy memory log buffer");
751
752 log->wdata = NULL;
753 }
754
755 #endif