Mercurial > hg > nginx
comparison src/core/ngx_log.c @ 5254:7ecaa9e4bf1b
Core: support several "error_log" directives.
When several "error_log" directives are specified in the same configuration
block, logs are written to all files with a matching log level.
All logs are stored in the singly-linked list that is sorted by log level in
the descending order.
Specific debug levels (NGX_LOG_DEBUG_HTTP,EVENT, etc.) are not supported
if several "error_log" directives are specified. In this case all logs
will use debug level that has largest absolute value.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Thu, 20 Jun 2013 20:47:39 +0400 |
parents | 3bb51e5afa9e |
children | e088695737c3 |
comparison
equal
deleted
inserted
replaced
5253:a82f305487c2 | 5254:7ecaa9e4bf1b |
---|---|
8 #include <ngx_config.h> | 8 #include <ngx_config.h> |
9 #include <ngx_core.h> | 9 #include <ngx_core.h> |
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); | |
14 static void ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log); | |
13 | 15 |
14 | 16 |
15 static ngx_command_t ngx_errlog_commands[] = { | 17 static ngx_command_t ngx_errlog_commands[] = { |
16 | 18 |
17 {ngx_string("error_log"), | 19 {ngx_string("error_log"), |
84 const char *fmt, va_list args) | 86 const char *fmt, va_list args) |
85 | 87 |
86 #endif | 88 #endif |
87 { | 89 { |
88 #if (NGX_HAVE_VARIADIC_MACROS) | 90 #if (NGX_HAVE_VARIADIC_MACROS) |
89 va_list args; | 91 va_list args; |
90 #endif | 92 #endif |
91 u_char *p, *last, *msg; | 93 u_char *p, *last, *msg; |
92 u_char errstr[NGX_MAX_ERROR_STR]; | 94 u_char errstr[NGX_MAX_ERROR_STR]; |
93 | 95 ngx_uint_t wrote_stderr, debug_connection; |
94 if (log->file->fd == NGX_INVALID_FILE) { | |
95 return; | |
96 } | |
97 | 96 |
98 last = errstr + NGX_MAX_ERROR_STR; | 97 last = errstr + NGX_MAX_ERROR_STR; |
99 | 98 |
100 ngx_memcpy(errstr, ngx_cached_err_log_time.data, | 99 ngx_memcpy(errstr, ngx_cached_err_log_time.data, |
101 ngx_cached_err_log_time.len); | 100 ngx_cached_err_log_time.len); |
138 p = last - NGX_LINEFEED_SIZE; | 137 p = last - NGX_LINEFEED_SIZE; |
139 } | 138 } |
140 | 139 |
141 ngx_linefeed(p); | 140 ngx_linefeed(p); |
142 | 141 |
143 (void) ngx_write_fd(log->file->fd, errstr, p - errstr); | 142 wrote_stderr = 0; |
143 debug_connection = (log->log_level & NGX_LOG_DEBUG_CONNECTION) != 0; | |
144 | |
145 while (log) { | |
146 | |
147 if (log->log_level < level && !debug_connection) { | |
148 break; | |
149 } | |
150 | |
151 (void) ngx_write_fd(log->file->fd, errstr, p - errstr); | |
152 | |
153 if (log->file->fd == ngx_stderr) { | |
154 wrote_stderr = 1; | |
155 } | |
156 | |
157 log = log->next; | |
158 } | |
144 | 159 |
145 if (!ngx_use_stderr | 160 if (!ngx_use_stderr |
146 || level > NGX_LOG_WARN | 161 || level > NGX_LOG_WARN |
147 || log->file->fd == ngx_stderr) | 162 || wrote_stderr) |
148 { | 163 { |
149 return; | 164 return; |
150 } | 165 } |
151 | 166 |
152 msg -= (7 + err_levels[level].len + 3); | 167 msg -= (7 + err_levels[level].len + 3); |
346 | 361 |
347 return &ngx_log; | 362 return &ngx_log; |
348 } | 363 } |
349 | 364 |
350 | 365 |
351 ngx_log_t * | 366 static char * |
352 ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name) | |
353 { | |
354 ngx_log_t *log; | |
355 | |
356 log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t)); | |
357 if (log == NULL) { | |
358 return NULL; | |
359 } | |
360 | |
361 log->file = ngx_conf_open_file(cycle, name); | |
362 if (log->file == NULL) { | |
363 return NULL; | |
364 } | |
365 | |
366 return log; | |
367 } | |
368 | |
369 | |
370 char * | |
371 ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log) | 367 ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log) |
372 { | 368 { |
373 ngx_uint_t i, n, d, found; | 369 ngx_uint_t i, n, d, found; |
374 ngx_str_t *value; | 370 ngx_str_t *value; |
371 | |
372 if (cf->args->nelts == 2) { | |
373 log->log_level = NGX_LOG_ERR; | |
374 return NGX_CONF_OK; | |
375 } | |
375 | 376 |
376 value = cf->args->elts; | 377 value = cf->args->elts; |
377 | 378 |
378 for (i = 2; i < cf->args->nelts; i++) { | 379 for (i = 2; i < cf->args->nelts; i++) { |
379 found = 0; | 380 found = 0; |
426 | 427 |
427 | 428 |
428 static char * | 429 static char * |
429 ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 430 ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
430 { | 431 { |
432 ngx_log_t *dummy; | |
433 | |
434 dummy = &cf->cycle->new_log; | |
435 | |
436 return ngx_log_set_log(cf, &dummy); | |
437 } | |
438 | |
439 | |
440 char * | |
441 ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head) | |
442 { | |
443 ngx_log_t *new_log; | |
431 ngx_str_t *value, name; | 444 ngx_str_t *value, name; |
432 | 445 |
433 if (cf->cycle->new_log.file) { | 446 if (*head != NULL && (*head)->log_level == 0) { |
434 return "is duplicate"; | 447 new_log = *head; |
448 | |
449 } else { | |
450 | |
451 new_log = ngx_pcalloc(cf->pool, sizeof(ngx_log_t)); | |
452 if (new_log == NULL) { | |
453 return NGX_CONF_ERROR; | |
454 } | |
455 | |
456 if (*head == NULL) { | |
457 *head = new_log; | |
458 } | |
435 } | 459 } |
436 | 460 |
437 value = cf->args->elts; | 461 value = cf->args->elts; |
438 | 462 |
439 if (ngx_strcmp(value[1].data, "stderr") == 0) { | 463 if (ngx_strcmp(value[1].data, "stderr") == 0) { |
442 | 466 |
443 } else { | 467 } else { |
444 name = value[1]; | 468 name = value[1]; |
445 } | 469 } |
446 | 470 |
447 cf->cycle->new_log.file = ngx_conf_open_file(cf->cycle, &name); | 471 new_log->file = ngx_conf_open_file(cf->cycle, &name); |
448 if (cf->cycle->new_log.file == NULL) { | 472 if (new_log->file == NULL) { |
449 return NULL; | 473 return NGX_CONF_ERROR; |
450 } | 474 } |
451 | 475 |
452 if (cf->args->nelts == 2) { | 476 if (ngx_log_set_levels(cf, new_log) != NGX_CONF_OK) { |
453 cf->cycle->new_log.log_level = NGX_LOG_ERR; | 477 return NGX_CONF_ERROR; |
454 return NGX_CONF_OK; | 478 } |
455 } | 479 |
456 | 480 if (*head != new_log) { |
457 return ngx_log_set_levels(cf, &cf->cycle->new_log); | 481 ngx_log_insert(*head, new_log); |
458 } | 482 } |
483 | |
484 return NGX_CONF_OK; | |
485 } | |
486 | |
487 | |
488 static void | |
489 ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log) | |
490 { | |
491 ngx_log_t tmp; | |
492 | |
493 if (new_log->log_level > log->log_level) { | |
494 | |
495 /* | |
496 * list head address is permanent, insert new log after | |
497 * head and swap its contents with head | |
498 */ | |
499 | |
500 tmp = *log; | |
501 *log = *new_log; | |
502 *new_log = tmp; | |
503 | |
504 log->next = new_log; | |
505 return; | |
506 } | |
507 | |
508 while (log->next) { | |
509 if (new_log->log_level > log->next->log_level) { | |
510 new_log->next = log->next; | |
511 log->next = new_log; | |
512 return; | |
513 } | |
514 | |
515 log = log->next; | |
516 } | |
517 | |
518 log->next = new_log; | |
519 } |