Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_log_module.c
Go to the documentation of this file.
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 #include <ngx_http.h>
11 
12 #if (NGX_ZLIB)
13 #include <zlib.h>
14 #endif
15 
16 
18 
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);
21 
23  uintptr_t data);
24 
25 
27  size_t len;
30  uintptr_t data;
31 };
32 
33 
34 typedef struct {
37  ngx_array_t *ops; /* array of ngx_http_log_op_t */
39 
40 
41 typedef struct {
42  ngx_array_t formats; /* array of ngx_http_log_fmt_t */
43  ngx_uint_t combined_used; /* unsigned combined_used:1 */
45 
46 
47 typedef struct {
48  u_char *start;
49  u_char *pos;
50  u_char *last;
51 
56 
57 
58 typedef struct {
62 
63 
64 typedef struct {
71 
72 
73 typedef struct {
74  ngx_array_t *logs; /* array of ngx_http_log_t */
75 
79 
80  ngx_uint_t off; /* unsigned off:1 */
82 
83 
84 typedef struct {
86  size_t len;
89 
90 
91 static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
92  u_char *buf, size_t len);
93 static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
94  ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len);
95 
96 #if (NGX_ZLIB)
97 static ssize_t ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len,
98  ngx_int_t level, ngx_log_t *log);
99 
100 static void *ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size);
101 static void ngx_http_log_gzip_free(void *opaque, void *address);
102 #endif
103 
104 static void ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log);
105 static void ngx_http_log_flush_handler(ngx_event_t *ev);
106 
107 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
108  ngx_http_log_op_t *op);
109 static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
110  ngx_http_log_op_t *op);
111 static u_char *ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf,
112  ngx_http_log_op_t *op);
113 static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
114  ngx_http_log_op_t *op);
115 static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
116  ngx_http_log_op_t *op);
117 static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf,
118  ngx_http_log_op_t *op);
119 static u_char *ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
120  ngx_http_log_op_t *op);
121 static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r,
122  u_char *buf, ngx_http_log_op_t *op);
123 static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
124  ngx_http_log_op_t *op);
125 
126 static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
127  ngx_http_log_op_t *op, ngx_str_t *value);
128 static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
129  uintptr_t data);
130 static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
131  ngx_http_log_op_t *op);
132 static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size);
133 
134 
135 static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
136 static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf);
137 static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
138  void *child);
139 static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
140  void *conf);
141 static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
142  void *conf);
143 static char *ngx_http_log_compile_format(ngx_conf_t *cf,
144  ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
145 static char *ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
146  void *conf);
147 static ngx_int_t ngx_http_log_init(ngx_conf_t *cf);
148 
149 
150 static ngx_command_t ngx_http_log_commands[] = {
151 
152  { ngx_string("log_format"),
154  ngx_http_log_set_format,
156  0,
157  NULL },
158 
159  { ngx_string("access_log"),
162  ngx_http_log_set_log,
164  0,
165  NULL },
166 
167  { ngx_string("open_log_file_cache"),
169  ngx_http_log_open_file_cache,
171  0,
172  NULL },
173 
175 };
176 
177 
178 static ngx_http_module_t ngx_http_log_module_ctx = {
179  NULL, /* preconfiguration */
180  ngx_http_log_init, /* postconfiguration */
181 
182  ngx_http_log_create_main_conf, /* create main configuration */
183  NULL, /* init main configuration */
184 
185  NULL, /* create server configuration */
186  NULL, /* merge server configuration */
187 
188  ngx_http_log_create_loc_conf, /* create location configuration */
189  ngx_http_log_merge_loc_conf /* merge location configuration */
190 };
191 
192 
195  &ngx_http_log_module_ctx, /* module context */
196  ngx_http_log_commands, /* module directives */
197  NGX_HTTP_MODULE, /* module type */
198  NULL, /* init master */
199  NULL, /* init module */
200  NULL, /* init process */
201  NULL, /* init thread */
202  NULL, /* exit thread */
203  NULL, /* exit process */
204  NULL, /* exit master */
206 };
207 
208 
209 static ngx_str_t ngx_http_access_log = ngx_string(NGX_HTTP_LOG_PATH);
210 
211 
212 static ngx_str_t ngx_http_combined_fmt =
213  ngx_string("$remote_addr - $remote_user [$time_local] "
214  "\"$request\" $status $body_bytes_sent "
215  "\"$http_referer\" \"$http_user_agent\"");
216 
217 
218 static ngx_http_log_var_t ngx_http_log_vars[] = {
219  { ngx_string("pipe"), 1, ngx_http_log_pipe },
220  { ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1,
221  ngx_http_log_time },
222  { ngx_string("time_iso8601"), sizeof("1970-09-28T12:00:00+06:00") - 1,
223  ngx_http_log_iso8601 },
224  { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec },
225  { ngx_string("request_time"), NGX_TIME_T_LEN + 4,
226  ngx_http_log_request_time },
227  { ngx_string("status"), NGX_INT_T_LEN, ngx_http_log_status },
228  { ngx_string("bytes_sent"), NGX_OFF_T_LEN, ngx_http_log_bytes_sent },
229  { ngx_string("body_bytes_sent"), NGX_OFF_T_LEN,
230  ngx_http_log_body_bytes_sent },
231  { ngx_string("request_length"), NGX_SIZE_T_LEN,
232  ngx_http_log_request_length },
233 
234  { ngx_null_string, 0, NULL }
235 };
236 
237 
238 static ngx_int_t
239 ngx_http_log_handler(ngx_http_request_t *r)
240 {
241  u_char *line, *p;
242  size_t len;
243  ngx_uint_t i, l;
244  ngx_http_log_t *log;
245  ngx_http_log_op_t *op;
248 
250  "http log handler");
251 
252  lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
253 
254  if (lcf->off) {
255  return NGX_OK;
256  }
257 
258  log = lcf->logs->elts;
259  for (l = 0; l < lcf->logs->nelts; l++) {
260 
261  if (ngx_time() == log[l].disk_full_time) {
262 
263  /*
264  * on FreeBSD writing to a full filesystem with enabled softupdates
265  * may block process for much longer time than writing to non-full
266  * filesystem, so we skip writing to a log for one second
267  */
268 
269  continue;
270  }
271 
272  ngx_http_script_flush_no_cacheable_variables(r, log[l].format->flushes);
273 
274  len = 0;
275  op = log[l].format->ops->elts;
276  for (i = 0; i < log[l].format->ops->nelts; i++) {
277  if (op[i].len == 0) {
278  len += op[i].getlen(r, op[i].data);
279 
280  } else {
281  len += op[i].len;
282  }
283  }
284 
285  len += NGX_LINEFEED_SIZE;
286 
287  buffer = log[l].file ? log[l].file->data : NULL;
288 
289  if (buffer) {
290 
291  if (len > (size_t) (buffer->last - buffer->pos)) {
292 
293  ngx_http_log_write(r, &log[l], buffer->start,
294  buffer->pos - buffer->start);
295 
296  buffer->pos = buffer->start;
297  }
298 
299  if (len <= (size_t) (buffer->last - buffer->pos)) {
300 
301  p = buffer->pos;
302 
303  if (buffer->event && p == buffer->start) {
304  ngx_add_timer(buffer->event, buffer->flush);
305  }
306 
307  for (i = 0; i < log[l].format->ops->nelts; i++) {
308  p = op[i].run(r, p, &op[i]);
309  }
310 
311  ngx_linefeed(p);
312 
313  buffer->pos = p;
314 
315  continue;
316  }
317 
318  if (buffer->event && buffer->event->timer_set) {
319  ngx_del_timer(buffer->event);
320  }
321  }
322 
323  line = ngx_pnalloc(r->pool, len);
324  if (line == NULL) {
325  return NGX_ERROR;
326  }
327 
328  p = line;
329 
330  for (i = 0; i < log[l].format->ops->nelts; i++) {
331  p = op[i].run(r, p, &op[i]);
332  }
333 
334  ngx_linefeed(p);
335 
336  ngx_http_log_write(r, &log[l], line, p - line);
337  }
338 
339  return NGX_OK;
340 }
341 
342 
343 static void
344 ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
345  size_t len)
346 {
347  u_char *name;
348  time_t now;
349  ssize_t n;
350  ngx_err_t err;
351 #if (NGX_ZLIB)
353 #endif
354 
355  if (log->script == NULL) {
356  name = log->file->name.data;
357 
358 #if (NGX_ZLIB)
359  buffer = log->file->data;
360 
361  if (buffer && buffer->gzip) {
362  n = ngx_http_log_gzip(log->file->fd, buf, len, buffer->gzip,
363  r->connection->log);
364  } else {
365  n = ngx_write_fd(log->file->fd, buf, len);
366  }
367 #else
368  n = ngx_write_fd(log->file->fd, buf, len);
369 #endif
370 
371  } else {
372  name = NULL;
373  n = ngx_http_log_script_write(r, log->script, &name, buf, len);
374  }
375 
376  if (n == (ssize_t) len) {
377  return;
378  }
379 
380  now = ngx_time();
381 
382  if (n == -1) {
383  err = ngx_errno;
384 
385  if (err == NGX_ENOSPC) {
386  log->disk_full_time = now;
387  }
388 
389  if (now - log->error_log_time > 59) {
391  ngx_write_fd_n " to \"%s\" failed", name);
392 
393  log->error_log_time = now;
394  }
395 
396  return;
397  }
398 
399  if (now - log->error_log_time > 59) {
401  ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
402  name, n, len);
403 
404  log->error_log_time = now;
405  }
406 }
407 
408 
409 static ssize_t
410 ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
411  u_char **name, u_char *buf, size_t len)
412 {
413  size_t root;
414  ssize_t n;
415  ngx_str_t log, path;
419 
421 
422  if (!r->root_tested) {
423 
424  /* test root directory existence */
425 
426  if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
427  /* simulate successful logging */
428  return len;
429  }
430 
431  path.data[root] = '\0';
432 
433  ngx_memzero(&of, sizeof(ngx_open_file_info_t));
434 
435  of.valid = clcf->open_file_cache_valid;
437  of.test_dir = 1;
438  of.test_only = 1;
439  of.errors = clcf->open_file_cache_errors;
440  of.events = clcf->open_file_cache_events;
441 
442  if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
443  /* simulate successful logging */
444  return len;
445  }
446 
447  if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
448  != NGX_OK)
449  {
450  if (of.err == 0) {
451  /* simulate successful logging */
452  return len;
453  }
454 
456  "testing \"%s\" existence failed", path.data);
457 
458  /* simulate successful logging */
459  return len;
460  }
461 
462  if (!of.is_dir) {
464  "testing \"%s\" existence failed", path.data);
465 
466  /* simulate successful logging */
467  return len;
468  }
469  }
470 
471  if (ngx_http_script_run(r, &log, script->lengths->elts, 1,
472  script->values->elts)
473  == NULL)
474  {
475  /* simulate successful logging */
476  return len;
477  }
478 
479  log.data[log.len - 1] = '\0';
480  *name = log.data;
481 
483  "http log \"%s\"", log.data);
484 
485  llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
486 
487  ngx_memzero(&of, sizeof(ngx_open_file_info_t));
488 
489  of.log = 1;
490  of.valid = llcf->open_file_cache_valid;
493 
494  if (ngx_http_set_disable_symlinks(r, clcf, &log, &of) != NGX_OK) {
495  /* simulate successful logging */
496  return len;
497  }
498 
499  if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool)
500  != NGX_OK)
501  {
503  "%s \"%s\" failed", of.failed, log.data);
504  /* simulate successful logging */
505  return len;
506  }
507 
509  "http log #%d", of.fd);
510 
511  n = ngx_write_fd(of.fd, buf, len);
512 
513  return n;
514 }
515 
516 
517 #if (NGX_ZLIB)
518 
519 static ssize_t
520 ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,
521  ngx_log_t *log)
522 {
523  int rc, wbits, memlevel;
524  u_char *out;
525  size_t size;
526  ssize_t n;
527  z_stream zstream;
528  ngx_err_t err;
529  ngx_pool_t *pool;
530 
531  wbits = MAX_WBITS;
532  memlevel = MAX_MEM_LEVEL - 1;
533 
534  while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) {
535  wbits--;
536  memlevel--;
537  }
538 
539  /*
540  * This is a formula from deflateBound() for conservative upper bound of
541  * compressed data plus 18 bytes of gzip wrapper.
542  */
543 
544  size = len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5 + 18;
545 
546  ngx_memzero(&zstream, sizeof(z_stream));
547 
548  pool = ngx_create_pool(256, log);
549  if (pool == NULL) {
550  /* simulate successful logging */
551  return len;
552  }
553 
554  pool->log = log;
555 
556  zstream.zalloc = ngx_http_log_gzip_alloc;
557  zstream.zfree = ngx_http_log_gzip_free;
558  zstream.opaque = pool;
559 
560  out = ngx_pnalloc(pool, size);
561  if (out == NULL) {
562  goto done;
563  }
564 
565  zstream.next_in = buf;
566  zstream.avail_in = len;
567  zstream.next_out = out;
568  zstream.avail_out = size;
569 
570  rc = deflateInit2(&zstream, (int) level, Z_DEFLATED, wbits + 16, memlevel,
571  Z_DEFAULT_STRATEGY);
572 
573  if (rc != Z_OK) {
574  ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateInit2() failed: %d", rc);
575  goto done;
576  }
577 
579  "deflate in: ni:%p no:%p ai:%ud ao:%ud",
580  zstream.next_in, zstream.next_out,
581  zstream.avail_in, zstream.avail_out);
582 
583  rc = deflate(&zstream, Z_FINISH);
584 
585  if (rc != Z_STREAM_END) {
587  "deflate(Z_FINISH) failed: %d", rc);
588  goto done;
589  }
590 
592  "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
593  zstream.next_in, zstream.next_out,
594  zstream.avail_in, zstream.avail_out,
595  rc);
596 
597  size -= zstream.avail_out;
598 
599  rc = deflateEnd(&zstream);
600 
601  if (rc != Z_OK) {
602  ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc);
603  goto done;
604  }
605 
606  n = ngx_write_fd(fd, out, size);
607 
608  if (n != (ssize_t) size) {
609  err = (n == -1) ? ngx_errno : 0;
610 
611  ngx_destroy_pool(pool);
612 
613  ngx_set_errno(err);
614  return -1;
615  }
616 
617 done:
618 
619  ngx_destroy_pool(pool);
620 
621  /* simulate successful logging */
622  return len;
623 }
624 
625 
626 static void *
627 ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size)
628 {
629  ngx_pool_t *pool = opaque;
630 
632  "gzip alloc: n:%ud s:%ud", items, size);
633 
634  return ngx_palloc(pool, items * size);
635 }
636 
637 
638 static void
639 ngx_http_log_gzip_free(void *opaque, void *address)
640 {
641 #if 0
642  ngx_pool_t *pool = opaque;
643 
644  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0, "gzip free: %p", address);
645 #endif
646 }
647 
648 #endif
649 
650 
651 static void
652 ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log)
653 {
654  size_t len;
655  ssize_t n;
657 
658  buffer = file->data;
659 
660  len = buffer->pos - buffer->start;
661 
662  if (len == 0) {
663  return;
664  }
665 
666 #if (NGX_ZLIB)
667  if (buffer->gzip) {
668  n = ngx_http_log_gzip(file->fd, buffer->start, len, buffer->gzip, log);
669  } else {
670  n = ngx_write_fd(file->fd, buffer->start, len);
671  }
672 #else
673  n = ngx_write_fd(file->fd, buffer->start, len);
674 #endif
675 
676  if (n == -1) {
678  ngx_write_fd_n " to \"%s\" failed",
679  file->name.data);
680 
681  } else if ((size_t) n != len) {
683  ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
684  file->name.data, n, len);
685  }
686 
687  buffer->pos = buffer->start;
688 
689  if (buffer->event && buffer->event->timer_set) {
690  ngx_del_timer(buffer->event);
691  }
692 }
693 
694 
695 static void
696 ngx_http_log_flush_handler(ngx_event_t *ev)
697 {
699  "http log buffer flush handler");
700 
701  ngx_http_log_flush(ev->data, ev->log);
702 }
703 
704 
705 static u_char *
706 ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
707  ngx_http_log_op_t *op)
708 {
709  size_t len;
710  uintptr_t data;
711 
712  len = op->len;
713  data = op->data;
714 
715  while (len--) {
716  *buf++ = (u_char) (data & 0xff);
717  data >>= 8;
718  }
719 
720  return buf;
721 }
722 
723 
724 static u_char *
725 ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf,
726  ngx_http_log_op_t *op)
727 {
728  return ngx_cpymem(buf, (u_char *) op->data, op->len);
729 }
730 
731 
732 static u_char *
733 ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
734 {
735  if (r->pipeline) {
736  *buf = 'p';
737  } else {
738  *buf = '.';
739  }
740 
741  return buf + 1;
742 }
743 
744 
745 static u_char *
746 ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
747 {
750 }
751 
752 static u_char *
753 ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
754 {
757 }
758 
759 static u_char *
760 ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
761 {
762  ngx_time_t *tp;
763 
764  tp = ngx_timeofday();
765 
766  return ngx_sprintf(buf, "%T.%03M", tp->sec, tp->msec);
767 }
768 
769 
770 static u_char *
771 ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
772  ngx_http_log_op_t *op)
773 {
774  ngx_time_t *tp;
775  ngx_msec_int_t ms;
776 
777  tp = ngx_timeofday();
778 
779  ms = (ngx_msec_int_t)
780  ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
781  ms = ngx_max(ms, 0);
782 
783  return ngx_sprintf(buf, "%T.%03M", ms / 1000, ms % 1000);
784 }
785 
786 
787 static u_char *
788 ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
789 {
790  ngx_uint_t status;
791 
792  if (r->err_status) {
793  status = r->err_status;
794 
795  } else if (r->headers_out.status) {
796  status = r->headers_out.status;
797 
798  } else if (r->http_version == NGX_HTTP_VERSION_9) {
799  status = 9;
800 
801  } else {
802  status = 0;
803  }
804 
805  return ngx_sprintf(buf, "%03ui", status);
806 }
807 
808 
809 static u_char *
810 ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
811  ngx_http_log_op_t *op)
812 {
813  return ngx_sprintf(buf, "%O", r->connection->sent);
814 }
815 
816 
817 /*
818  * although there is a real $body_bytes_sent variable,
819  * this log operation code function is more optimized for logging
820  */
821 
822 static u_char *
823 ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
824  ngx_http_log_op_t *op)
825 {
826  off_t length;
827 
828  length = r->connection->sent - r->header_size;
829 
830  if (length > 0) {
831  return ngx_sprintf(buf, "%O", length);
832  }
833 
834  *buf = '0';
835 
836  return buf + 1;
837 }
838 
839 
840 static u_char *
841 ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
842  ngx_http_log_op_t *op)
843 {
844  return ngx_sprintf(buf, "%O", r->request_length);
845 }
846 
847 
848 static ngx_int_t
849 ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
850  ngx_str_t *value)
851 {
853 
854  index = ngx_http_get_variable_index(cf, value);
855  if (index == NGX_ERROR) {
856  return NGX_ERROR;
857  }
858 
859  op->len = 0;
860  op->getlen = ngx_http_log_variable_getlen;
861  op->run = ngx_http_log_variable;
862  op->data = index;
863 
864  return NGX_OK;
865 }
866 
867 
868 static size_t
869 ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data)
870 {
871  uintptr_t len;
873 
874  value = ngx_http_get_indexed_variable(r, data);
875 
876  if (value == NULL || value->not_found) {
877  return 1;
878  }
879 
880  len = ngx_http_log_escape(NULL, value->data, value->len);
881 
882  value->escape = len ? 1 : 0;
883 
884  return value->len + len * 3;
885 }
886 
887 
888 static u_char *
889 ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
890 {
892 
893  value = ngx_http_get_indexed_variable(r, op->data);
894 
895  if (value == NULL || value->not_found) {
896  *buf = '-';
897  return buf + 1;
898  }
899 
900  if (value->escape == 0) {
901  return ngx_cpymem(buf, value->data, value->len);
902 
903  } else {
904  return (u_char *) ngx_http_log_escape(buf, value->data, value->len);
905  }
906 }
907 
908 
909 static uintptr_t
910 ngx_http_log_escape(u_char *dst, u_char *src, size_t size)
911 {
912  ngx_uint_t n;
913  static u_char hex[] = "0123456789ABCDEF";
914 
915  static uint32_t escape[] = {
916  0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
917 
918  /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
919  0x00000004, /* 0000 0000 0000 0000 0000 0000 0000 0100 */
920 
921  /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
922  0x10000000, /* 0001 0000 0000 0000 0000 0000 0000 0000 */
923 
924  /* ~}| {zyx wvut srqp onml kjih gfed cba` */
925  0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
926 
927  0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
928  0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
929  0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
930  0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
931  };
932 
933 
934  if (dst == NULL) {
935 
936  /* find the number of the characters to be escaped */
937 
938  n = 0;
939 
940  while (size) {
941  if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
942  n++;
943  }
944  src++;
945  size--;
946  }
947 
948  return (uintptr_t) n;
949  }
950 
951  while (size) {
952  if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
953  *dst++ = '\\';
954  *dst++ = 'x';
955  *dst++ = hex[*src >> 4];
956  *dst++ = hex[*src & 0xf];
957  src++;
958 
959  } else {
960  *dst++ = *src++;
961  }
962  size--;
963  }
964 
965  return (uintptr_t) dst;
966 }
967 
968 
969 static void *
970 ngx_http_log_create_main_conf(ngx_conf_t *cf)
971 {
973 
974  ngx_http_log_fmt_t *fmt;
975 
976  conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
977  if (conf == NULL) {
978  return NULL;
979  }
980 
981  if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t))
982  != NGX_OK)
983  {
984  return NULL;
985  }
986 
987  fmt = ngx_array_push(&conf->formats);
988  if (fmt == NULL) {
989  return NULL;
990  }
991 
992  ngx_str_set(&fmt->name, "combined");
993 
994  fmt->flushes = NULL;
995 
996  fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
997  if (fmt->ops == NULL) {
998  return NULL;
999  }
1000 
1001  return conf;
1002 }
1003 
1004 
1005 static void *
1006 ngx_http_log_create_loc_conf(ngx_conf_t *cf)
1007 {
1009 
1010  conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t));
1011  if (conf == NULL) {
1012  return NULL;
1013  }
1014 
1016 
1017  return conf;
1018 }
1019 
1020 
1021 static char *
1022 ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
1023 {
1024  ngx_http_log_loc_conf_t *prev = parent;
1025  ngx_http_log_loc_conf_t *conf = child;
1026 
1027  ngx_http_log_t *log;
1028  ngx_http_log_fmt_t *fmt;
1030 
1031  if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
1032 
1033  conf->open_file_cache = prev->open_file_cache;
1036 
1037  if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
1038  conf->open_file_cache = NULL;
1039  }
1040  }
1041 
1042  if (conf->logs || conf->off) {
1043  return NGX_CONF_OK;
1044  }
1045 
1046  conf->logs = prev->logs;
1047  conf->off = prev->off;
1048 
1049  if (conf->logs || conf->off) {
1050  return NGX_CONF_OK;
1051  }
1052 
1053  conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
1054  if (conf->logs == NULL) {
1055  return NGX_CONF_ERROR;
1056  }
1057 
1058  log = ngx_array_push(conf->logs);
1059  if (log == NULL) {
1060  return NGX_CONF_ERROR;
1061  }
1062 
1063  log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log);
1064  if (log->file == NULL) {
1065  return NGX_CONF_ERROR;
1066  }
1067 
1068  log->script = NULL;
1069  log->disk_full_time = 0;
1070  log->error_log_time = 0;
1071 
1072  lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
1073  fmt = lmcf->formats.elts;
1074 
1075  /* the default "combined" format */
1076  log->format = &fmt[0];
1077  lmcf->combined_used = 1;
1078 
1079  return NGX_CONF_OK;
1080 }
1081 
1082 
1083 static char *
1084 ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1085 {
1086  ngx_http_log_loc_conf_t *llcf = conf;
1087 
1088  ssize_t size;
1089  ngx_int_t gzip;
1090  ngx_uint_t i, n;
1091  ngx_msec_t flush;
1092  ngx_str_t *value, name, s;
1093  ngx_http_log_t *log;
1095  ngx_http_log_fmt_t *fmt;
1098 
1099  value = cf->args->elts;
1100 
1101  if (ngx_strcmp(value[1].data, "off") == 0) {
1102  llcf->off = 1;
1103  if (cf->args->nelts == 2) {
1104  return NGX_CONF_OK;
1105  }
1106 
1108  "invalid parameter \"%V\"", &value[2]);
1109  return NGX_CONF_ERROR;
1110  }
1111 
1112  if (llcf->logs == NULL) {
1113  llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
1114  if (llcf->logs == NULL) {
1115  return NGX_CONF_ERROR;
1116  }
1117  }
1118 
1119  lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
1120 
1121  log = ngx_array_push(llcf->logs);
1122  if (log == NULL) {
1123  return NGX_CONF_ERROR;
1124  }
1125 
1126  ngx_memzero(log, sizeof(ngx_http_log_t));
1127 
1128  n = ngx_http_script_variables_count(&value[1]);
1129 
1130  if (n == 0) {
1131  log->file = ngx_conf_open_file(cf->cycle, &value[1]);
1132  if (log->file == NULL) {
1133  return NGX_CONF_ERROR;
1134  }
1135 
1136  } else {
1137  if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
1138  return NGX_CONF_ERROR;
1139  }
1140 
1141  log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t));
1142  if (log->script == NULL) {
1143  return NGX_CONF_ERROR;
1144  }
1145 
1146  ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1147 
1148  sc.cf = cf;
1149  sc.source = &value[1];
1150  sc.lengths = &log->script->lengths;
1151  sc.values = &log->script->values;
1152  sc.variables = n;
1153  sc.complete_lengths = 1;
1154  sc.complete_values = 1;
1155 
1156  if (ngx_http_script_compile(&sc) != NGX_OK) {
1157  return NGX_CONF_ERROR;
1158  }
1159  }
1160 
1161  if (cf->args->nelts >= 3) {
1162  name = value[2];
1163 
1164  if (ngx_strcmp(name.data, "combined") == 0) {
1165  lmcf->combined_used = 1;
1166  }
1167 
1168  } else {
1169  ngx_str_set(&name, "combined");
1170  lmcf->combined_used = 1;
1171  }
1172 
1173  fmt = lmcf->formats.elts;
1174  for (i = 0; i < lmcf->formats.nelts; i++) {
1175  if (fmt[i].name.len == name.len
1176  && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
1177  {
1178  log->format = &fmt[i];
1179  break;
1180  }
1181  }
1182 
1183  if (log->format == NULL) {
1185  "unknown log format \"%V\"", &name);
1186  return NGX_CONF_ERROR;
1187  }
1188 
1189  size = 0;
1190  flush = 0;
1191  gzip = 0;
1192 
1193  for (i = 3; i < cf->args->nelts; i++) {
1194 
1195  if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
1196  s.len = value[i].len - 7;
1197  s.data = value[i].data + 7;
1198 
1199  size = ngx_parse_size(&s);
1200 
1201  if (size == NGX_ERROR || size == 0) {
1203  "invalid buffer size \"%V\"", &s);
1204  return NGX_CONF_ERROR;
1205  }
1206 
1207  continue;
1208  }
1209 
1210  if (ngx_strncmp(value[i].data, "flush=", 6) == 0) {
1211  s.len = value[i].len - 6;
1212  s.data = value[i].data + 6;
1213 
1214  flush = ngx_parse_time(&s, 0);
1215 
1216  if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) {
1218  "invalid flush time \"%V\"", &s);
1219  return NGX_CONF_ERROR;
1220  }
1221 
1222  continue;
1223  }
1224 
1225  if (ngx_strncmp(value[i].data, "gzip", 4) == 0
1226  && (value[i].len == 4 || value[i].data[4] == '='))
1227  {
1228 #if (NGX_ZLIB)
1229  if (size == 0) {
1230  size = 64 * 1024;
1231  }
1232 
1233  if (value[i].len == 4) {
1234  gzip = Z_BEST_SPEED;
1235  continue;
1236  }
1237 
1238  s.len = value[i].len - 5;
1239  s.data = value[i].data + 5;
1240 
1241  gzip = ngx_atoi(s.data, s.len);
1242 
1243  if (gzip < 1 || gzip > 9) {
1245  "invalid compression level \"%V\"", &s);
1246  return NGX_CONF_ERROR;
1247  }
1248 
1249  continue;
1250 
1251 #else
1253  "nginx was built without zlib support");
1254  return NGX_CONF_ERROR;
1255 #endif
1256  }
1257 
1259  "invalid parameter \"%V\"", &value[i]);
1260  return NGX_CONF_ERROR;
1261  }
1262 
1263  if (flush && size == 0) {
1265  "no buffer is defined for access_log \"%V\"",
1266  &value[1]);
1267  return NGX_CONF_ERROR;
1268  }
1269 
1270  if (size) {
1271 
1272  if (log->script) {
1274  "buffered logs cannot have variables in name");
1275  return NGX_CONF_ERROR;
1276  }
1277 
1278  if (log->file->data) {
1279  buffer = log->file->data;
1280 
1281  if (buffer->last - buffer->start != size
1282  || buffer->flush != flush
1283  || buffer->gzip != gzip)
1284  {
1286  "access_log \"%V\" already defined "
1287  "with conflicting parameters",
1288  &value[1]);
1289  return NGX_CONF_ERROR;
1290  }
1291 
1292  return NGX_CONF_OK;
1293  }
1294 
1295  buffer = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_buf_t));
1296  if (buffer == NULL) {
1297  return NGX_CONF_ERROR;
1298  }
1299 
1300  buffer->start = ngx_pnalloc(cf->pool, size);
1301  if (buffer->start == NULL) {
1302  return NGX_CONF_ERROR;
1303  }
1304 
1305  buffer->pos = buffer->start;
1306  buffer->last = buffer->start + size;
1307 
1308  if (flush) {
1309  buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
1310  if (buffer->event == NULL) {
1311  return NGX_CONF_ERROR;
1312  }
1313 
1314  buffer->event->data = log->file;
1315  buffer->event->handler = ngx_http_log_flush_handler;
1316  buffer->event->log = &cf->cycle->new_log;
1317 
1318  buffer->flush = flush;
1319  }
1320 
1321  buffer->gzip = gzip;
1322 
1323  log->file->flush = ngx_http_log_flush;
1324  log->file->data = buffer;
1325  }
1326 
1327  return NGX_CONF_OK;
1328 }
1329 
1330 
1331 static char *
1332 ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1333 {
1334  ngx_http_log_main_conf_t *lmcf = conf;
1335 
1336  ngx_str_t *value;
1337  ngx_uint_t i;
1338  ngx_http_log_fmt_t *fmt;
1339 
1340  if (cf->cmd_type != NGX_HTTP_MAIN_CONF) {
1342  "the \"log_format\" directive may be used "
1343  "only on \"http\" level");
1344  }
1345 
1346  value = cf->args->elts;
1347 
1348  fmt = lmcf->formats.elts;
1349  for (i = 0; i < lmcf->formats.nelts; i++) {
1350  if (fmt[i].name.len == value[1].len
1351  && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
1352  {
1354  "duplicate \"log_format\" name \"%V\"",
1355  &value[1]);
1356  return NGX_CONF_ERROR;
1357  }
1358  }
1359 
1360  fmt = ngx_array_push(&lmcf->formats);
1361  if (fmt == NULL) {
1362  return NGX_CONF_ERROR;
1363  }
1364 
1365  fmt->name = value[1];
1366 
1367  fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
1368  if (fmt->flushes == NULL) {
1369  return NGX_CONF_ERROR;
1370  }
1371 
1372  fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
1373  if (fmt->ops == NULL) {
1374  return NGX_CONF_ERROR;
1375  }
1376 
1377  return ngx_http_log_compile_format(cf, fmt->flushes, fmt->ops, cf->args, 2);
1378 }
1379 
1380 
1381 static char *
1382 ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
1383  ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
1384 {
1385  u_char *data, *p, ch;
1386  size_t i, len;
1387  ngx_str_t *value, var;
1388  ngx_int_t *flush;
1389  ngx_uint_t bracket;
1390  ngx_http_log_op_t *op;
1391  ngx_http_log_var_t *v;
1392 
1393  value = args->elts;
1394 
1395  for ( /* void */ ; s < args->nelts; s++) {
1396 
1397  i = 0;
1398 
1399  while (i < value[s].len) {
1400 
1401  op = ngx_array_push(ops);
1402  if (op == NULL) {
1403  return NGX_CONF_ERROR;
1404  }
1405 
1406  data = &value[s].data[i];
1407 
1408  if (value[s].data[i] == '$') {
1409 
1410  if (++i == value[s].len) {
1411  goto invalid;
1412  }
1413 
1414  if (value[s].data[i] == '{') {
1415  bracket = 1;
1416 
1417  if (++i == value[s].len) {
1418  goto invalid;
1419  }
1420 
1421  var.data = &value[s].data[i];
1422 
1423  } else {
1424  bracket = 0;
1425  var.data = &value[s].data[i];
1426  }
1427 
1428  for (var.len = 0; i < value[s].len; i++, var.len++) {
1429  ch = value[s].data[i];
1430 
1431  if (ch == '}' && bracket) {
1432  i++;
1433  bracket = 0;
1434  break;
1435  }
1436 
1437  if ((ch >= 'A' && ch <= 'Z')
1438  || (ch >= 'a' && ch <= 'z')
1439  || (ch >= '0' && ch <= '9')
1440  || ch == '_')
1441  {
1442  continue;
1443  }
1444 
1445  break;
1446  }
1447 
1448  if (bracket) {
1450  "the closing bracket in \"%V\" "
1451  "variable is missing", &var);
1452  return NGX_CONF_ERROR;
1453  }
1454 
1455  if (var.len == 0) {
1456  goto invalid;
1457  }
1458 
1459  for (v = ngx_http_log_vars; v->name.len; v++) {
1460 
1461  if (v->name.len == var.len
1462  && ngx_strncmp(v->name.data, var.data, var.len) == 0)
1463  {
1464  op->len = v->len;
1465  op->getlen = NULL;
1466  op->run = v->run;
1467  op->data = 0;
1468 
1469  goto found;
1470  }
1471  }
1472 
1473  if (ngx_http_log_variable_compile(cf, op, &var) != NGX_OK) {
1474  return NGX_CONF_ERROR;
1475  }
1476 
1477  if (flushes) {
1478 
1479  flush = ngx_array_push(flushes);
1480  if (flush == NULL) {
1481  return NGX_CONF_ERROR;
1482  }
1483 
1484  *flush = op->data; /* variable index */
1485  }
1486 
1487  found:
1488 
1489  continue;
1490  }
1491 
1492  i++;
1493 
1494  while (i < value[s].len && value[s].data[i] != '$') {
1495  i++;
1496  }
1497 
1498  len = &value[s].data[i] - data;
1499 
1500  if (len) {
1501 
1502  op->len = len;
1503  op->getlen = NULL;
1504 
1505  if (len <= sizeof(uintptr_t)) {
1506  op->run = ngx_http_log_copy_short;
1507  op->data = 0;
1508 
1509  while (len--) {
1510  op->data <<= 8;
1511  op->data |= data[len];
1512  }
1513 
1514  } else {
1515  op->run = ngx_http_log_copy_long;
1516 
1517  p = ngx_pnalloc(cf->pool, len);
1518  if (p == NULL) {
1519  return NGX_CONF_ERROR;
1520  }
1521 
1522  ngx_memcpy(p, data, len);
1523  op->data = (uintptr_t) p;
1524  }
1525  }
1526  }
1527  }
1528 
1529  return NGX_CONF_OK;
1530 
1531 invalid:
1532 
1533  ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);
1534 
1535  return NGX_CONF_ERROR;
1536 }
1537 
1538 
1539 static char *
1540 ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1541 {
1542  ngx_http_log_loc_conf_t *llcf = conf;
1543 
1544  time_t inactive, valid;
1545  ngx_str_t *value, s;
1546  ngx_int_t max, min_uses;
1547  ngx_uint_t i;
1548 
1549  if (llcf->open_file_cache != NGX_CONF_UNSET_PTR) {
1550  return "is duplicate";
1551  }
1552 
1553  value = cf->args->elts;
1554 
1555  max = 0;
1556  inactive = 10;
1557  valid = 60;
1558  min_uses = 1;
1559 
1560  for (i = 1; i < cf->args->nelts; i++) {
1561 
1562  if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
1563 
1564  max = ngx_atoi(value[i].data + 4, value[i].len - 4);
1565  if (max == NGX_ERROR) {
1566  goto failed;
1567  }
1568 
1569  continue;
1570  }
1571 
1572  if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
1573 
1574  s.len = value[i].len - 9;
1575  s.data = value[i].data + 9;
1576 
1577  inactive = ngx_parse_time(&s, 1);
1578  if (inactive == (time_t) NGX_ERROR) {
1579  goto failed;
1580  }
1581 
1582  continue;
1583  }
1584 
1585  if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) {
1586 
1587  min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
1588  if (min_uses == NGX_ERROR) {
1589  goto failed;
1590  }
1591 
1592  continue;
1593  }
1594 
1595  if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
1596 
1597  s.len = value[i].len - 6;
1598  s.data = value[i].data + 6;
1599 
1600  valid = ngx_parse_time(&s, 1);
1601  if (valid == (time_t) NGX_ERROR) {
1602  goto failed;
1603  }
1604 
1605  continue;
1606  }
1607 
1608  if (ngx_strcmp(value[i].data, "off") == 0) {
1609 
1610  llcf->open_file_cache = NULL;
1611 
1612  continue;
1613  }
1614 
1615  failed:
1616 
1618  "invalid \"open_log_file_cache\" parameter \"%V\"",
1619  &value[i]);
1620  return NGX_CONF_ERROR;
1621  }
1622 
1623  if (llcf->open_file_cache == NULL) {
1624  return NGX_CONF_OK;
1625  }
1626 
1627  if (max == 0) {
1629  "\"open_log_file_cache\" must have \"max\" parameter");
1630  return NGX_CONF_ERROR;
1631  }
1632 
1633  llcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
1634 
1635  if (llcf->open_file_cache) {
1636 
1637  llcf->open_file_cache_valid = valid;
1638  llcf->open_file_cache_min_uses = min_uses;
1639 
1640  return NGX_CONF_OK;
1641  }
1642 
1643  return NGX_CONF_ERROR;
1644 }
1645 
1646 
1647 static ngx_int_t
1648 ngx_http_log_init(ngx_conf_t *cf)
1649 {
1650  ngx_str_t *value;
1651  ngx_array_t a;
1653  ngx_http_log_fmt_t *fmt;
1656 
1657  lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
1658 
1659  if (lmcf->combined_used) {
1660  if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) {
1661  return NGX_ERROR;
1662  }
1663 
1664  value = ngx_array_push(&a);
1665  if (value == NULL) {
1666  return NGX_ERROR;
1667  }
1668 
1669  *value = ngx_http_combined_fmt;
1670  fmt = lmcf->formats.elts;
1671 
1672  if (ngx_http_log_compile_format(cf, NULL, fmt->ops, &a, 0)
1673  != NGX_CONF_OK)
1674  {
1675  return NGX_ERROR;
1676  }
1677  }
1678 
1680 
1682  if (h == NULL) {
1683  return NGX_ERROR;
1684  }
1685 
1686  *h = ngx_http_log_handler;
1687 
1688  return NGX_OK;
1689 }