1
2 /*
3 * Copyright (C) Igor Sysoev
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
10
11
12 typedef struct ngx_http_log_op_s ngx_http_log_op_t;
13
14 typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf,
15 ngx_http_log_op_t *op);
16
17 typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r,
18 uintptr_t data);
19
20
21 struct ngx_http_log_op_s {
22 size_t len;
23 ngx_http_log_op_getlen_pt getlen;
24 ngx_http_log_op_run_pt run;
25 uintptr_t data;
26 };
27
28
29 typedef struct {
30 ngx_str_t name;
31 ngx_array_t *flushes;
32 ngx_array_t *ops; /* array of ngx_http_log_op_t */
33 } ngx_http_log_fmt_t;
34
35
36 typedef struct {
37 ngx_array_t formats; /* array of ngx_http_log_fmt_t */
38 ngx_uint_t combined_used; /* unsigned combined_used:1 */
39 } ngx_http_log_main_conf_t;
40
41
42 typedef struct {
43 ngx_array_t *lengths;
44 ngx_array_t *values;
45 } ngx_http_log_script_t;
46
47
48 typedef struct {
49 ngx_open_file_t *file;
50 ngx_http_log_script_t *script;
51 time_t disk_full_time;
52 time_t error_log_time;
53 ngx_http_log_fmt_t *format;
54 } ngx_http_log_t;
55
56
57 typedef struct {
58 ngx_array_t *logs; /* array of ngx_http_log_t */
59
60 ngx_open_file_cache_t *open_file_cache;
61 time_t open_file_cache_valid;
62 ngx_uint_t open_file_cache_min_uses;
63
64 ngx_uint_t off; /* unsigned off:1 */
65 } ngx_http_log_loc_conf_t;
66
67
68 typedef struct {
69 ngx_str_t name;
70 size_t len;
71 ngx_http_log_op_run_pt run;
72 } ngx_http_log_var_t;
73
74
75 static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
76 u_char *buf, size_t len);
77 static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
78 ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len);
79
80 static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf,
81 ngx_http_log_op_t *op);
82 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
83 ngx_http_log_op_t *op);
84 static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
85 ngx_http_log_op_t *op);
86 static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
87 ngx_http_log_op_t *op);
88 static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
89 ngx_http_log_op_t *op);
90 static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf,
91 ngx_http_log_op_t *op);
92 static u_char *ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
93 ngx_http_log_op_t *op);
94 static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r,
95 u_char *buf, ngx_http_log_op_t *op);
96 static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
97 ngx_http_log_op_t *op);
98
99 static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
100 ngx_http_log_op_t *op, ngx_str_t *value);
101 static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
102 uintptr_t data);
103 static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
104 ngx_http_log_op_t *op);
105 static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size);
106
107
108 static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
109 static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf);
110 static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
111 void *child);
112 static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
113 void *conf);
114 static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
115 void *conf);
116 static char *ngx_http_log_compile_format(ngx_conf_t *cf,
117 ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
118 static char *ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
119 void *conf);
120 static ngx_int_t ngx_http_log_init(ngx_conf_t *cf);
121
122
123 static ngx_command_t ngx_http_log_commands[] = {
124
125 { ngx_string("log_format"),
126 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
127 ngx_http_log_set_format,
128 NGX_HTTP_MAIN_CONF_OFFSET,
129 0,
130 NULL },
131
132 { ngx_string("access_log"),
133 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
134 |NGX_HTTP_LMT_CONF|NGX_CONF_TAKE123,
135 ngx_http_log_set_log,
136 NGX_HTTP_LOC_CONF_OFFSET,
137 0,
138 NULL },
139
140 { ngx_string("open_log_file_cache"),
141 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
142 ngx_http_log_open_file_cache,
143 NGX_HTTP_LOC_CONF_OFFSET,
144 0,
145 NULL },
146
147 ngx_null_command
148 };
149
150
151 static ngx_http_module_t ngx_http_log_module_ctx = {
152 NULL, /* preconfiguration */
153 ngx_http_log_init, /* postconfiguration */
154
155 ngx_http_log_create_main_conf, /* create main configuration */
156 NULL, /* init main configuration */
157
158 NULL, /* create server configuration */
159 NULL, /* merge server configuration */
160
161 ngx_http_log_create_loc_conf, /* create location configration */
162 ngx_http_log_merge_loc_conf /* merge location configration */
163 };
164
165
166 ngx_module_t ngx_http_log_module = {
167 NGX_MODULE_V1,
168 &ngx_http_log_module_ctx, /* module context */
169 ngx_http_log_commands, /* module directives */
170 NGX_HTTP_MODULE, /* module type */
171 NULL, /* init master */
172 NULL, /* init module */
173 NULL, /* init process */
174 NULL, /* init thread */
175 NULL, /* exit thread */
176 NULL, /* exit process */
177 NULL, /* exit master */
178 NGX_MODULE_V1_PADDING
179 };
180
181
182 static ngx_str_t ngx_http_access_log = ngx_string(NGX_HTTP_LOG_PATH);
183
184
185 static ngx_str_t ngx_http_combined_fmt =
186 ngx_string("$remote_addr - $remote_user [$time_local] "
187 "\"$request\" $status $body_bytes_sent "
188 "\"$http_referer\" \"$http_user_agent\"");
189
190
191 static ngx_http_log_var_t ngx_http_log_vars[] = {
192 { ngx_string("connection"), NGX_ATOMIC_T_LEN, ngx_http_log_connection },
193 { ngx_string("pipe"), 1, ngx_http_log_pipe },
194 { ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1,
195 ngx_http_log_time },
196 { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec },
197 { ngx_string("request_time"), NGX_TIME_T_LEN + 4,
198 ngx_http_log_request_time },
199 { ngx_string("status"), 3, ngx_http_log_status },
200 { ngx_string("bytes_sent"), NGX_OFF_T_LEN, ngx_http_log_bytes_sent },
201 { ngx_string("body_bytes_sent"), NGX_OFF_T_LEN,
202 ngx_http_log_body_bytes_sent },
203 { ngx_string("apache_bytes_sent"), NGX_OFF_T_LEN,
204 ngx_http_log_body_bytes_sent },
205 { ngx_string("request_length"), NGX_SIZE_T_LEN,
206 ngx_http_log_request_length },
207
208 { ngx_null_string, 0, NULL }
209 };
210
211
212 ngx_int_t
213 ngx_http_log_handler(ngx_http_request_t *r)
214 {
215 u_char *line, *p;
216 size_t len;
217 ngx_uint_t i, l;
218 ngx_http_log_t *log;
219 ngx_open_file_t *file;
220 ngx_http_log_op_t *op;
221 ngx_http_log_loc_conf_t *lcf;
222
223 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
224 "http log handler");
225
226 lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
227
228 if (lcf->off) {
229 return NGX_OK;
230 }
231
232 log = lcf->logs->elts;
233 for (l = 0; l < lcf->logs->nelts; l++) {
234
235 if (ngx_time() == log[l].disk_full_time) {
236
237 /*
238 * on FreeBSD writing to a full filesystem with enabled softupdates
239 * may block process for much longer time than writing to non-full
240 * filesystem, so we skip writing to a log for one second
241 */
242
243 continue;
244 }
245
246 ngx_http_script_flush_no_cacheable_variables(r, log[l].format->flushes);
247
248 len = 0;
249 op = log[l].format->ops->elts;
250 for (i = 0; i < log[l].format->ops->nelts; i++) {
251 if (op[i].len == 0) {
252 len += op[i].getlen(r, op[i].data);
253
254 } else {
255 len += op[i].len;
256 }
257 }
258
259 len += NGX_LINEFEED_SIZE;
260
261 file = log[l].file;
262
263 if (file && file->buffer) {
264
265 if (len > (size_t) (file->last - file->pos)) {
266
267 ngx_http_log_write(r, &log[l], file->buffer,
268 file->pos - file->buffer);
269
270 file->pos = file->buffer;
271 }
272
273 if (len <= (size_t) (file->last - file->pos)) {
274
275 p = file->pos;
276
277 for (i = 0; i < log[l].format->ops->nelts; i++) {
278 p = op[i].run(r, p, &op[i]);
279 }
280
281 ngx_linefeed(p);
282
283 file->pos = p;
284
285 continue;
286 }
287 }
288
289 line = ngx_pnalloc(r->pool, len);
290 if (line == NULL) {
291 return NGX_ERROR;
292 }
293
294 p = line;
295
296 for (i = 0; i < log[l].format->ops->nelts; i++) {
297 p = op[i].run(r, p, &op[i]);
298 }
299
300 ngx_linefeed(p);
301
302 ngx_http_log_write(r, &log[l], line, p - line);
303 }
304
305 return NGX_OK;
306 }
307
308
309 static void
310 ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
311 size_t len)
312 {
313 u_char *name;
314 time_t now;
315 ssize_t n;
316 ngx_err_t err;
317
318 if (log->script == NULL) {
319 name = log->file->name.data;
320 n = ngx_write_fd(log->file->fd, buf, len);
321
322 } else {
323 name = NULL;
324 n = ngx_http_log_script_write(r, log->script, &name, buf, len);
325 }
326
327 if (n == (ssize_t) len) {
328 return;
329 }
330
331 now = ngx_time();
332
333 if (n == -1) {
334 err = ngx_errno;
335
336 if (err == NGX_ENOSPC) {
337 log->disk_full_time = now;
338 }
339
340 if (now - log->error_log_time > 59) {
341 ngx_log_error(NGX_LOG_ALERT, r->connection->log, err,
342 ngx_write_fd_n " to \"%s\" failed", name);
343
344 log->error_log_time = now;
345 }
346
347 return;
348 }
349
350 if (now - log->error_log_time > 59) {
351 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
352 ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
353 name, n, len);
354
355 log->error_log_time = now;
356 }
357 }
358
359
360 static ssize_t
361 ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
362 u_char **name, u_char *buf, size_t len)
363 {
364 size_t root;
365 ssize_t n;
366 ngx_str_t log, path;
367 ngx_open_file_info_t of;
368 ngx_http_log_loc_conf_t *llcf;
369 ngx_http_core_loc_conf_t *clcf;
370
371 if (!r->root_tested) {
372
373 /* test root directory existance */
374
375 if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
376 /* simulate successfull logging */
377 return len;
378 }
379
380 path.data[root] = '\0';
381
382 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
383
384 ngx_memzero(&of, sizeof(ngx_open_file_info_t));
385
386 of.valid = clcf->open_file_cache_valid;
387 of.min_uses = clcf->open_file_cache_min_uses;
388 of.test_dir = 1;
389 of.test_only = 1;
390 of.errors = clcf->open_file_cache_errors;
391 of.events = clcf->open_file_cache_events;
392
393 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
394 != NGX_OK)
395 {
396 if (of.err == 0) {
397 /* simulate successfull logging */
398 return len;
399 }
400
401 ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err,
402 "testing \"%s\" existence failed", path.data);
403
404 /* simulate successfull logging */
405 return len;
406 }
407
408 if (!of.is_dir) {
409 ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ENOTDIR,
410 "testing \"%s\" existence failed", path.data);
411
412 /* simulate successfull logging */
413 return len;
414 }
415 }
416
417 if (ngx_http_script_run(r, &log, script->lengths->elts, 1,
418 script->values->elts)
419 == NULL)
420 {
421 /* simulate successfull logging */
422 return len;
423 }
424
425 log.data[log.len - 1] = '\0';
426 *name = log.data;
427
428 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
429 "http log \"%s\"", log.data);
430
431 llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
432
433 ngx_memzero(&of, sizeof(ngx_open_file_info_t));
434
435 of.log = 1;
436 of.valid = llcf->open_file_cache_valid;
437 of.min_uses = llcf->open_file_cache_min_uses;
438 of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
439
440 if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool)
441 != NGX_OK)
442 {
443 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
444 "%s \"%s\" failed", of.failed, log.data);
445 /* simulate successfull logging */
446 return len;
447 }
448
449 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
450 "http log #%d", of.fd);
451
452 n = ngx_write_fd(of.fd, buf, len);
453
454 return n;
455 }
456
457
458 static u_char *
459 ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
460 ngx_http_log_op_t *op)
461 {
462 size_t len;
463 uintptr_t data;
464
465 len = op->len;
466 data = op->data;
467
468 while (len--) {
469 *buf++ = (u_char) (data & 0xff);
470 data >>= 8;
471 }
472
473 return buf;
474 }
475
476
477 static u_char *
478 ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf,
479 ngx_http_log_op_t *op)
480 {
481 return ngx_cpymem(buf, (u_char *) op->data, op->len);
482 }
483
484
485 static u_char *
486 ngx_http_log_connection(ngx_http_request_t *r, u_char *buf,
487 ngx_http_log_op_t *op)
488 {
489 return ngx_sprintf(buf, "%ui", r->connection->number);
490 }
491
492
493 static u_char *
494 ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
495 {
496 if (r->pipeline) {
497 *buf = 'p';
498 } else {
499 *buf = '.';
500 }
501
502 return buf + 1;
503 }
504
505
506 static u_char *
507 ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
508 {
509 return ngx_cpymem(buf, ngx_cached_http_log_time.data,
510 ngx_cached_http_log_time.len);
511 }
512
513
514 static u_char *
515 ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
516 {
517 ngx_time_t *tp;
518
519 tp = ngx_timeofday();
520
521 return ngx_sprintf(buf, "%T.%03M", tp->sec, tp->msec);
522 }
523
524
525 static u_char *
526 ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
527 ngx_http_log_op_t *op)
528 {
529 ngx_time_t *tp;
530 ngx_msec_int_t ms;
531
532 tp = ngx_timeofday();
533
534 ms = (ngx_msec_int_t)
535 ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
536 ms = (ms >= 0) ? ms : 0;
537
538 return ngx_sprintf(buf, "%T.%03M", ms / 1000, ms % 1000);
539 }
540
541
542 static u_char *
543 ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
544 {
545 return ngx_sprintf(buf, "%ui",
546 r->err_status ? r->err_status : r->headers_out.status);
547 }
548
549
550 static u_char *
551 ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
552 ngx_http_log_op_t *op)
553 {
554 return ngx_sprintf(buf, "%O", r->connection->sent);
555 }
556
557
558 /*
559 * although there is a real $body_bytes_sent variable,
560 * this log operation code function is more optimized for logging
561 */
562
563 static u_char *
564 ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
565 ngx_http_log_op_t *op)
566 {
567 off_t length;
568
569 length = r->connection->sent - r->header_size;
570
571 if (length > 0) {
572 return ngx_sprintf(buf, "%O", length);
573 }
574
575 *buf = '';
576
577 return buf + 1;
578 }
579
580
581 static u_char *
582 ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
583 ngx_http_log_op_t *op)
584 {
585 return ngx_sprintf(buf, "%O", r->request_length);
586 }
587
588
589 static ngx_int_t
590 ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
591 ngx_str_t *value)
592 {
593 ngx_int_t index;
594
595 index = ngx_http_get_variable_index(cf, value);
596 if (index == NGX_ERROR) {
597 return NGX_ERROR;
598 }
599
600 op->len = 0;
601 op->getlen = ngx_http_log_variable_getlen;
602 op->run = ngx_http_log_variable;
603 op->data = index;
604
605 return NGX_OK;
606 }
607
608
609 static size_t
610 ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data)
611 {
612 uintptr_t len;
613 ngx_http_variable_value_t *value;
614
615 value = ngx_http_get_indexed_variable(r, data);
616
617 if (value == NULL || value->not_found) {
618 return 1;
619 }
620
621 len = ngx_http_log_escape(NULL, value->data, value->len);
622
623 value->escape = len ? 1 : 0;
624
625 return value->len + len * 3;
626 }
627
628
629 static u_char *
630 ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
631 {
632 ngx_http_variable_value_t *value;
633
634 value = ngx_http_get_indexed_variable(r, op->data);
635
636 if (value == NULL || value->not_found) {
637 *buf = '-';
638 return buf + 1;
639 }
640
641 if (value->escape == 0) {
642 return ngx_cpymem(buf, value->data, value->len);
643
644 } else {
645 return (u_char *) ngx_http_log_escape(buf, value->data, value->len);
646 }
647 }
648
649
650 static uintptr_t
651 ngx_http_log_escape(u_char *dst, u_char *src, size_t size)
652 {
653 ngx_uint_t i, n;
654 static u_char hex[] = "0123456789ABCDEF";
655
656 static uint32_t escape[] = {
657 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
658
659 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
660 0x00000004, /* 0000 0000 0000 0000 0000 0000 0000 0100 */
661
662 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
663 0x10000000, /* 0001 0000 0000 0000 0000 0000 0000 0000 */
664
665 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
666 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
667
668 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
669 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
670 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
671 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
672 };
673
674
675 if (dst == NULL) {
676
677 /* find the number of the characters to be escaped */
678
679 n = 0;
680
681 for (i = 0; i < size; i++) {
682 if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
683 n++;
684 }
685 src++;
686 }
687
688 return (uintptr_t) n;
689 }
690
691 for (i = 0; i < size; i++) {
692 if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
693 *dst++ = '\\';
694 *dst++ = 'x';
695 *dst++ = hex[*src >> 4];
696 *dst++ = hex[*src & 0xf];
697 src++;
698
699 } else {
700 *dst++ = *src++;
701 }
702 }
703
704 return (uintptr_t) dst;
705 }
706
707
708 static void *
709 ngx_http_log_create_main_conf(ngx_conf_t *cf)
710 {
711 ngx_http_log_main_conf_t *conf;
712
713 ngx_http_log_fmt_t *fmt;
714
715 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
716 if (conf == NULL) {
717 return NULL;
718 }
719
720 if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t))
721 != NGX_OK)
722 {
723 return NULL;
724 }
725
726 fmt = ngx_array_push(&conf->formats);
727 if (fmt == NULL) {
728 return NULL;
729 }
730
731 fmt->name.len = sizeof("combined") - 1;
732 fmt->name.data = (u_char *) "combined";
733
734 fmt->flushes = NULL;
735
736 fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
737 if (fmt->ops == NULL) {
738 return NULL;
739 }
740
741 return conf;
742 }
743
744
745 static void *
746 ngx_http_log_create_loc_conf(ngx_conf_t *cf)
747 {
748 ngx_http_log_loc_conf_t *conf;
749
750 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t));
751 if (conf == NULL) {
752 return NULL;
753 }
754
755 conf->open_file_cache = NGX_CONF_UNSET_PTR;
756
757 return conf;
758 }
759
760
761 static char *
762 ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
763 {
764 ngx_http_log_loc_conf_t *prev = parent;
765 ngx_http_log_loc_conf_t *conf = child;
766
767 ngx_http_log_t *log;
768 ngx_http_log_fmt_t *fmt;
769 ngx_http_log_main_conf_t *lmcf;
770
771 if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
772
773 conf->open_file_cache = prev->open_file_cache;
774 conf->open_file_cache_valid = prev->open_file_cache_valid;
775 conf->open_file_cache_min_uses = prev->open_file_cache_min_uses;
776
777 if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
778 conf->open_file_cache = NULL;
779 }
780 }
781
782 if (conf->logs || conf->off) {
783 return NGX_CONF_OK;
784 }
785
786 conf->logs = prev->logs;
787 conf->off = prev->off;
788
789 if (conf->logs || conf->off) {
790 return NGX_CONF_OK;
791 }
792
793 conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
794 if (conf->logs == NULL) {
795 return NGX_CONF_ERROR;
796 }
797
798 log = ngx_array_push(conf->logs);
799 if (log == NULL) {
800 return NGX_CONF_ERROR;
801 }
802
803 log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log);
804 if (log->file == NULL) {
805 return NGX_CONF_ERROR;
806 }
807
808 log->script = NULL;
809 log->disk_full_time = 0;
810 log->error_log_time = 0;
811
812 lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
813 fmt = lmcf->formats.elts;
814
815 /* the default "combined" format */
816 log->format = &fmt[0];
817 lmcf->combined_used = 1;
818
819 return NGX_CONF_OK;
820 }
821
822
823 static char *
824 ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
825 {
826 ngx_http_log_loc_conf_t *llcf = conf;
827
828 ssize_t buf;
829 ngx_uint_t i, n;
830 ngx_str_t *value, name;
831 ngx_http_log_t *log;
832 ngx_http_log_fmt_t *fmt;
833 ngx_http_log_main_conf_t *lmcf;
834 ngx_http_script_compile_t sc;
835
836 value = cf->args->elts;
837
838 if (ngx_strcmp(value[1].data, "off") == 0) {
839 llcf->off = 1;
840 if (cf->args->nelts == 2) {
841 return NGX_CONF_OK;
842 }
843
844 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
845 "invalid parameter \"%V\"", &value[2]);
846 return NGX_CONF_ERROR;
847 }
848
849 if (llcf->logs == NULL) {
850 llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
851 if (llcf->logs == NULL) {
852 return NGX_CONF_ERROR;
853 }
854 }
855
856 lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
857
858 log = ngx_array_push(llcf->logs);
859 if (log == NULL) {
860 return NGX_CONF_ERROR;
861 }
862
863 ngx_memzero(log, sizeof(ngx_http_log_t));
864
865 n = ngx_http_script_variables_count(&value[1]);
866
867 if (n == 0) {
868 log->file = ngx_conf_open_file(cf->cycle, &value[1]);
869 if (log->file == NULL) {
870 return NGX_CONF_ERROR;
871 }
872
873 } else {
874 if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
875 return NGX_CONF_ERROR;
876 }
877
878 log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t));
879 if (log->script == NULL) {
880 return NGX_CONF_ERROR;
881 }
882
883 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
884
885 sc.cf = cf;
886 sc.source = &value[1];
887 sc.lengths = &log->script->lengths;
888 sc.values = &log->script->values;
889 sc.variables = n;
890 sc.complete_lengths = 1;
891 sc.complete_values = 1;
892
893 if (ngx_http_script_compile(&sc) != NGX_OK) {
894 return NGX_CONF_ERROR;
895 }
896 }
897
898 if (cf->args->nelts >= 3) {
899 name = value[2];
900
901 if (ngx_strcmp(name.data, "combined") == 0) {
902 lmcf->combined_used = 1;
903 }
904
905 } else {
906 name.len = sizeof("combined") - 1;
907 name.data = (u_char *) "combined";
908 lmcf->combined_used = 1;
909 }
910
911 fmt = lmcf->formats.elts;
912 for (i = 0; i < lmcf->formats.nelts; i++) {
913 if (fmt[i].name.len == name.len
914 && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
915 {
916 log->format = &fmt[i];
917 goto buffer;
918 }
919 }
920
921 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
922 "unknown log format \"%V\"", &name);
923 return NGX_CONF_ERROR;
924
925 buffer:
926
927 if (cf->args->nelts == 4) {
928 if (ngx_strncmp(value[3].data, "buffer=", 7) != 0) {
929 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
930 "invalid parameter \"%V\"", &value[3]);
931 return NGX_CONF_ERROR;
932 }
933
934 if (log->script) {
935 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
936 "buffered logs can not have variables in name");
937 return NGX_CONF_ERROR;
938 }
939
940 name.len = value[3].len - 7;
941 name.data = value[3].data + 7;
942
943 buf = ngx_parse_size(&name);
944
945 if (buf == NGX_ERROR) {
946 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
947 "invalid parameter \"%V\"", &value[3]);
948 return NGX_CONF_ERROR;
949 }
950
951 if (log->file->buffer && log->file->last - log->file->pos != buf) {
952 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
953 "access_log \"%V\" already defined "
954 "with different buffer size", &value[1]);
955 return NGX_CONF_ERROR;
956 }
957
958 log->file->buffer = ngx_palloc(cf->pool, buf);
959 if (log->file->buffer == NULL) {
960 return NGX_CONF_ERROR;
961 }
962
963 log->file->pos = log->file->buffer;
964 log->file->last = log->file->buffer + buf;
965 }
966
967 return NGX_CONF_OK;
968 }
969
970
971 static char *
972 ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
973 {
974 ngx_http_log_main_conf_t *lmcf = conf;
975
976 ngx_str_t *value;
977 ngx_uint_t i;
978 ngx_http_log_fmt_t *fmt;
979
980 value = cf->args->elts;
981
982 fmt = lmcf->formats.elts;
983 for (i = 0; i < lmcf->formats.nelts; i++) {
984 if (fmt[i].name.len == value[1].len
985 && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
986 {
987 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
988 "duplicate \"log_format\" name \"%V\"",
989 &value[1]);
990 return NGX_CONF_ERROR;
991 }
992 }
993
994 fmt = ngx_array_push(&lmcf->formats);
995 if (fmt == NULL) {
996 return NGX_CONF_ERROR;
997 }
998
999 fmt->name = value[1];
1000
1001 fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
1002 if (fmt->flushes == NULL) {
1003 return NGX_CONF_ERROR;
1004 }
1005
1006 fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
1007 if (fmt->ops == NULL) {
1008 return NGX_CONF_ERROR;
1009 }
1010
1011 return ngx_http_log_compile_format(cf, fmt->flushes, fmt->ops, cf->args, 2);
1012 }
1013
1014
1015 static char *
1016 ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
1017 ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
1018 {
1019 u_char *data, *p, ch;
1020 size_t i, len;
1021 ngx_str_t *value, var;
1022 ngx_int_t *flush;
1023 ngx_uint_t bracket;
1024 ngx_http_log_op_t *op;
1025 ngx_http_log_var_t *v;
1026
1027 value = args->elts;
1028
1029 for ( /* void */ ; s < args->nelts; s++) {
1030
1031 for (i = 0; i < value[s].len; i++) {
1032 if (value[s].data[i] != '%') {
1033 continue;
1034 }
1035
1036 ch = value[s].data[i + 1];
1037
1038 if ((ch >= 'A' && ch <= 'Z')
1039 || (ch >= 'a' && ch <= 'z')
1040 || ch == '{')
1041 {
1042 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1043 "the parameters in the \"%%name\" form are not supported, "
1044 "use the \"$variable\" instead");
1045
1046 return NGX_CONF_ERROR;
1047 }
1048 }
1049
1050 i = 0;
1051
1052 while (i < value[s].len) {
1053
1054 op = ngx_array_push(ops);
1055 if (op == NULL) {
1056 return NGX_CONF_ERROR;
1057 }
1058
1059 data = &value[s].data[i];
1060
1061 if (value[s].data[i] == '$') {
1062
1063 if (++i == value[s].len) {
1064 goto invalid;
1065 }
1066
1067 if (value[s].data[i] == '{') {
1068 bracket = 1;
1069
1070 if (++i == value[s].len) {
1071 goto invalid;
1072 }
1073
1074 var.data = &value[s].data[i];
1075
1076 } else {
1077 bracket = 0;
1078 var.data = &value[s].data[i];
1079 }
1080
1081 for (var.len = 0; i < value[s].len; i++, var.len++) {
1082 ch = value[s].data[i];
1083
1084 if (ch == '}' && bracket) {
1085 i++;
1086 bracket = 0;
1087 break;
1088 }
1089
1090 if ((ch >= 'A' && ch <= 'Z')
1091 || (ch >= 'a' && ch <= 'z')
1092 || (ch >= '' && ch <= '9')
1093 || ch == '_')
1094 {
1095 continue;
1096 }
1097
1098 break;
1099 }
1100
1101 if (bracket) {
1102 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1103 "the closing bracket in \"%V\" "
1104 "variable is missing", &var);
1105 return NGX_CONF_ERROR;
1106 }
1107
1108 if (var.len == 0) {
1109 goto invalid;
1110 }
1111
1112 if (ngx_strncmp(var.data, "apache_bytes_sent", 17) == 0) {
1113 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
1114 "use \"$body_bytes_sent\" instead of "
1115 "\"$apache_bytes_sent\"");
1116 }
1117
1118 for (v = ngx_http_log_vars; v->name.len; v++) {
1119
1120 if (v->name.len == var.len
1121 && ngx_strncmp(v->name.data, var.data, var.len) == 0)
1122 {
1123 op->len = v->len;
1124 op->getlen = NULL;
1125 op->run = v->run;
1126 op->data = 0;
1127
1128 goto found;
1129 }
1130 }
1131
1132 if (ngx_http_log_variable_compile(cf, op, &var) != NGX_OK) {
1133 return NGX_CONF_ERROR;
1134 }
1135
1136 if (flushes) {
1137
1138 flush = ngx_array_push(flushes);
1139 if (flush == NULL) {
1140 return NGX_CONF_ERROR;
1141 }
1142
1143 *flush = op->data; /* variable index */
1144 }
1145
1146 found:
1147
1148 continue;
1149 }
1150
1151 i++;
1152
1153 while (i < value[s].len && value[s].data[i] != '$') {
1154 i++;
1155 }
1156
1157 len = &value[s].data[i] - data;
1158
1159 if (len) {
1160
1161 op->len = len;
1162 op->getlen = NULL;
1163
1164 if (len <= sizeof(uintptr_t)) {
1165 op->run = ngx_http_log_copy_short;
1166 op->data = 0;
1167
1168 while (len--) {
1169 op->data <<= 8;
1170 op->data |= data[len];
1171 }
1172
1173 } else {
1174 op->run = ngx_http_log_copy_long;
1175
1176 p = ngx_pnalloc(cf->pool, len);
1177 if (p == NULL) {
1178 return NGX_CONF_ERROR;
1179 }
1180
1181 ngx_memcpy(p, data, len);
1182 op->data = (uintptr_t) p;
1183 }
1184 }
1185 }
1186 }
1187
1188 return NGX_CONF_OK;
1189
1190 invalid:
1191
1192 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);
1193
1194 return NGX_CONF_ERROR;
1195 }
1196
1197
1198 static char *
1199 ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1200 {
1201 ngx_http_log_loc_conf_t *llcf = conf;
1202
1203 time_t inactive, valid;
1204 ngx_str_t *value, s;
1205 ngx_int_t max, min_uses;
1206 ngx_uint_t i;
1207
1208 if (llcf->open_file_cache != NGX_CONF_UNSET_PTR) {
1209 return "is duplicate";
1210 }
1211
1212 value = cf->args->elts;
1213
1214 max = 0;
1215 inactive = 10;
1216 valid = 60;
1217 min_uses = 1;
1218
1219 for (i = 1; i < cf->args->nelts; i++) {
1220
1221 if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
1222
1223 max = ngx_atoi(value[i].data + 4, value[i].len - 4);
1224 if (max == NGX_ERROR) {
1225 goto failed;
1226 }
1227
1228 continue;
1229 }
1230
1231 if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
1232
1233 s.len = value[i].len - 9;
1234 s.data = value[i].data + 9;
1235
1236 inactive = ngx_parse_time(&s, 1);
1237 if (inactive < 0) {
1238 goto failed;
1239 }
1240
1241 continue;
1242 }
1243
1244 if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) {
1245
1246 min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
1247 if (min_uses == NGX_ERROR) {
1248 goto failed;
1249 }
1250
1251 continue;
1252 }
1253
1254 if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
1255
1256 s.len = value[i].len - 6;
1257 s.data = value[i].data + 6;
1258
1259 valid = ngx_parse_time(&s, 1);
1260 if (valid < 0) {
1261 goto failed;
1262 }
1263
1264 continue;
1265 }
1266
1267 if (ngx_strcmp(value[i].data, "off") == 0) {
1268
1269 llcf->open_file_cache = NULL;
1270
1271 continue;
1272 }
1273
1274 failed:
1275
1276 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1277 "invalid \"open_log_file_cache\" parameter \"%V\"",
1278 &value[i]);
1279 return NGX_CONF_ERROR;
1280 }
1281
1282 if (llcf->open_file_cache == NULL) {
1283 return NGX_CONF_OK;
1284 }
1285
1286 if (max == 0) {
1287 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1288 "\"open_log_file_cache\" must have \"max\" parameter");
1289 return NGX_CONF_ERROR;
1290 }
1291
1292 llcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
1293
1294 if (llcf->open_file_cache) {
1295
1296 llcf->open_file_cache_valid = valid;
1297 llcf->open_file_cache_min_uses = min_uses;
1298
1299 return NGX_CONF_OK;
1300 }
1301
1302 return NGX_CONF_ERROR;
1303 }
1304
1305
1306 static ngx_int_t
1307 ngx_http_log_init(ngx_conf_t *cf)
1308 {
1309 ngx_str_t *value;
1310 ngx_array_t a;
1311 ngx_http_handler_pt *h;
1312 ngx_http_log_fmt_t *fmt;
1313 ngx_http_log_main_conf_t *lmcf;
1314 ngx_http_core_main_conf_t *cmcf;
1315
1316 lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
1317
1318 if (lmcf->combined_used) {
1319 if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) {
1320 return NGX_ERROR;
1321 }
1322
1323 value = ngx_array_push(&a);
1324 if (value == NULL) {
1325 return NGX_ERROR;
1326 }
1327
1328 *value = ngx_http_combined_fmt;
1329 fmt = lmcf->formats.elts;
1330
1331 if (ngx_http_log_compile_format(cf, NULL, fmt->ops, &a, 0)
1332 != NGX_CONF_OK)
1333 {
1334 return NGX_ERROR;
1335 }
1336 }
1337
1338 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
1339
1340 h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
1341 if (h == NULL) {
1342 return NGX_ERROR;
1343 }
1344
1345 *h = ngx_http_log_handler;
1346
1347 return NGX_OK;
1348 }
1349
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.