3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
17 typedef struct ngx_http_log_op_s ngx_http_log_op_t;
19 typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf,
20 ngx_http_log_op_t *op);
22 typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r,
26 struct ngx_http_log_op_s {
28 ngx_http_log_op_getlen_pt getlen;
29 ngx_http_log_op_run_pt run;
37 ngx_array_t *ops; /* array of ngx_http_log_op_t */
42 ngx_array_t formats; /* array of ngx_http_log_fmt_t */
43 ngx_uint_t combined_used; /* unsigned combined_used:1 */
44 } ngx_http_log_main_conf_t;
61 } ngx_http_log_script_t;
65 ngx_open_file_t *file;
66 ngx_http_log_script_t *script;
67 time_t disk_full_time;
68 time_t error_log_time;
69 ngx_syslog_peer_t *syslog_peer;
70 ngx_http_log_fmt_t *format;
71 ngx_http_complex_value_t *filter;
76 ngx_array_t *logs; /* array of ngx_http_log_t */
78 ngx_open_file_cache_t *open_file_cache;
79 time_t open_file_cache_valid;
80 ngx_uint_t open_file_cache_min_uses;
82 ngx_uint_t off; /* unsigned off:1 */
83 } ngx_http_log_loc_conf_t;
89 ngx_http_log_op_run_pt run;
93 static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
94 u_char *buf, size_t len);
95 static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
96 ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len);
99 static ssize_t ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len,
100 ngx_int_t level, ngx_log_t *log);
102 static void *ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size);
103 static void ngx_http_log_gzip_free(void *opaque, void *address);
106 static void ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log);
107 static void ngx_http_log_flush_handler(ngx_event_t *ev);
109 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
110 ngx_http_log_op_t *op);
111 static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
112 ngx_http_log_op_t *op);
113 static u_char *ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf,
114 ngx_http_log_op_t *op);
115 static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
116 ngx_http_log_op_t *op);
117 static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
118 ngx_http_log_op_t *op);
119 static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf,
120 ngx_http_log_op_t *op);
121 static u_char *ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
122 ngx_http_log_op_t *op);
123 static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r,
124 u_char *buf, ngx_http_log_op_t *op);
125 static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
126 ngx_http_log_op_t *op);
128 static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
129 ngx_http_log_op_t *op, ngx_str_t *value, ngx_uint_t json);
130 static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
132 static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
133 ngx_http_log_op_t *op);
134 static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size);
135 static size_t ngx_http_log_json_variable_getlen(ngx_http_request_t *r,
137 static u_char *ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf,
138 ngx_http_log_op_t *op);
141 static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
142 static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf);
143 static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
145 static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
147 static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
149 static char *ngx_http_log_compile_format(ngx_conf_t *cf,
150 ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
151 static char *ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
153 static ngx_int_t ngx_http_log_init(ngx_conf_t *cf);
156 static ngx_command_t ngx_http_log_commands[] = {
158 { ngx_string("log_format"),
159 NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
160 ngx_http_log_set_format,
161 NGX_HTTP_MAIN_CONF_OFFSET,
165 { ngx_string("access_log"),
166 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
167 |NGX_HTTP_LMT_CONF|NGX_CONF_1MORE,
168 ngx_http_log_set_log,
169 NGX_HTTP_LOC_CONF_OFFSET,
173 { ngx_string("open_log_file_cache"),
174 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
175 ngx_http_log_open_file_cache,
176 NGX_HTTP_LOC_CONF_OFFSET,
184 static ngx_http_module_t ngx_http_log_module_ctx = {
185 NULL, /* preconfiguration */
186 ngx_http_log_init, /* postconfiguration */
188 ngx_http_log_create_main_conf, /* create main configuration */
189 NULL, /* init main configuration */
191 NULL, /* create server configuration */
192 NULL, /* merge server configuration */
194 ngx_http_log_create_loc_conf, /* create location configuration */
195 ngx_http_log_merge_loc_conf /* merge location configuration */
199 ngx_module_t ngx_http_log_module = {
201 &ngx_http_log_module_ctx, /* module context */
202 ngx_http_log_commands, /* module directives */
203 NGX_HTTP_MODULE, /* module type */
204 NULL, /* init master */
205 NULL, /* init module */
206 NULL, /* init process */
207 NULL, /* init thread */
208 NULL, /* exit thread */
209 NULL, /* exit process */
210 NULL, /* exit master */
211 NGX_MODULE_V1_PADDING
215 static ngx_str_t ngx_http_access_log = ngx_string(NGX_HTTP_LOG_PATH);
218 static ngx_str_t ngx_http_combined_fmt =
219 ngx_string("$remote_addr - $remote_user [$time_local] "
220 "\"$request\" $status $body_bytes_sent "
221 "\"$http_referer\" \"$http_user_agent\"");
224 static ngx_http_log_var_t ngx_http_log_vars[] = {
225 { ngx_string("pipe"), 1, ngx_http_log_pipe },
226 { ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1,
228 { ngx_string("time_iso8601"), sizeof("1970-09-28T12:00:00+06:00") - 1,
229 ngx_http_log_iso8601 },
230 { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec },
231 { ngx_string("request_time"), NGX_TIME_T_LEN + 4,
232 ngx_http_log_request_time },
233 { ngx_string("status"), NGX_INT_T_LEN, ngx_http_log_status },
234 { ngx_string("bytes_sent"), NGX_OFF_T_LEN, ngx_http_log_bytes_sent },
235 { ngx_string("body_bytes_sent"), NGX_OFF_T_LEN,
236 ngx_http_log_body_bytes_sent },
237 { ngx_string("request_length"), NGX_SIZE_T_LEN,
238 ngx_http_log_request_length },
240 { ngx_null_string, 0, NULL }
245 ngx_http_log_handler(ngx_http_request_t *r)
253 ngx_http_log_op_t *op;
254 ngx_http_log_buf_t *buffer;
255 ngx_http_log_loc_conf_t *lcf;
257 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
260 lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
266 log = lcf->logs->elts;
267 for (l = 0; l < lcf->logs->nelts; l++) {
270 if (ngx_http_complex_value(r, log[l].filter, &val) != NGX_OK) {
274 if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) {
279 if (ngx_time() == log[l].disk_full_time) {
282 * on FreeBSD writing to a full filesystem with enabled softupdates
283 * may block process for much longer time than writing to non-full
284 * filesystem, so we skip writing to a log for one second
290 ngx_http_script_flush_no_cacheable_variables(r, log[l].format->flushes);
293 op = log[l].format->ops->elts;
294 for (i = 0; i < log[l].format->ops->nelts; i++) {
295 if (op[i].len == 0) {
296 len += op[i].getlen(r, op[i].data);
303 if (log[l].syslog_peer) {
305 /* length of syslog's PRI and HEADER message parts */
306 len += sizeof("<255>Jan 01 00:00:00 ") - 1
307 + ngx_cycle->hostname.len + 1
308 + log[l].syslog_peer->tag.len + 2;
313 len += NGX_LINEFEED_SIZE;
315 buffer = log[l].file ? log[l].file->data : NULL;
319 if (len > (size_t) (buffer->last - buffer->pos)) {
321 ngx_http_log_write(r, &log[l], buffer->start,
322 buffer->pos - buffer->start);
324 buffer->pos = buffer->start;
327 if (len <= (size_t) (buffer->last - buffer->pos)) {
331 if (buffer->event && p == buffer->start) {
332 ngx_add_timer(buffer->event, buffer->flush);
335 for (i = 0; i < log[l].format->ops->nelts; i++) {
336 p = op[i].run(r, p, &op[i]);
346 if (buffer->event && buffer->event->timer_set) {
347 ngx_del_timer(buffer->event);
353 line = ngx_pnalloc(r->pool, len);
360 if (log[l].syslog_peer) {
361 p = ngx_syslog_add_header(log[l].syslog_peer, line);
364 for (i = 0; i < log[l].format->ops->nelts; i++) {
365 p = op[i].run(r, p, &op[i]);
368 if (log[l].syslog_peer) {
372 n = ngx_syslog_send(log[l].syslog_peer, line, size);
375 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
376 "send() to syslog failed");
378 } else if ((size_t) n != size) {
379 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
380 "send() to syslog has written only %z of %uz",
389 ngx_http_log_write(r, &log[l], line, p - line);
397 ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
405 ngx_http_log_buf_t *buffer;
408 if (log->script == NULL) {
409 name = log->file->name.data;
412 buffer = log->file->data;
414 if (buffer && buffer->gzip) {
415 n = ngx_http_log_gzip(log->file->fd, buf, len, buffer->gzip,
418 n = ngx_write_fd(log->file->fd, buf, len);
421 n = ngx_write_fd(log->file->fd, buf, len);
426 n = ngx_http_log_script_write(r, log->script, &name, buf, len);
429 if (n == (ssize_t) len) {
438 if (err == NGX_ENOSPC) {
439 log->disk_full_time = now;
442 if (now - log->error_log_time > 59) {
443 ngx_log_error(NGX_LOG_ALERT, r->connection->log, err,
444 ngx_write_fd_n " to \"%s\" failed", name);
446 log->error_log_time = now;
452 if (now - log->error_log_time > 59) {
453 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
454 ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
457 log->error_log_time = now;
463 ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
464 u_char **name, u_char *buf, size_t len)
469 ngx_open_file_info_t of;
470 ngx_http_log_loc_conf_t *llcf;
471 ngx_http_core_loc_conf_t *clcf;
473 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
475 if (!r->root_tested) {
477 /* test root directory existence */
479 if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
480 /* simulate successful logging */
484 path.data[root] = '\0';
486 ngx_memzero(&of, sizeof(ngx_open_file_info_t));
488 of.valid = clcf->open_file_cache_valid;
489 of.min_uses = clcf->open_file_cache_min_uses;
492 of.errors = clcf->open_file_cache_errors;
493 of.events = clcf->open_file_cache_events;
495 if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
496 /* simulate successful logging */
500 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
504 /* simulate successful logging */
508 ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err,
509 "testing \"%s\" existence failed", path.data);
511 /* simulate successful logging */
516 ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ENOTDIR,
517 "testing \"%s\" existence failed", path.data);
519 /* simulate successful logging */
524 if (ngx_http_script_run(r, &log, script->lengths->elts, 1,
525 script->values->elts)
528 /* simulate successful logging */
532 log.data[log.len - 1] = '\0';
535 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
536 "http log \"%s\"", log.data);
538 llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
540 ngx_memzero(&of, sizeof(ngx_open_file_info_t));
543 of.valid = llcf->open_file_cache_valid;
544 of.min_uses = llcf->open_file_cache_min_uses;
545 of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
547 if (ngx_http_set_disable_symlinks(r, clcf, &log, &of) != NGX_OK) {
548 /* simulate successful logging */
552 if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool)
556 /* simulate successful logging */
560 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
561 "%s \"%s\" failed", of.failed, log.data);
562 /* simulate successful logging */
566 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
567 "http log #%d", of.fd);
569 n = ngx_write_fd(of.fd, buf, len);
578 ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,
581 int rc, wbits, memlevel;
590 memlevel = MAX_MEM_LEVEL - 1;
592 while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) {
598 * This is a formula from deflateBound() for conservative upper bound of
599 * compressed data plus 18 bytes of gzip wrapper.
602 size = len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5 + 18;
604 ngx_memzero(&zstream, sizeof(z_stream));
606 pool = ngx_create_pool(256, log);
608 /* simulate successful logging */
614 zstream.zalloc = ngx_http_log_gzip_alloc;
615 zstream.zfree = ngx_http_log_gzip_free;
616 zstream.opaque = pool;
618 out = ngx_pnalloc(pool, size);
623 zstream.next_in = buf;
624 zstream.avail_in = len;
625 zstream.next_out = out;
626 zstream.avail_out = size;
628 rc = deflateInit2(&zstream, (int) level, Z_DEFLATED, wbits + 16, memlevel,
632 ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateInit2() failed: %d", rc);
636 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, log, 0,
637 "deflate in: ni:%p no:%p ai:%ud ao:%ud",
638 zstream.next_in, zstream.next_out,
639 zstream.avail_in, zstream.avail_out);
641 rc = deflate(&zstream, Z_FINISH);
643 if (rc != Z_STREAM_END) {
644 ngx_log_error(NGX_LOG_ALERT, log, 0,
645 "deflate(Z_FINISH) failed: %d", rc);
649 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, log, 0,
650 "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
651 zstream.next_in, zstream.next_out,
652 zstream.avail_in, zstream.avail_out,
655 size -= zstream.avail_out;
657 rc = deflateEnd(&zstream);
660 ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc);
664 n = ngx_write_fd(fd, out, size);
666 if (n != (ssize_t) size) {
667 err = (n == -1) ? ngx_errno : 0;
669 ngx_destroy_pool(pool);
677 ngx_destroy_pool(pool);
679 /* simulate successful logging */
685 ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size)
687 ngx_pool_t *pool = opaque;
689 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pool->log, 0,
690 "gzip alloc: n:%ud s:%ud", items, size);
692 return ngx_palloc(pool, items * size);
697 ngx_http_log_gzip_free(void *opaque, void *address)
700 ngx_pool_t *pool = opaque;
702 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0, "gzip free: %p", address);
710 ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log)
714 ngx_http_log_buf_t *buffer;
718 len = buffer->pos - buffer->start;
726 n = ngx_http_log_gzip(file->fd, buffer->start, len, buffer->gzip, log);
728 n = ngx_write_fd(file->fd, buffer->start, len);
731 n = ngx_write_fd(file->fd, buffer->start, len);
735 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
736 ngx_write_fd_n " to \"%s\" failed",
739 } else if ((size_t) n != len) {
740 ngx_log_error(NGX_LOG_ALERT, log, 0,
741 ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
742 file->name.data, n, len);
745 buffer->pos = buffer->start;
747 if (buffer->event && buffer->event->timer_set) {
748 ngx_del_timer(buffer->event);
754 ngx_http_log_flush_handler(ngx_event_t *ev)
756 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
757 "http log buffer flush handler");
759 ngx_http_log_flush(ev->data, ev->log);
764 ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
765 ngx_http_log_op_t *op)
774 *buf++ = (u_char) (data & 0xff);
783 ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf,
784 ngx_http_log_op_t *op)
786 return ngx_cpymem(buf, (u_char *) op->data, op->len);
791 ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
804 ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
806 return ngx_cpymem(buf, ngx_cached_http_log_time.data,
807 ngx_cached_http_log_time.len);
811 ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
813 return ngx_cpymem(buf, ngx_cached_http_log_iso8601.data,
814 ngx_cached_http_log_iso8601.len);
818 ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
822 tp = ngx_timeofday();
824 return ngx_sprintf(buf, "%T.%03M", tp->sec, tp->msec);
829 ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
830 ngx_http_log_op_t *op)
835 tp = ngx_timeofday();
837 ms = (ngx_msec_int_t)
838 ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
841 return ngx_sprintf(buf, "%T.%03M", (time_t) ms / 1000, ms % 1000);
846 ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
851 status = r->err_status;
853 } else if (r->headers_out.status) {
854 status = r->headers_out.status;
856 } else if (r->http_version == NGX_HTTP_VERSION_9) {
863 return ngx_sprintf(buf, "%03ui", status);
868 ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
869 ngx_http_log_op_t *op)
871 return ngx_sprintf(buf, "%O", r->connection->sent);
876 * although there is a real $body_bytes_sent variable,
877 * this log operation code function is more optimized for logging
881 ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
882 ngx_http_log_op_t *op)
886 length = r->connection->sent - r->header_size;
889 return ngx_sprintf(buf, "%O", length);
899 ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
900 ngx_http_log_op_t *op)
902 return ngx_sprintf(buf, "%O", r->request_length);
907 ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
908 ngx_str_t *value, ngx_uint_t json)
912 index = ngx_http_get_variable_index(cf, value);
913 if (index == NGX_ERROR) {
920 op->getlen = ngx_http_log_json_variable_getlen;
921 op->run = ngx_http_log_json_variable;
924 op->getlen = ngx_http_log_variable_getlen;
925 op->run = ngx_http_log_variable;
935 ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data)
938 ngx_http_variable_value_t *value;
940 value = ngx_http_get_indexed_variable(r, data);
942 if (value == NULL || value->not_found) {
946 len = ngx_http_log_escape(NULL, value->data, value->len);
948 value->escape = len ? 1 : 0;
950 return value->len + len * 3;
955 ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
957 ngx_http_variable_value_t *value;
959 value = ngx_http_get_indexed_variable(r, op->data);
961 if (value == NULL || value->not_found) {
966 if (value->escape == 0) {
967 return ngx_cpymem(buf, value->data, value->len);
970 return (u_char *) ngx_http_log_escape(buf, value->data, value->len);
976 ngx_http_log_escape(u_char *dst, u_char *src, size_t size)
979 static u_char hex[] = "0123456789ABCDEF";
981 static uint32_t escape[] = {
982 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
984 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
985 0x00000004, /* 0000 0000 0000 0000 0000 0000 0000 0100 */
987 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
988 0x10000000, /* 0001 0000 0000 0000 0000 0000 0000 0000 */
990 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
991 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
993 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
994 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
995 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
996 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1002 /* find the number of the characters to be escaped */
1007 if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
1014 return (uintptr_t) n;
1018 if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
1021 *dst++ = hex[*src >> 4];
1022 *dst++ = hex[*src & 0xf];
1031 return (uintptr_t) dst;
1036 ngx_http_log_json_variable_getlen(ngx_http_request_t *r, uintptr_t data)
1039 ngx_http_variable_value_t *value;
1041 value = ngx_http_get_indexed_variable(r, data);
1043 if (value == NULL || value->not_found) {
1047 len = ngx_escape_json(NULL, value->data, value->len);
1049 value->escape = len ? 1 : 0;
1051 return value->len + len;
1056 ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf,
1057 ngx_http_log_op_t *op)
1059 ngx_http_variable_value_t *value;
1061 value = ngx_http_get_indexed_variable(r, op->data);
1063 if (value == NULL || value->not_found) {
1067 if (value->escape == 0) {
1068 return ngx_cpymem(buf, value->data, value->len);
1071 return (u_char *) ngx_escape_json(buf, value->data, value->len);
1077 ngx_http_log_create_main_conf(ngx_conf_t *cf)
1079 ngx_http_log_main_conf_t *conf;
1081 ngx_http_log_fmt_t *fmt;
1083 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
1088 if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t))
1094 fmt = ngx_array_push(&conf->formats);
1099 ngx_str_set(&fmt->name, "combined");
1101 fmt->flushes = NULL;
1103 fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
1104 if (fmt->ops == NULL) {
1113 ngx_http_log_create_loc_conf(ngx_conf_t *cf)
1115 ngx_http_log_loc_conf_t *conf;
1117 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t));
1122 conf->open_file_cache = NGX_CONF_UNSET_PTR;
1129 ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
1131 ngx_http_log_loc_conf_t *prev = parent;
1132 ngx_http_log_loc_conf_t *conf = child;
1134 ngx_http_log_t *log;
1135 ngx_http_log_fmt_t *fmt;
1136 ngx_http_log_main_conf_t *lmcf;
1138 if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
1140 conf->open_file_cache = prev->open_file_cache;
1141 conf->open_file_cache_valid = prev->open_file_cache_valid;
1142 conf->open_file_cache_min_uses = prev->open_file_cache_min_uses;
1144 if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
1145 conf->open_file_cache = NULL;
1149 if (conf->logs || conf->off) {
1153 conf->logs = prev->logs;
1154 conf->off = prev->off;
1156 if (conf->logs || conf->off) {
1160 conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
1161 if (conf->logs == NULL) {
1162 return NGX_CONF_ERROR;
1165 log = ngx_array_push(conf->logs);
1167 return NGX_CONF_ERROR;
1170 ngx_memzero(log, sizeof(ngx_http_log_t));
1172 log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log);
1173 if (log->file == NULL) {
1174 return NGX_CONF_ERROR;
1177 lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
1178 fmt = lmcf->formats.elts;
1180 /* the default "combined" format */
1181 log->format = &fmt[0];
1182 lmcf->combined_used = 1;
1189 ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1191 ngx_http_log_loc_conf_t *llcf = conf;
1197 ngx_str_t *value, name, s;
1198 ngx_http_log_t *log;
1199 ngx_syslog_peer_t *peer;
1200 ngx_http_log_buf_t *buffer;
1201 ngx_http_log_fmt_t *fmt;
1202 ngx_http_log_main_conf_t *lmcf;
1203 ngx_http_script_compile_t sc;
1204 ngx_http_compile_complex_value_t ccv;
1206 value = cf->args->elts;
1208 if (ngx_strcmp(value[1].data, "off") == 0) {
1210 if (cf->args->nelts == 2) {
1214 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1215 "invalid parameter \"%V\"", &value[2]);
1216 return NGX_CONF_ERROR;
1219 if (llcf->logs == NULL) {
1220 llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
1221 if (llcf->logs == NULL) {
1222 return NGX_CONF_ERROR;
1226 lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
1228 log = ngx_array_push(llcf->logs);
1230 return NGX_CONF_ERROR;
1233 ngx_memzero(log, sizeof(ngx_http_log_t));
1236 if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {
1238 peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
1240 return NGX_CONF_ERROR;
1243 if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
1244 return NGX_CONF_ERROR;
1247 log->syslog_peer = peer;
1249 goto process_formats;
1252 n = ngx_http_script_variables_count(&value[1]);
1255 log->file = ngx_conf_open_file(cf->cycle, &value[1]);
1256 if (log->file == NULL) {
1257 return NGX_CONF_ERROR;
1261 if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
1262 return NGX_CONF_ERROR;
1265 log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t));
1266 if (log->script == NULL) {
1267 return NGX_CONF_ERROR;
1270 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1273 sc.source = &value[1];
1274 sc.lengths = &log->script->lengths;
1275 sc.values = &log->script->values;
1277 sc.complete_lengths = 1;
1278 sc.complete_values = 1;
1280 if (ngx_http_script_compile(&sc) != NGX_OK) {
1281 return NGX_CONF_ERROR;
1287 if (cf->args->nelts >= 3) {
1290 if (ngx_strcmp(name.data, "combined") == 0) {
1291 lmcf->combined_used = 1;
1295 ngx_str_set(&name, "combined");
1296 lmcf->combined_used = 1;
1299 fmt = lmcf->formats.elts;
1300 for (i = 0; i < lmcf->formats.nelts; i++) {
1301 if (fmt[i].name.len == name.len
1302 && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
1304 log->format = &fmt[i];
1309 if (log->format == NULL) {
1310 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1311 "unknown log format \"%V\"", &name);
1312 return NGX_CONF_ERROR;
1319 for (i = 3; i < cf->args->nelts; i++) {
1321 if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
1322 s.len = value[i].len - 7;
1323 s.data = value[i].data + 7;
1325 size = ngx_parse_size(&s);
1327 if (size == NGX_ERROR || size == 0) {
1328 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1329 "invalid buffer size \"%V\"", &s);
1330 return NGX_CONF_ERROR;
1336 if (ngx_strncmp(value[i].data, "flush=", 6) == 0) {
1337 s.len = value[i].len - 6;
1338 s.data = value[i].data + 6;
1340 flush = ngx_parse_time(&s, 0);
1342 if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) {
1343 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1344 "invalid flush time \"%V\"", &s);
1345 return NGX_CONF_ERROR;
1351 if (ngx_strncmp(value[i].data, "gzip", 4) == 0
1352 && (value[i].len == 4 || value[i].data[4] == '='))
1359 if (value[i].len == 4) {
1360 gzip = Z_BEST_SPEED;
1364 s.len = value[i].len - 5;
1365 s.data = value[i].data + 5;
1367 gzip = ngx_atoi(s.data, s.len);
1369 if (gzip < 1 || gzip > 9) {
1370 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1371 "invalid compression level \"%V\"", &s);
1372 return NGX_CONF_ERROR;
1378 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1379 "nginx was built without zlib support");
1380 return NGX_CONF_ERROR;
1384 if (ngx_strncmp(value[i].data, "if=", 3) == 0) {
1385 s.len = value[i].len - 3;
1386 s.data = value[i].data + 3;
1388 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
1392 ccv.complex_value = ngx_palloc(cf->pool,
1393 sizeof(ngx_http_complex_value_t));
1394 if (ccv.complex_value == NULL) {
1395 return NGX_CONF_ERROR;
1398 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
1399 return NGX_CONF_ERROR;
1402 log->filter = ccv.complex_value;
1407 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1408 "invalid parameter \"%V\"", &value[i]);
1409 return NGX_CONF_ERROR;
1412 if (flush && size == 0) {
1413 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1414 "no buffer is defined for access_log \"%V\"",
1416 return NGX_CONF_ERROR;
1422 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1423 "buffered logs cannot have variables in name");
1424 return NGX_CONF_ERROR;
1427 if (log->syslog_peer) {
1428 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1429 "logs to syslog cannot be buffered");
1430 return NGX_CONF_ERROR;
1433 if (log->file->data) {
1434 buffer = log->file->data;
1436 if (buffer->last - buffer->start != size
1437 || buffer->flush != flush
1438 || buffer->gzip != gzip)
1440 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1441 "access_log \"%V\" already defined "
1442 "with conflicting parameters",
1444 return NGX_CONF_ERROR;
1450 buffer = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_buf_t));
1451 if (buffer == NULL) {
1452 return NGX_CONF_ERROR;
1455 buffer->start = ngx_pnalloc(cf->pool, size);
1456 if (buffer->start == NULL) {
1457 return NGX_CONF_ERROR;
1460 buffer->pos = buffer->start;
1461 buffer->last = buffer->start + size;
1464 buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
1465 if (buffer->event == NULL) {
1466 return NGX_CONF_ERROR;
1469 buffer->event->data = log->file;
1470 buffer->event->handler = ngx_http_log_flush_handler;
1471 buffer->event->log = &cf->cycle->new_log;
1472 buffer->event->cancelable = 1;
1474 buffer->flush = flush;
1477 buffer->gzip = gzip;
1479 log->file->flush = ngx_http_log_flush;
1480 log->file->data = buffer;
1488 ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1490 ngx_http_log_main_conf_t *lmcf = conf;
1494 ngx_http_log_fmt_t *fmt;
1496 value = cf->args->elts;
1498 fmt = lmcf->formats.elts;
1499 for (i = 0; i < lmcf->formats.nelts; i++) {
1500 if (fmt[i].name.len == value[1].len
1501 && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
1503 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1504 "duplicate \"log_format\" name \"%V\"",
1506 return NGX_CONF_ERROR;
1510 fmt = ngx_array_push(&lmcf->formats);
1512 return NGX_CONF_ERROR;
1515 fmt->name = value[1];
1517 fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
1518 if (fmt->flushes == NULL) {
1519 return NGX_CONF_ERROR;
1522 fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
1523 if (fmt->ops == NULL) {
1524 return NGX_CONF_ERROR;
1527 return ngx_http_log_compile_format(cf, fmt->flushes, fmt->ops, cf->args, 2);
1532 ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
1533 ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
1535 u_char *data, *p, ch;
1537 ngx_str_t *value, var;
1539 ngx_uint_t bracket, json;
1540 ngx_http_log_op_t *op;
1541 ngx_http_log_var_t *v;
1546 if (s < args->nelts && ngx_strncmp(value[s].data, "escape=", 7) == 0) {
1547 data = value[s].data + 7;
1549 if (ngx_strcmp(data, "json") == 0) {
1552 } else if (ngx_strcmp(data, "default") != 0) {
1553 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1554 "unknown log format escaping \"%s\"", data);
1555 return NGX_CONF_ERROR;
1561 for ( /* void */ ; s < args->nelts; s++) {
1565 while (i < value[s].len) {
1567 op = ngx_array_push(ops);
1569 return NGX_CONF_ERROR;
1572 data = &value[s].data[i];
1574 if (value[s].data[i] == '$') {
1576 if (++i == value[s].len) {
1580 if (value[s].data[i] == '{') {
1583 if (++i == value[s].len) {
1587 var.data = &value[s].data[i];
1591 var.data = &value[s].data[i];
1594 for (var.len = 0; i < value[s].len; i++, var.len++) {
1595 ch = value[s].data[i];
1597 if (ch == '}' && bracket) {
1603 if ((ch >= 'A' && ch <= 'Z')
1604 || (ch >= 'a' && ch <= 'z')
1605 || (ch >= '0' && ch <= '9')
1615 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1616 "the closing bracket in \"%V\" "
1617 "variable is missing", &var);
1618 return NGX_CONF_ERROR;
1625 for (v = ngx_http_log_vars; v->name.len; v++) {
1627 if (v->name.len == var.len
1628 && ngx_strncmp(v->name.data, var.data, var.len) == 0)
1639 if (ngx_http_log_variable_compile(cf, op, &var, json)
1642 return NGX_CONF_ERROR;
1647 flush = ngx_array_push(flushes);
1648 if (flush == NULL) {
1649 return NGX_CONF_ERROR;
1652 *flush = op->data; /* variable index */
1662 while (i < value[s].len && value[s].data[i] != '$') {
1666 len = &value[s].data[i] - data;
1673 if (len <= sizeof(uintptr_t)) {
1674 op->run = ngx_http_log_copy_short;
1679 op->data |= data[len];
1683 op->run = ngx_http_log_copy_long;
1685 p = ngx_pnalloc(cf->pool, len);
1687 return NGX_CONF_ERROR;
1690 ngx_memcpy(p, data, len);
1691 op->data = (uintptr_t) p;
1701 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);
1703 return NGX_CONF_ERROR;
1708 ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1710 ngx_http_log_loc_conf_t *llcf = conf;
1712 time_t inactive, valid;
1713 ngx_str_t *value, s;
1714 ngx_int_t max, min_uses;
1717 if (llcf->open_file_cache != NGX_CONF_UNSET_PTR) {
1718 return "is duplicate";
1721 value = cf->args->elts;
1728 for (i = 1; i < cf->args->nelts; i++) {
1730 if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
1732 max = ngx_atoi(value[i].data + 4, value[i].len - 4);
1733 if (max == NGX_ERROR) {
1740 if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
1742 s.len = value[i].len - 9;
1743 s.data = value[i].data + 9;
1745 inactive = ngx_parse_time(&s, 1);
1746 if (inactive == (time_t) NGX_ERROR) {
1753 if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) {
1755 min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
1756 if (min_uses == NGX_ERROR) {
1763 if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
1765 s.len = value[i].len - 6;
1766 s.data = value[i].data + 6;
1768 valid = ngx_parse_time(&s, 1);
1769 if (valid == (time_t) NGX_ERROR) {
1776 if (ngx_strcmp(value[i].data, "off") == 0) {
1778 llcf->open_file_cache = NULL;
1785 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1786 "invalid \"open_log_file_cache\" parameter \"%V\"",
1788 return NGX_CONF_ERROR;
1791 if (llcf->open_file_cache == NULL) {
1796 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1797 "\"open_log_file_cache\" must have \"max\" parameter");
1798 return NGX_CONF_ERROR;
1801 llcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
1803 if (llcf->open_file_cache) {
1805 llcf->open_file_cache_valid = valid;
1806 llcf->open_file_cache_min_uses = min_uses;
1811 return NGX_CONF_ERROR;
1816 ngx_http_log_init(ngx_conf_t *cf)
1820 ngx_http_handler_pt *h;
1821 ngx_http_log_fmt_t *fmt;
1822 ngx_http_log_main_conf_t *lmcf;
1823 ngx_http_core_main_conf_t *cmcf;
1825 lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
1827 if (lmcf->combined_used) {
1828 if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) {
1832 value = ngx_array_push(&a);
1833 if (value == NULL) {
1837 *value = ngx_http_combined_fmt;
1838 fmt = lmcf->formats.elts;
1840 if (ngx_http_log_compile_format(cf, NULL, fmt->ops, &a, 0)
1847 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
1849 h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
1854 *h = ngx_http_log_handler;