Mercurial > hg > nginx
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 |