xref: /nginx/src/core/ngx_log.c (revision 6484:4b420f9c4c5d)
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 
11 
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);
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
32 
33 
34 static ngx_command_t  ngx_errlog_commands[] = {
35 
36     { ngx_string("error_log"),
37       NGX_MAIN_CONF|NGX_CONF_1MORE,
38       ngx_error_log,
39       0,
40       0,
41       NULL },
42 
43       ngx_null_command
44 };
45 
46 
47 static ngx_core_module_t  ngx_errlog_module_ctx = {
48     ngx_string("errlog"),
49     NULL,
50     NULL
51 };
52 
53 
54 ngx_module_t  ngx_errlog_module = {
55     NGX_MODULE_V1,
56     &ngx_errlog_module_ctx,                /* module context */
57     ngx_errlog_commands,                   /* module directives */
58     NGX_CORE_MODULE,                       /* module type */
59     NULL,                                  /* init master */
60     NULL,                                  /* init module */
61     NULL,                                  /* init process */
62     NULL,                                  /* init thread */
63     NULL,                                  /* exit thread */
64     NULL,                                  /* exit process */
65     NULL,                                  /* exit master */
66     NGX_MODULE_V1_PADDING
67 };
68 
69 
70 static ngx_log_t        ngx_log;
71 static ngx_open_file_t  ngx_log_file;
72 ngx_uint_t              ngx_use_stderr = 1;
73 
74 
75 static ngx_str_t err_levels[] = {
76     ngx_null_string,
77     ngx_string("emerg"),
78     ngx_string("alert"),
79     ngx_string("crit"),
80     ngx_string("error"),
81     ngx_string("warn"),
82     ngx_string("notice"),
83     ngx_string("info"),
84     ngx_string("debug")
85 };
86 
87 static const char *debug_levels[] = {
88     "debug_core", "debug_alloc", "debug_mutex", "debug_event",
89     "debug_http", "debug_mail", "debug_stream"
90 };
91 
92 
93 #if (NGX_HAVE_VARIADIC_MACROS)
94 
95 void
96 ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
97     const char *fmt, ...)
98 
99 #else
100 
101 void
102 ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
103     const char *fmt, va_list args)
104 
105 #endif
106 {
107 #if (NGX_HAVE_VARIADIC_MACROS)
108     va_list      args;
109 #endif
110     u_char      *p, *last, *msg;
111     ssize_t      n;
112     ngx_uint_t   wrote_stderr, debug_connection;
113     u_char       errstr[NGX_MAX_ERROR_STR];
114 
115     last = errstr + NGX_MAX_ERROR_STR;
116 
117     p = ngx_cpymem(errstr, ngx_cached_err_log_time.data,
118                    ngx_cached_err_log_time.len);
119 
120     p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]);
121 
122     /* pid#tid */
123     p = ngx_slprintf(p, last, "%P#" NGX_TID_T_FMT ": ",
124                     ngx_log_pid, ngx_log_tid);
125 
126     if (log->connection) {
127         p = ngx_slprintf(p, last, "*%uA ", log->connection);
128     }
129 
130     msg = p;
131 
132 #if (NGX_HAVE_VARIADIC_MACROS)
133 
134     va_start(args, fmt);
135     p = ngx_vslprintf(p, last, fmt, args);
136     va_end(args);
137 
138 #else
139 
140     p = ngx_vslprintf(p, last, fmt, args);
141 
142 #endif
143 
144     if (err) {
145         p = ngx_log_errno(p, last, err);
146     }
147 
148     if (level != NGX_LOG_DEBUG && log->handler) {
149         p = log->handler(log, p, last - p);
150     }
151 
152     if (p > last - NGX_LINEFEED_SIZE) {
153         p = last - NGX_LINEFEED_SIZE;
154     }
155 
156     ngx_linefeed(p);
157 
158     wrote_stderr = 0;
159     debug_connection = (log->log_level & NGX_LOG_DEBUG_CONNECTION) != 0;
160 
161     while (log) {
162 
163         if (log->log_level < level && !debug_connection) {
164             break;
165         }
166 
167         if (log->writer) {
168             log->writer(log, level, errstr, p - errstr);
169             goto next;
170         }
171 
172         if (ngx_time() == log->disk_full_time) {
173 
174             /*
175              * on FreeBSD writing to a full filesystem with enabled softupdates
176              * may block process for much longer time than writing to non-full
177              * filesystem, so we skip writing to a log for one second
178              */
179 
180             goto next;
181         }
182 
183         n = ngx_write_fd(log->file->fd, errstr, p - errstr);
184 
185         if (n == -1 && ngx_errno == NGX_ENOSPC) {
186             log->disk_full_time = ngx_time();
187         }
188 
189         if (log->file->fd == ngx_stderr) {
190             wrote_stderr = 1;
191         }
192 
193     next:
194 
195         log = log->next;
196     }
197 
198     if (!ngx_use_stderr
199         || level > NGX_LOG_WARN
200         || wrote_stderr)
201     {
202         return;
203     }
204 
205     msg -= (7 + err_levels[level].len + 3);
206 
207     (void) ngx_sprintf(msg, "nginx: [%V] ", &err_levels[level]);
208 
209     (void) ngx_write_console(ngx_stderr, msg, p - msg);
210 }
211 
212 
213 #if !(NGX_HAVE_VARIADIC_MACROS)
214 
215 void ngx_cdecl
216 ngx_log_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
217     const char *fmt, ...)
218 {
219     va_list  args;
220 
221     if (log->log_level >= level) {
222         va_start(args, fmt);
223         ngx_log_error_core(level, log, err, fmt, args);
224         va_end(args);
225     }
226 }
227 
228 
229 void ngx_cdecl
230 ngx_log_debug_core(ngx_log_t *log, ngx_err_t err, const char *fmt, ...)
231 {
232     va_list  args;
233 
234     va_start(args, fmt);
235     ngx_log_error_core(NGX_LOG_DEBUG, log, err, fmt, args);
236     va_end(args);
237 }
238 
239 #endif
240 
241 
242 void ngx_cdecl
243 ngx_log_abort(ngx_err_t err, const char *fmt, ...)
244 {
245     u_char   *p;
246     va_list   args;
247     u_char    errstr[NGX_MAX_CONF_ERRSTR];
248 
249     va_start(args, fmt);
250     p = ngx_vsnprintf(errstr, sizeof(errstr) - 1, fmt, args);
251     va_end(args);
252 
253     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
254                   "%*s", p - errstr, errstr);
255 }
256 
257 
258 void ngx_cdecl
259 ngx_log_stderr(ngx_err_t err, const char *fmt, ...)
260 {
261     u_char   *p, *last;
262     va_list   args;
263     u_char    errstr[NGX_MAX_ERROR_STR];
264 
265     last = errstr + NGX_MAX_ERROR_STR;
266 
267     p = ngx_cpymem(errstr, "nginx: ", 7);
268 
269     va_start(args, fmt);
270     p = ngx_vslprintf(p, last, fmt, args);
271     va_end(args);
272 
273     if (err) {
274         p = ngx_log_errno(p, last, err);
275     }
276 
277     if (p > last - NGX_LINEFEED_SIZE) {
278         p = last - NGX_LINEFEED_SIZE;
279     }
280 
281     ngx_linefeed(p);
282 
283     (void) ngx_write_console(ngx_stderr, errstr, p - errstr);
284 }
285 
286 
287 u_char *
288 ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err)
289 {
290     if (buf > last - 50) {
291 
292         /* leave a space for an error code */
293 
294         buf = last - 50;
295         *buf++ = '.';
296         *buf++ = '.';
297         *buf++ = '.';
298     }
299 
300 #if (NGX_WIN32)
301     buf = ngx_slprintf(buf, last, ((unsigned) err < 0x80000000)
302                                        ? " (%d: " : " (%Xd: ", err);
303 #else
304     buf = ngx_slprintf(buf, last, " (%d: ", err);
305 #endif
306 
307     buf = ngx_strerror(err, buf, last - buf);
308 
309     if (buf < last) {
310         *buf++ = ')';
311     }
312 
313     return buf;
314 }
315 
316 
317 ngx_log_t *
318 ngx_log_init(u_char *prefix)
319 {
320     u_char  *p, *name;
321     size_t   nlen, plen;
322 
323     ngx_log.file = &ngx_log_file;
324     ngx_log.log_level = NGX_LOG_NOTICE;
325 
326     name = (u_char *) NGX_ERROR_LOG_PATH;
327 
328     /*
329      * we use ngx_strlen() here since BCC warns about
330      * condition is always false and unreachable code
331      */
332 
333     nlen = ngx_strlen(name);
334 
335     if (nlen == 0) {
336         ngx_log_file.fd = ngx_stderr;
337         return &ngx_log;
338     }
339 
340     p = NULL;
341 
342 #if (NGX_WIN32)
343     if (name[1] != ':') {
344 #else
345     if (name[0] != '/') {
346 #endif
347 
348         if (prefix) {
349             plen = ngx_strlen(prefix);
350 
351         } else {
352 #ifdef NGX_PREFIX
353             prefix = (u_char *) NGX_PREFIX;
354             plen = ngx_strlen(prefix);
355 #else
356             plen = 0;
357 #endif
358         }
359 
360         if (plen) {
361             name = malloc(plen + nlen + 2);
362             if (name == NULL) {
363                 return NULL;
364             }
365 
366             p = ngx_cpymem(name, prefix, plen);
367 
368             if (!ngx_path_separator(*(p - 1))) {
369                 *p++ = '/';
370             }
371 
372             ngx_cpystrn(p, (u_char *) NGX_ERROR_LOG_PATH, nlen + 1);
373 
374             p = name;
375         }
376     }
377 
378     ngx_log_file.fd = ngx_open_file(name, NGX_FILE_APPEND,
379                                     NGX_FILE_CREATE_OR_OPEN,
380                                     NGX_FILE_DEFAULT_ACCESS);
381 
382     if (ngx_log_file.fd == NGX_INVALID_FILE) {
383         ngx_log_stderr(ngx_errno,
384                        "[alert] could not open error log file: "
385                        ngx_open_file_n " \"%s\" failed", name);
386 #if (NGX_WIN32)
387         ngx_event_log(ngx_errno,
388                        "could not open error log file: "
389                        ngx_open_file_n " \"%s\" failed", name);
390 #endif
391 
392         ngx_log_file.fd = ngx_stderr;
393     }
394 
395     if (p) {
396         ngx_free(p);
397     }
398 
399     return &ngx_log;
400 }
401 
402 
403 ngx_int_t
404 ngx_log_open_default(ngx_cycle_t *cycle)
405 {
406     ngx_log_t         *log;
407     static ngx_str_t   error_log = ngx_string(NGX_ERROR_LOG_PATH);
408 
409     if (ngx_log_get_file_log(&cycle->new_log) != NULL) {
410         return NGX_OK;
411     }
412 
413     if (cycle->new_log.log_level != 0) {
414         /* there are some error logs, but no files */
415 
416         log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t));
417         if (log == NULL) {
418             return NGX_ERROR;
419         }
420 
421     } else {
422         /* no error logs at all */
423         log = &cycle->new_log;
424     }
425 
426     log->log_level = NGX_LOG_ERR;
427 
428     log->file = ngx_conf_open_file(cycle, &error_log);
429     if (log->file == NULL) {
430         return NGX_ERROR;
431     }
432 
433     if (log != &cycle->new_log) {
434         ngx_log_insert(&cycle->new_log, log);
435     }
436 
437     return NGX_OK;
438 }
439 
440 
441 ngx_int_t
442 ngx_log_redirect_stderr(ngx_cycle_t *cycle)
443 {
444     ngx_fd_t  fd;
445 
446     if (cycle->log_use_stderr) {
447         return NGX_OK;
448     }
449 
450     /* file log always exists when we are called */
451     fd = ngx_log_get_file_log(cycle->log)->file->fd;
452 
453     if (fd != ngx_stderr) {
454         if (ngx_set_stderr(fd) == NGX_FILE_ERROR) {
455             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
456                           ngx_set_stderr_n " failed");
457 
458             return NGX_ERROR;
459         }
460     }
461 
462     return NGX_OK;
463 }
464 
465 
466 ngx_log_t *
467 ngx_log_get_file_log(ngx_log_t *head)
468 {
469     ngx_log_t  *log;
470 
471     for (log = head; log; log = log->next) {
472         if (log->file != NULL) {
473             return log;
474         }
475     }
476 
477     return NULL;
478 }
479 
480 
481 static char *
482 ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log)
483 {
484     ngx_uint_t   i, n, d, found;
485     ngx_str_t   *value;
486 
487     if (cf->args->nelts == 2) {
488         log->log_level = NGX_LOG_ERR;
489         return NGX_CONF_OK;
490     }
491 
492     value = cf->args->elts;
493 
494     for (i = 2; i < cf->args->nelts; i++) {
495         found = 0;
496 
497         for (n = 1; n <= NGX_LOG_DEBUG; n++) {
498             if (ngx_strcmp(value[i].data, err_levels[n].data) == 0) {
499 
500                 if (log->log_level != 0) {
501                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
502                                        "duplicate log level \"%V\"",
503                                        &value[i]);
504                     return NGX_CONF_ERROR;
505                 }
506 
507                 log->log_level = n;
508                 found = 1;
509                 break;
510             }
511         }
512 
513         for (n = 0, d = NGX_LOG_DEBUG_FIRST; d <= NGX_LOG_DEBUG_LAST; d <<= 1) {
514             if (ngx_strcmp(value[i].data, debug_levels[n++]) == 0) {
515                 if (log->log_level & ~NGX_LOG_DEBUG_ALL) {
516                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
517                                        "invalid log level \"%V\"",
518                                        &value[i]);
519                     return NGX_CONF_ERROR;
520                 }
521 
522                 log->log_level |= d;
523                 found = 1;
524                 break;
525             }
526         }
527 
528 
529         if (!found) {
530             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
531                                "invalid log level \"%V\"", &value[i]);
532             return NGX_CONF_ERROR;
533         }
534     }
535 
536     if (log->log_level == NGX_LOG_DEBUG) {
537         log->log_level = NGX_LOG_DEBUG_ALL;
538     }
539 
540     return NGX_CONF_OK;
541 }
542 
543 
544 static char *
545 ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
546 {
547     ngx_log_t  *dummy;
548 
549     dummy = &cf->cycle->new_log;
550 
551     return ngx_log_set_log(cf, &dummy);
552 }
553 
554 
555 char *
556 ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head)
557 {
558     ngx_log_t          *new_log;
559     ngx_str_t          *value, name;
560     ngx_syslog_peer_t  *peer;
561 
562     if (*head != NULL && (*head)->log_level == 0) {
563         new_log = *head;
564 
565     } else {
566 
567         new_log = ngx_pcalloc(cf->pool, sizeof(ngx_log_t));
568         if (new_log == NULL) {
569             return NGX_CONF_ERROR;
570         }
571 
572         if (*head == NULL) {
573             *head = new_log;
574         }
575     }
576 
577     value = cf->args->elts;
578 
579     if (ngx_strcmp(value[1].data, "stderr") == 0) {
580         ngx_str_null(&name);
581         cf->cycle->log_use_stderr = 1;
582 
583         new_log->file = ngx_conf_open_file(cf->cycle, &name);
584         if (new_log->file == NULL) {
585             return NGX_CONF_ERROR;
586         }
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_pcalloc(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
646 
647     } else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {
648         peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
649         if (peer == NULL) {
650             return NGX_CONF_ERROR;
651         }
652 
653         if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
654             return NGX_CONF_ERROR;
655         }
656 
657         new_log->writer = ngx_syslog_writer;
658         new_log->wdata = peer;
659 
660     } else {
661         new_log->file = ngx_conf_open_file(cf->cycle, &value[1]);
662         if (new_log->file == NULL) {
663             return NGX_CONF_ERROR;
664         }
665     }
666 
667     if (ngx_log_set_levels(cf, new_log) != NGX_CONF_OK) {
668         return NGX_CONF_ERROR;
669     }
670 
671     if (*head != new_log) {
672         ngx_log_insert(*head, new_log);
673     }
674 
675     return NGX_CONF_OK;
676 }
677 
678 
679 static void
680 ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log)
681 {
682     ngx_log_t  tmp;
683 
684     if (new_log->log_level > log->log_level) {
685 
686         /*
687          * list head address is permanent, insert new log after
688          * head and swap its contents with head
689          */
690 
691         tmp = *log;
692         *log = *new_log;
693         *new_log = tmp;
694 
695         log->next = new_log;
696         return;
697     }
698 
699     while (log->next) {
700         if (new_log->log_level > log->next->log_level) {
701             new_log->next = log->next;
702             log->next = new_log;
703             return;
704         }
705 
706         log = log->next;
707     }
708 
709     log->next = new_log;
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
756