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_stream.h>
11
12 #if (NGX_ZLIB)
13 #include <zlib.h>
14 #endif
15
16
17 typedef struct ngx_stream_log_op_s ngx_stream_log_op_t;
18
19 typedef u_char *(*ngx_stream_log_op_run_pt) (ngx_stream_session_t *s,
20 u_char *buf, ngx_stream_log_op_t *op);
21
22 typedef size_t (*ngx_stream_log_op_getlen_pt) (ngx_stream_session_t *s,
23 uintptr_t data);
24
25
26 struct ngx_stream_log_op_s {
27 size_t len;
28 ngx_stream_log_op_getlen_pt getlen;
29 ngx_stream_log_op_run_pt run;
30 uintptr_t data;
31 };
32
33
34 typedef struct {
35 ngx_str_t name;
36 ngx_array_t *flushes;
37 ngx_array_t *ops; /* array of ngx_stream_log_op_t */
38 } ngx_stream_log_fmt_t;
39
40
41 typedef struct {
42 ngx_array_t formats; /* array of ngx_stream_log_fmt_t */
43 } ngx_stream_log_main_conf_t;
44
45
46 typedef struct {
47 u_char *start;
48 u_char *pos;
49 u_char *last;
50
51 ngx_event_t *event;
52 ngx_msec_t flush;
53 ngx_int_t gzip;
54 } ngx_stream_log_buf_t;
55
56
57 typedef struct {
58 ngx_array_t *lengths;
59 ngx_array_t *values;
60 } ngx_stream_log_script_t;
61
62
63 typedef struct {
64 ngx_open_file_t *file;
65 ngx_stream_log_script_t *script;
66 time_t disk_full_time;
67 time_t error_log_time;
68 ngx_syslog_peer_t *syslog_peer;
69 ngx_stream_log_fmt_t *format;
70 ngx_stream_complex_value_t *filter;
71 } ngx_stream_log_t;
72
73
74 typedef struct {
75 ngx_array_t *logs; /* array of ngx_stream_log_t */
76
77 ngx_open_file_cache_t *open_file_cache;
78 time_t open_file_cache_valid;
79 ngx_uint_t open_file_cache_min_uses;
80
81 ngx_uint_t off; /* unsigned off:1 */
82 } ngx_stream_log_srv_conf_t;
83
84
85 typedef struct {
86 ngx_str_t name;
87 size_t len;
88 ngx_stream_log_op_run_pt run;
89 } ngx_stream_log_var_t;
90
91
92 #define NGX_STREAM_LOG_ESCAPE_DEFAULT 0
93 #define NGX_STREAM_LOG_ESCAPE_JSON 1
94 #define NGX_STREAM_LOG_ESCAPE_NONE 2
95
96
97 static void ngx_stream_log_write(ngx_stream_session_t *s, ngx_stream_log_t *log,
98 u_char *buf, size_t len);
99 static ssize_t ngx_stream_log_script_write(ngx_stream_session_t *s,
100 ngx_stream_log_script_t *script, u_char **name, u_char *buf, size_t len);
101
102 #if (NGX_ZLIB)
103 static ssize_t ngx_stream_log_gzip(ngx_fd_t fd, u_char *buf, size_t len,
104 ngx_int_t level, ngx_log_t *log);
105
106 static void *ngx_stream_log_gzip_alloc(void *opaque, u_int items, u_int size);
107 static void ngx_stream_log_gzip_free(void *opaque, void *address);
108 #endif
109
110 static void ngx_stream_log_flush(ngx_open_file_t *file, ngx_log_t *log);
111 static void ngx_stream_log_flush_handler(ngx_event_t *ev);
112
113 static ngx_int_t ngx_stream_log_variable_compile(ngx_conf_t *cf,
114 ngx_stream_log_op_t *op, ngx_str_t *value, ngx_uint_t escape);
115 static size_t ngx_stream_log_variable_getlen(ngx_stream_session_t *s,
116 uintptr_t data);
117 static u_char *ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf,
118 ngx_stream_log_op_t *op);
119 static uintptr_t ngx_stream_log_escape(u_char *dst, u_char *src, size_t size);
120 static size_t ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s,
121 uintptr_t data);
122 static u_char *ngx_stream_log_json_variable(ngx_stream_session_t *s,
123 u_char *buf, ngx_stream_log_op_t *op);
124 static size_t ngx_stream_log_unescaped_variable_getlen(ngx_stream_session_t *s,
125 uintptr_t data);
126 static u_char *ngx_stream_log_unescaped_variable(ngx_stream_session_t *s,
127 u_char *buf, ngx_stream_log_op_t *op);
128
129
130 static void *ngx_stream_log_create_main_conf(ngx_conf_t *cf);
131 static void *ngx_stream_log_create_srv_conf(ngx_conf_t *cf);
132 static char *ngx_stream_log_merge_srv_conf(ngx_conf_t *cf, void *parent,
133 void *child);
134 static char *ngx_stream_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
135 void *conf);
136 static char *ngx_stream_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
137 void *conf);
138 static char *ngx_stream_log_compile_format(ngx_conf_t *cf,
139 ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
140 static char *ngx_stream_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
141 void *conf);
142 static ngx_int_t ngx_stream_log_init(ngx_conf_t *cf);
143
144
145 static ngx_command_t ngx_stream_log_commands[] = {
146
147 { ngx_string("log_format"),
148 NGX_STREAM_MAIN_CONF|NGX_CONF_2MORE,
149 ngx_stream_log_set_format,
150 NGX_STREAM_MAIN_CONF_OFFSET,
151 0,
152 NULL },
153
154 { ngx_string("access_log"),
155 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
156 ngx_stream_log_set_log,
157 NGX_STREAM_SRV_CONF_OFFSET,
158 0,
159 NULL },
160
161 { ngx_string("open_log_file_cache"),
162 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1234,
163 ngx_stream_log_open_file_cache,
164 NGX_STREAM_SRV_CONF_OFFSET,
165 0,
166 NULL },
167
168 ngx_null_command
169 };
170
171
172 static ngx_stream_module_t ngx_stream_log_module_ctx = {
173 NULL, /* preconfiguration */
174 ngx_stream_log_init, /* postconfiguration */
175
176 ngx_stream_log_create_main_conf, /* create main configuration */
177 NULL, /* init main configuration */
178
179 ngx_stream_log_create_srv_conf, /* create server configuration */
180 ngx_stream_log_merge_srv_conf /* merge server configuration */
181 };
182
183
184 ngx_module_t ngx_stream_log_module = {
185 NGX_MODULE_V1,
186 &ngx_stream_log_module_ctx, /* module context */
187 ngx_stream_log_commands, /* module directives */
188 NGX_STREAM_MODULE, /* module type */
189 NULL, /* init master */
190 NULL, /* init module */
191 NULL, /* init process */
192 NULL, /* init thread */
193 NULL, /* exit thread */
194 NULL, /* exit process */
195 NULL, /* exit master */
196 NGX_MODULE_V1_PADDING
197 };
198
199
200 static ngx_int_t
ngx_stream_log_handler(ngx_stream_session_t * s)201 ngx_stream_log_handler(ngx_stream_session_t *s)
202 {
203 u_char *line, *p;
204 size_t len, size;
205 ssize_t n;
206 ngx_str_t val;
207 ngx_uint_t i, l;
208 ngx_stream_log_t *log;
209 ngx_stream_log_op_t *op;
210 ngx_stream_log_buf_t *buffer;
211 ngx_stream_log_srv_conf_t *lscf;
212
213 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
214 "stream log handler");
215
216 lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_log_module);
217
218 if (lscf->off || lscf->logs == NULL) {
219 return NGX_OK;
220 }
221
222 log = lscf->logs->elts;
223 for (l = 0; l < lscf->logs->nelts; l++) {
224
225 if (log[l].filter) {
226 if (ngx_stream_complex_value(s, log[l].filter, &val) != NGX_OK) {
227 return NGX_ERROR;
228 }
229
230 if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) {
231 continue;
232 }
233 }
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_stream_script_flush_no_cacheable_variables(s,
247 log[l].format->flushes);
248
249 len = 0;
250 op = log[l].format->ops->elts;
251 for (i = 0; i < log[l].format->ops->nelts; i++) {
252 if (op[i].len == 0) {
253 len += op[i].getlen(s, op[i].data);
254
255 } else {
256 len += op[i].len;
257 }
258 }
259
260 if (log[l].syslog_peer) {
261
262 /* length of syslog's PRI and HEADER message parts */
263 len += sizeof("<255>Jan 01 00:00:00 ") - 1
264 + ngx_cycle->hostname.len + 1
265 + log[l].syslog_peer->tag.len + 2;
266
267 goto alloc_line;
268 }
269
270 len += NGX_LINEFEED_SIZE;
271
272 buffer = log[l].file ? log[l].file->data : NULL;
273
274 if (buffer) {
275
276 if (len > (size_t) (buffer->last - buffer->pos)) {
277
278 ngx_stream_log_write(s, &log[l], buffer->start,
279 buffer->pos - buffer->start);
280
281 buffer->pos = buffer->start;
282 }
283
284 if (len <= (size_t) (buffer->last - buffer->pos)) {
285
286 p = buffer->pos;
287
288 if (buffer->event && p == buffer->start) {
289 ngx_add_timer(buffer->event, buffer->flush);
290 }
291
292 for (i = 0; i < log[l].format->ops->nelts; i++) {
293 p = op[i].run(s, p, &op[i]);
294 }
295
296 ngx_linefeed(p);
297
298 buffer->pos = p;
299
300 continue;
301 }
302
303 if (buffer->event && buffer->event->timer_set) {
304 ngx_del_timer(buffer->event);
305 }
306 }
307
308 alloc_line:
309
310 line = ngx_pnalloc(s->connection->pool, len);
311 if (line == NULL) {
312 return NGX_ERROR;
313 }
314
315 p = line;
316
317 if (log[l].syslog_peer) {
318 p = ngx_syslog_add_header(log[l].syslog_peer, line);
319 }
320
321 for (i = 0; i < log[l].format->ops->nelts; i++) {
322 p = op[i].run(s, p, &op[i]);
323 }
324
325 if (log[l].syslog_peer) {
326
327 size = p - line;
328
329 n = ngx_syslog_send(log[l].syslog_peer, line, size);
330
331 if (n < 0) {
332 ngx_log_error(NGX_LOG_WARN, s->connection->log, 0,
333 "send() to syslog failed");
334
335 } else if ((size_t) n != size) {
336 ngx_log_error(NGX_LOG_WARN, s->connection->log, 0,
337 "send() to syslog has written only %z of %uz",
338 n, size);
339 }
340
341 continue;
342 }
343
344 ngx_linefeed(p);
345
346 ngx_stream_log_write(s, &log[l], line, p - line);
347 }
348
349 return NGX_OK;
350 }
351
352
353 static void
ngx_stream_log_write(ngx_stream_session_t * s,ngx_stream_log_t * log,u_char * buf,size_t len)354 ngx_stream_log_write(ngx_stream_session_t *s, ngx_stream_log_t *log,
355 u_char *buf, size_t len)
356 {
357 u_char *name;
358 time_t now;
359 ssize_t n;
360 ngx_err_t err;
361 #if (NGX_ZLIB)
362 ngx_stream_log_buf_t *buffer;
363 #endif
364
365 if (log->script == NULL) {
366 name = log->file->name.data;
367
368 #if (NGX_ZLIB)
369 buffer = log->file->data;
370
371 if (buffer && buffer->gzip) {
372 n = ngx_stream_log_gzip(log->file->fd, buf, len, buffer->gzip,
373 s->connection->log);
374 } else {
375 n = ngx_write_fd(log->file->fd, buf, len);
376 }
377 #else
378 n = ngx_write_fd(log->file->fd, buf, len);
379 #endif
380
381 } else {
382 name = NULL;
383 n = ngx_stream_log_script_write(s, log->script, &name, buf, len);
384 }
385
386 if (n == (ssize_t) len) {
387 return;
388 }
389
390 now = ngx_time();
391
392 if (n == -1) {
393 err = ngx_errno;
394
395 if (err == NGX_ENOSPC) {
396 log->disk_full_time = now;
397 }
398
399 if (now - log->error_log_time > 59) {
400 ngx_log_error(NGX_LOG_ALERT, s->connection->log, err,
401 ngx_write_fd_n " to \"%s\" failed", name);
402
403 log->error_log_time = now;
404 }
405
406 return;
407 }
408
409 if (now - log->error_log_time > 59) {
410 ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
411 ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
412 name, n, len);
413
414 log->error_log_time = now;
415 }
416 }
417
418
419 static ssize_t
ngx_stream_log_script_write(ngx_stream_session_t * s,ngx_stream_log_script_t * script,u_char ** name,u_char * buf,size_t len)420 ngx_stream_log_script_write(ngx_stream_session_t *s,
421 ngx_stream_log_script_t *script, u_char **name, u_char *buf, size_t len)
422 {
423 ssize_t n;
424 ngx_str_t log;
425 ngx_open_file_info_t of;
426 ngx_stream_log_srv_conf_t *lscf;
427
428 if (ngx_stream_script_run(s, &log, script->lengths->elts, 1,
429 script->values->elts)
430 == NULL)
431 {
432 /* simulate successful logging */
433 return len;
434 }
435
436 log.data[log.len - 1] = '\0';
437 *name = log.data;
438
439 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
440 "stream log \"%s\"", log.data);
441
442 lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_log_module);
443
444 ngx_memzero(&of, sizeof(ngx_open_file_info_t));
445
446 of.log = 1;
447 of.valid = lscf->open_file_cache_valid;
448 of.min_uses = lscf->open_file_cache_min_uses;
449 of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
450
451 if (ngx_open_cached_file(lscf->open_file_cache, &log, &of,
452 s->connection->pool)
453 != NGX_OK)
454 {
455 if (of.err == 0) {
456 /* simulate successful logging */
457 return len;
458 }
459
460 ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno,
461 "%s \"%s\" failed", of.failed, log.data);
462 /* simulate successful logging */
463 return len;
464 }
465
466 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
467 "stream log #%d", of.fd);
468
469 n = ngx_write_fd(of.fd, buf, len);
470
471 return n;
472 }
473
474
475 #if (NGX_ZLIB)
476
477 static ssize_t
ngx_stream_log_gzip(ngx_fd_t fd,u_char * buf,size_t len,ngx_int_t level,ngx_log_t * log)478 ngx_stream_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,
479 ngx_log_t *log)
480 {
481 int rc, wbits, memlevel;
482 u_char *out;
483 size_t size;
484 ssize_t n;
485 z_stream zstream;
486 ngx_err_t err;
487 ngx_pool_t *pool;
488
489 wbits = MAX_WBITS;
490 memlevel = MAX_MEM_LEVEL - 1;
491
492 while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) {
493 wbits--;
494 memlevel--;
495 }
496
497 /*
498 * This is a formula from deflateBound() for conservative upper bound of
499 * compressed data plus 18 bytes of gzip wrapper.
500 */
501
502 size = len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5 + 18;
503
504 ngx_memzero(&zstream, sizeof(z_stream));
505
506 pool = ngx_create_pool(256, log);
507 if (pool == NULL) {
508 /* simulate successful logging */
509 return len;
510 }
511
512 pool->log = log;
513
514 zstream.zalloc = ngx_stream_log_gzip_alloc;
515 zstream.zfree = ngx_stream_log_gzip_free;
516 zstream.opaque = pool;
517
518 out = ngx_pnalloc(pool, size);
519 if (out == NULL) {
520 goto done;
521 }
522
523 zstream.next_in = buf;
524 zstream.avail_in = len;
525 zstream.next_out = out;
526 zstream.avail_out = size;
527
528 rc = deflateInit2(&zstream, (int) level, Z_DEFLATED, wbits + 16, memlevel,
529 Z_DEFAULT_STRATEGY);
530
531 if (rc != Z_OK) {
532 ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateInit2() failed: %d", rc);
533 goto done;
534 }
535
536 ngx_log_debug4(NGX_LOG_DEBUG_STREAM, log, 0,
537 "deflate in: ni:%p no:%p ai:%ud ao:%ud",
538 zstream.next_in, zstream.next_out,
539 zstream.avail_in, zstream.avail_out);
540
541 rc = deflate(&zstream, Z_FINISH);
542
543 if (rc != Z_STREAM_END) {
544 ngx_log_error(NGX_LOG_ALERT, log, 0,
545 "deflate(Z_FINISH) failed: %d", rc);
546 goto done;
547 }
548
549 ngx_log_debug5(NGX_LOG_DEBUG_STREAM, log, 0,
550 "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
551 zstream.next_in, zstream.next_out,
552 zstream.avail_in, zstream.avail_out,
553 rc);
554
555 size -= zstream.avail_out;
556
557 rc = deflateEnd(&zstream);
558
559 if (rc != Z_OK) {
560 ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc);
561 goto done;
562 }
563
564 n = ngx_write_fd(fd, out, size);
565
566 if (n != (ssize_t) size) {
567 err = (n == -1) ? ngx_errno : 0;
568
569 ngx_destroy_pool(pool);
570
571 ngx_set_errno(err);
572 return -1;
573 }
574
575 done:
576
577 ngx_destroy_pool(pool);
578
579 /* simulate successful logging */
580 return len;
581 }
582
583
584 static void *
ngx_stream_log_gzip_alloc(void * opaque,u_int items,u_int size)585 ngx_stream_log_gzip_alloc(void *opaque, u_int items, u_int size)
586 {
587 ngx_pool_t *pool = opaque;
588
589 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pool->log, 0,
590 "gzip alloc: n:%ud s:%ud", items, size);
591
592 return ngx_palloc(pool, items * size);
593 }
594
595
596 static void
ngx_stream_log_gzip_free(void * opaque,void * address)597 ngx_stream_log_gzip_free(void *opaque, void *address)
598 {
599 #if 0
600 ngx_pool_t *pool = opaque;
601
602 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pool->log, 0,
603 "gzip free: %p", address);
604 #endif
605 }
606
607 #endif
608
609
610 static void
ngx_stream_log_flush(ngx_open_file_t * file,ngx_log_t * log)611 ngx_stream_log_flush(ngx_open_file_t *file, ngx_log_t *log)
612 {
613 size_t len;
614 ssize_t n;
615 ngx_stream_log_buf_t *buffer;
616
617 buffer = file->data;
618
619 len = buffer->pos - buffer->start;
620
621 if (len == 0) {
622 return;
623 }
624
625 #if (NGX_ZLIB)
626 if (buffer->gzip) {
627 n = ngx_stream_log_gzip(file->fd, buffer->start, len, buffer->gzip,
628 log);
629 } else {
630 n = ngx_write_fd(file->fd, buffer->start, len);
631 }
632 #else
633 n = ngx_write_fd(file->fd, buffer->start, len);
634 #endif
635
636 if (n == -1) {
637 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
638 ngx_write_fd_n " to \"%s\" failed",
639 file->name.data);
640
641 } else if ((size_t) n != len) {
642 ngx_log_error(NGX_LOG_ALERT, log, 0,
643 ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
644 file->name.data, n, len);
645 }
646
647 buffer->pos = buffer->start;
648
649 if (buffer->event && buffer->event->timer_set) {
650 ngx_del_timer(buffer->event);
651 }
652 }
653
654
655 static void
ngx_stream_log_flush_handler(ngx_event_t * ev)656 ngx_stream_log_flush_handler(ngx_event_t *ev)
657 {
658 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
659 "stream log buffer flush handler");
660
661 ngx_stream_log_flush(ev->data, ev->log);
662 }
663
664
665 static u_char *
ngx_stream_log_copy_short(ngx_stream_session_t * s,u_char * buf,ngx_stream_log_op_t * op)666 ngx_stream_log_copy_short(ngx_stream_session_t *s, u_char *buf,
667 ngx_stream_log_op_t *op)
668 {
669 size_t len;
670 uintptr_t data;
671
672 len = op->len;
673 data = op->data;
674
675 while (len--) {
676 *buf++ = (u_char) (data & 0xff);
677 data >>= 8;
678 }
679
680 return buf;
681 }
682
683
684 static u_char *
ngx_stream_log_copy_long(ngx_stream_session_t * s,u_char * buf,ngx_stream_log_op_t * op)685 ngx_stream_log_copy_long(ngx_stream_session_t *s, u_char *buf,
686 ngx_stream_log_op_t *op)
687 {
688 return ngx_cpymem(buf, (u_char *) op->data, op->len);
689 }
690
691
692 static ngx_int_t
ngx_stream_log_variable_compile(ngx_conf_t * cf,ngx_stream_log_op_t * op,ngx_str_t * value,ngx_uint_t escape)693 ngx_stream_log_variable_compile(ngx_conf_t *cf, ngx_stream_log_op_t *op,
694 ngx_str_t *value, ngx_uint_t escape)
695 {
696 ngx_int_t index;
697
698 index = ngx_stream_get_variable_index(cf, value);
699 if (index == NGX_ERROR) {
700 return NGX_ERROR;
701 }
702
703 op->len = 0;
704
705 switch (escape) {
706 case NGX_STREAM_LOG_ESCAPE_JSON:
707 op->getlen = ngx_stream_log_json_variable_getlen;
708 op->run = ngx_stream_log_json_variable;
709 break;
710
711 case NGX_STREAM_LOG_ESCAPE_NONE:
712 op->getlen = ngx_stream_log_unescaped_variable_getlen;
713 op->run = ngx_stream_log_unescaped_variable;
714 break;
715
716 default: /* NGX_STREAM_LOG_ESCAPE_DEFAULT */
717 op->getlen = ngx_stream_log_variable_getlen;
718 op->run = ngx_stream_log_variable;
719 }
720
721 op->data = index;
722
723 return NGX_OK;
724 }
725
726
727 static size_t
ngx_stream_log_variable_getlen(ngx_stream_session_t * s,uintptr_t data)728 ngx_stream_log_variable_getlen(ngx_stream_session_t *s, uintptr_t data)
729 {
730 uintptr_t len;
731 ngx_stream_variable_value_t *value;
732
733 value = ngx_stream_get_indexed_variable(s, data);
734
735 if (value == NULL || value->not_found) {
736 return 1;
737 }
738
739 len = ngx_stream_log_escape(NULL, value->data, value->len);
740
741 value->escape = len ? 1 : 0;
742
743 return value->len + len * 3;
744 }
745
746
747 static u_char *
ngx_stream_log_variable(ngx_stream_session_t * s,u_char * buf,ngx_stream_log_op_t * op)748 ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf,
749 ngx_stream_log_op_t *op)
750 {
751 ngx_stream_variable_value_t *value;
752
753 value = ngx_stream_get_indexed_variable(s, op->data);
754
755 if (value == NULL || value->not_found) {
756 *buf = '-';
757 return buf + 1;
758 }
759
760 if (value->escape == 0) {
761 return ngx_cpymem(buf, value->data, value->len);
762
763 } else {
764 return (u_char *) ngx_stream_log_escape(buf, value->data, value->len);
765 }
766 }
767
768
769 static uintptr_t
ngx_stream_log_escape(u_char * dst,u_char * src,size_t size)770 ngx_stream_log_escape(u_char *dst, u_char *src, size_t size)
771 {
772 ngx_uint_t n;
773 static u_char hex[] = "0123456789ABCDEF";
774
775 static uint32_t escape[] = {
776 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
777
778 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
779 0x00000004, /* 0000 0000 0000 0000 0000 0000 0000 0100 */
780
781 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
782 0x10000000, /* 0001 0000 0000 0000 0000 0000 0000 0000 */
783
784 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
785 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
786
787 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
788 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
789 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
790 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
791 };
792
793
794 if (dst == NULL) {
795
796 /* find the number of the characters to be escaped */
797
798 n = 0;
799
800 while (size) {
801 if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
802 n++;
803 }
804 src++;
805 size--;
806 }
807
808 return (uintptr_t) n;
809 }
810
811 while (size) {
812 if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
813 *dst++ = '\\';
814 *dst++ = 'x';
815 *dst++ = hex[*src >> 4];
816 *dst++ = hex[*src & 0xf];
817 src++;
818
819 } else {
820 *dst++ = *src++;
821 }
822 size--;
823 }
824
825 return (uintptr_t) dst;
826 }
827
828
829 static size_t
ngx_stream_log_json_variable_getlen(ngx_stream_session_t * s,uintptr_t data)830 ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s, uintptr_t data)
831 {
832 uintptr_t len;
833 ngx_stream_variable_value_t *value;
834
835 value = ngx_stream_get_indexed_variable(s, data);
836
837 if (value == NULL || value->not_found) {
838 return 0;
839 }
840
841 len = ngx_escape_json(NULL, value->data, value->len);
842
843 value->escape = len ? 1 : 0;
844
845 return value->len + len;
846 }
847
848
849 static u_char *
ngx_stream_log_json_variable(ngx_stream_session_t * s,u_char * buf,ngx_stream_log_op_t * op)850 ngx_stream_log_json_variable(ngx_stream_session_t *s, u_char *buf,
851 ngx_stream_log_op_t *op)
852 {
853 ngx_stream_variable_value_t *value;
854
855 value = ngx_stream_get_indexed_variable(s, op->data);
856
857 if (value == NULL || value->not_found) {
858 return buf;
859 }
860
861 if (value->escape == 0) {
862 return ngx_cpymem(buf, value->data, value->len);
863
864 } else {
865 return (u_char *) ngx_escape_json(buf, value->data, value->len);
866 }
867 }
868
869
870 static size_t
ngx_stream_log_unescaped_variable_getlen(ngx_stream_session_t * s,uintptr_t data)871 ngx_stream_log_unescaped_variable_getlen(ngx_stream_session_t *s,
872 uintptr_t data)
873 {
874 ngx_stream_variable_value_t *value;
875
876 value = ngx_stream_get_indexed_variable(s, data);
877
878 if (value == NULL || value->not_found) {
879 return 0;
880 }
881
882 value->escape = 0;
883
884 return value->len;
885 }
886
887
888 static u_char *
ngx_stream_log_unescaped_variable(ngx_stream_session_t * s,u_char * buf,ngx_stream_log_op_t * op)889 ngx_stream_log_unescaped_variable(ngx_stream_session_t *s, u_char *buf,
890 ngx_stream_log_op_t *op)
891 {
892 ngx_stream_variable_value_t *value;
893
894 value = ngx_stream_get_indexed_variable(s, op->data);
895
896 if (value == NULL || value->not_found) {
897 return buf;
898 }
899
900 return ngx_cpymem(buf, value->data, value->len);
901 }
902
903
904 static void *
ngx_stream_log_create_main_conf(ngx_conf_t * cf)905 ngx_stream_log_create_main_conf(ngx_conf_t *cf)
906 {
907 ngx_stream_log_main_conf_t *conf;
908
909 conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_main_conf_t));
910 if (conf == NULL) {
911 return NULL;
912 }
913
914 if (ngx_array_init(&conf->formats, cf->pool, 4,
915 sizeof(ngx_stream_log_fmt_t))
916 != NGX_OK)
917 {
918 return NULL;
919 }
920
921 return conf;
922 }
923
924
925 static void *
ngx_stream_log_create_srv_conf(ngx_conf_t * cf)926 ngx_stream_log_create_srv_conf(ngx_conf_t *cf)
927 {
928 ngx_stream_log_srv_conf_t *conf;
929
930 conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_srv_conf_t));
931 if (conf == NULL) {
932 return NULL;
933 }
934
935 conf->open_file_cache = NGX_CONF_UNSET_PTR;
936
937 return conf;
938 }
939
940
941 static char *
ngx_stream_log_merge_srv_conf(ngx_conf_t * cf,void * parent,void * child)942 ngx_stream_log_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
943 {
944 ngx_stream_log_srv_conf_t *prev = parent;
945 ngx_stream_log_srv_conf_t *conf = child;
946
947 if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
948
949 conf->open_file_cache = prev->open_file_cache;
950 conf->open_file_cache_valid = prev->open_file_cache_valid;
951 conf->open_file_cache_min_uses = prev->open_file_cache_min_uses;
952
953 if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
954 conf->open_file_cache = NULL;
955 }
956 }
957
958 if (conf->logs || conf->off) {
959 return NGX_CONF_OK;
960 }
961
962 conf->logs = prev->logs;
963 conf->off = prev->off;
964
965 return NGX_CONF_OK;
966 }
967
968
969 static char *
ngx_stream_log_set_log(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)970 ngx_stream_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
971 {
972 ngx_stream_log_srv_conf_t *lscf = conf;
973
974 ssize_t size;
975 ngx_int_t gzip;
976 ngx_uint_t i, n;
977 ngx_msec_t flush;
978 ngx_str_t *value, name, s;
979 ngx_stream_log_t *log;
980 ngx_syslog_peer_t *peer;
981 ngx_stream_log_buf_t *buffer;
982 ngx_stream_log_fmt_t *fmt;
983 ngx_stream_script_compile_t sc;
984 ngx_stream_log_main_conf_t *lmcf;
985 ngx_stream_compile_complex_value_t ccv;
986
987 value = cf->args->elts;
988
989 if (ngx_strcmp(value[1].data, "off") == 0) {
990 lscf->off = 1;
991 if (cf->args->nelts == 2) {
992 return NGX_CONF_OK;
993 }
994
995 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
996 "invalid parameter \"%V\"", &value[2]);
997 return NGX_CONF_ERROR;
998 }
999
1000 if (lscf->logs == NULL) {
1001 lscf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_stream_log_t));
1002 if (lscf->logs == NULL) {
1003 return NGX_CONF_ERROR;
1004 }
1005 }
1006
1007 lmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_log_module);
1008
1009 log = ngx_array_push(lscf->logs);
1010 if (log == NULL) {
1011 return NGX_CONF_ERROR;
1012 }
1013
1014 ngx_memzero(log, sizeof(ngx_stream_log_t));
1015
1016
1017 if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {
1018
1019 peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
1020 if (peer == NULL) {
1021 return NGX_CONF_ERROR;
1022 }
1023
1024 if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
1025 return NGX_CONF_ERROR;
1026 }
1027
1028 log->syslog_peer = peer;
1029
1030 goto process_formats;
1031 }
1032
1033 n = ngx_stream_script_variables_count(&value[1]);
1034
1035 if (n == 0) {
1036 log->file = ngx_conf_open_file(cf->cycle, &value[1]);
1037 if (log->file == NULL) {
1038 return NGX_CONF_ERROR;
1039 }
1040
1041 } else {
1042 if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
1043 return NGX_CONF_ERROR;
1044 }
1045
1046 log->script = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_script_t));
1047 if (log->script == NULL) {
1048 return NGX_CONF_ERROR;
1049 }
1050
1051 ngx_memzero(&sc, sizeof(ngx_stream_script_compile_t));
1052
1053 sc.cf = cf;
1054 sc.source = &value[1];
1055 sc.lengths = &log->script->lengths;
1056 sc.values = &log->script->values;
1057 sc.variables = n;
1058 sc.complete_lengths = 1;
1059 sc.complete_values = 1;
1060
1061 if (ngx_stream_script_compile(&sc) != NGX_OK) {
1062 return NGX_CONF_ERROR;
1063 }
1064 }
1065
1066 process_formats:
1067
1068 if (cf->args->nelts >= 3) {
1069 name = value[2];
1070
1071 } else {
1072 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1073 "log format is not specified");
1074 return NGX_CONF_ERROR;
1075 }
1076
1077 fmt = lmcf->formats.elts;
1078 for (i = 0; i < lmcf->formats.nelts; i++) {
1079 if (fmt[i].name.len == name.len
1080 && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
1081 {
1082 log->format = &fmt[i];
1083 break;
1084 }
1085 }
1086
1087 if (log->format == NULL) {
1088 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1089 "unknown log format \"%V\"", &name);
1090 return NGX_CONF_ERROR;
1091 }
1092
1093 size = 0;
1094 flush = 0;
1095 gzip = 0;
1096
1097 for (i = 3; i < cf->args->nelts; i++) {
1098
1099 if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
1100 s.len = value[i].len - 7;
1101 s.data = value[i].data + 7;
1102
1103 size = ngx_parse_size(&s);
1104
1105 if (size == NGX_ERROR || size == 0) {
1106 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1107 "invalid buffer size \"%V\"", &s);
1108 return NGX_CONF_ERROR;
1109 }
1110
1111 continue;
1112 }
1113
1114 if (ngx_strncmp(value[i].data, "flush=", 6) == 0) {
1115 s.len = value[i].len - 6;
1116 s.data = value[i].data + 6;
1117
1118 flush = ngx_parse_time(&s, 0);
1119
1120 if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) {
1121 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1122 "invalid flush time \"%V\"", &s);
1123 return NGX_CONF_ERROR;
1124 }
1125
1126 continue;
1127 }
1128
1129 if (ngx_strncmp(value[i].data, "gzip", 4) == 0
1130 && (value[i].len == 4 || value[i].data[4] == '='))
1131 {
1132 #if (NGX_ZLIB)
1133 if (size == 0) {
1134 size = 64 * 1024;
1135 }
1136
1137 if (value[i].len == 4) {
1138 gzip = Z_BEST_SPEED;
1139 continue;
1140 }
1141
1142 s.len = value[i].len - 5;
1143 s.data = value[i].data + 5;
1144
1145 gzip = ngx_atoi(s.data, s.len);
1146
1147 if (gzip < 1 || gzip > 9) {
1148 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1149 "invalid compression level \"%V\"", &s);
1150 return NGX_CONF_ERROR;
1151 }
1152
1153 continue;
1154
1155 #else
1156 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1157 "nginx was built without zlib support");
1158 return NGX_CONF_ERROR;
1159 #endif
1160 }
1161
1162 if (ngx_strncmp(value[i].data, "if=", 3) == 0) {
1163 s.len = value[i].len - 3;
1164 s.data = value[i].data + 3;
1165
1166 ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
1167
1168 ccv.cf = cf;
1169 ccv.value = &s;
1170 ccv.complex_value = ngx_palloc(cf->pool,
1171 sizeof(ngx_stream_complex_value_t));
1172 if (ccv.complex_value == NULL) {
1173 return NGX_CONF_ERROR;
1174 }
1175
1176 if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
1177 return NGX_CONF_ERROR;
1178 }
1179
1180 log->filter = ccv.complex_value;
1181
1182 continue;
1183 }
1184
1185 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1186 "invalid parameter \"%V\"", &value[i]);
1187 return NGX_CONF_ERROR;
1188 }
1189
1190 if (flush && size == 0) {
1191 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1192 "no buffer is defined for access_log \"%V\"",
1193 &value[1]);
1194 return NGX_CONF_ERROR;
1195 }
1196
1197 if (size) {
1198
1199 if (log->script) {
1200 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1201 "buffered logs cannot have variables in name");
1202 return NGX_CONF_ERROR;
1203 }
1204
1205 if (log->syslog_peer) {
1206 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1207 "logs to syslog cannot be buffered");
1208 return NGX_CONF_ERROR;
1209 }
1210
1211 if (log->file->data) {
1212 buffer = log->file->data;
1213
1214 if (buffer->last - buffer->start != size
1215 || buffer->flush != flush
1216 || buffer->gzip != gzip)
1217 {
1218 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1219 "access_log \"%V\" already defined "
1220 "with conflicting parameters",
1221 &value[1]);
1222 return NGX_CONF_ERROR;
1223 }
1224
1225 return NGX_CONF_OK;
1226 }
1227
1228 buffer = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_buf_t));
1229 if (buffer == NULL) {
1230 return NGX_CONF_ERROR;
1231 }
1232
1233 buffer->start = ngx_pnalloc(cf->pool, size);
1234 if (buffer->start == NULL) {
1235 return NGX_CONF_ERROR;
1236 }
1237
1238 buffer->pos = buffer->start;
1239 buffer->last = buffer->start + size;
1240
1241 if (flush) {
1242 buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
1243 if (buffer->event == NULL) {
1244 return NGX_CONF_ERROR;
1245 }
1246
1247 buffer->event->data = log->file;
1248 buffer->event->handler = ngx_stream_log_flush_handler;
1249 buffer->event->log = &cf->cycle->new_log;
1250 buffer->event->cancelable = 1;
1251
1252 buffer->flush = flush;
1253 }
1254
1255 buffer->gzip = gzip;
1256
1257 log->file->flush = ngx_stream_log_flush;
1258 log->file->data = buffer;
1259 }
1260
1261 return NGX_CONF_OK;
1262 }
1263
1264
1265 static char *
ngx_stream_log_set_format(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1266 ngx_stream_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1267 {
1268 ngx_stream_log_main_conf_t *lmcf = conf;
1269
1270 ngx_str_t *value;
1271 ngx_uint_t i;
1272 ngx_stream_log_fmt_t *fmt;
1273
1274 value = cf->args->elts;
1275
1276 fmt = lmcf->formats.elts;
1277 for (i = 0; i < lmcf->formats.nelts; i++) {
1278 if (fmt[i].name.len == value[1].len
1279 && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
1280 {
1281 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1282 "duplicate \"log_format\" name \"%V\"",
1283 &value[1]);
1284 return NGX_CONF_ERROR;
1285 }
1286 }
1287
1288 fmt = ngx_array_push(&lmcf->formats);
1289 if (fmt == NULL) {
1290 return NGX_CONF_ERROR;
1291 }
1292
1293 fmt->name = value[1];
1294
1295 fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
1296 if (fmt->flushes == NULL) {
1297 return NGX_CONF_ERROR;
1298 }
1299
1300 fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_stream_log_op_t));
1301 if (fmt->ops == NULL) {
1302 return NGX_CONF_ERROR;
1303 }
1304
1305 return ngx_stream_log_compile_format(cf, fmt->flushes, fmt->ops,
1306 cf->args, 2);
1307 }
1308
1309
1310 static char *
ngx_stream_log_compile_format(ngx_conf_t * cf,ngx_array_t * flushes,ngx_array_t * ops,ngx_array_t * args,ngx_uint_t s)1311 ngx_stream_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
1312 ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
1313 {
1314 u_char *data, *p, ch;
1315 size_t i, len;
1316 ngx_str_t *value, var;
1317 ngx_int_t *flush;
1318 ngx_uint_t bracket, escape;
1319 ngx_stream_log_op_t *op;
1320
1321 escape = NGX_STREAM_LOG_ESCAPE_DEFAULT;
1322 value = args->elts;
1323
1324 if (s < args->nelts && ngx_strncmp(value[s].data, "escape=", 7) == 0) {
1325 data = value[s].data + 7;
1326
1327 if (ngx_strcmp(data, "json") == 0) {
1328 escape = NGX_STREAM_LOG_ESCAPE_JSON;
1329
1330 } else if (ngx_strcmp(data, "none") == 0) {
1331 escape = NGX_STREAM_LOG_ESCAPE_NONE;
1332
1333 } else if (ngx_strcmp(data, "default") != 0) {
1334 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1335 "unknown log format escaping \"%s\"", data);
1336 return NGX_CONF_ERROR;
1337 }
1338
1339 s++;
1340 }
1341
1342 for ( /* void */ ; s < args->nelts; s++) {
1343
1344 i = 0;
1345
1346 while (i < value[s].len) {
1347
1348 op = ngx_array_push(ops);
1349 if (op == NULL) {
1350 return NGX_CONF_ERROR;
1351 }
1352
1353 data = &value[s].data[i];
1354
1355 if (value[s].data[i] == '$') {
1356
1357 if (++i == value[s].len) {
1358 goto invalid;
1359 }
1360
1361 if (value[s].data[i] == '{') {
1362 bracket = 1;
1363
1364 if (++i == value[s].len) {
1365 goto invalid;
1366 }
1367
1368 var.data = &value[s].data[i];
1369
1370 } else {
1371 bracket = 0;
1372 var.data = &value[s].data[i];
1373 }
1374
1375 for (var.len = 0; i < value[s].len; i++, var.len++) {
1376 ch = value[s].data[i];
1377
1378 if (ch == '}' && bracket) {
1379 i++;
1380 bracket = 0;
1381 break;
1382 }
1383
1384 if ((ch >= 'A' && ch <= 'Z')
1385 || (ch >= 'a' && ch <= 'z')
1386 || (ch >= '0' && ch <= '9')
1387 || ch == '_')
1388 {
1389 continue;
1390 }
1391
1392 break;
1393 }
1394
1395 if (bracket) {
1396 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1397 "the closing bracket in \"%V\" "
1398 "variable is missing", &var);
1399 return NGX_CONF_ERROR;
1400 }
1401
1402 if (var.len == 0) {
1403 goto invalid;
1404 }
1405
1406 if (ngx_stream_log_variable_compile(cf, op, &var, escape)
1407 != NGX_OK)
1408 {
1409 return NGX_CONF_ERROR;
1410 }
1411
1412 if (flushes) {
1413
1414 flush = ngx_array_push(flushes);
1415 if (flush == NULL) {
1416 return NGX_CONF_ERROR;
1417 }
1418
1419 *flush = op->data; /* variable index */
1420 }
1421
1422 continue;
1423 }
1424
1425 i++;
1426
1427 while (i < value[s].len && value[s].data[i] != '$') {
1428 i++;
1429 }
1430
1431 len = &value[s].data[i] - data;
1432
1433 if (len) {
1434
1435 op->len = len;
1436 op->getlen = NULL;
1437
1438 if (len <= sizeof(uintptr_t)) {
1439 op->run = ngx_stream_log_copy_short;
1440 op->data = 0;
1441
1442 while (len--) {
1443 op->data <<= 8;
1444 op->data |= data[len];
1445 }
1446
1447 } else {
1448 op->run = ngx_stream_log_copy_long;
1449
1450 p = ngx_pnalloc(cf->pool, len);
1451 if (p == NULL) {
1452 return NGX_CONF_ERROR;
1453 }
1454
1455 ngx_memcpy(p, data, len);
1456 op->data = (uintptr_t) p;
1457 }
1458 }
1459 }
1460 }
1461
1462 return NGX_CONF_OK;
1463
1464 invalid:
1465
1466 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);
1467
1468 return NGX_CONF_ERROR;
1469 }
1470
1471
1472 static char *
ngx_stream_log_open_file_cache(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1473 ngx_stream_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1474 {
1475 ngx_stream_log_srv_conf_t *lscf = conf;
1476
1477 time_t inactive, valid;
1478 ngx_str_t *value, s;
1479 ngx_int_t max, min_uses;
1480 ngx_uint_t i;
1481
1482 if (lscf->open_file_cache != NGX_CONF_UNSET_PTR) {
1483 return "is duplicate";
1484 }
1485
1486 value = cf->args->elts;
1487
1488 max = 0;
1489 inactive = 10;
1490 valid = 60;
1491 min_uses = 1;
1492
1493 for (i = 1; i < cf->args->nelts; i++) {
1494
1495 if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
1496
1497 max = ngx_atoi(value[i].data + 4, value[i].len - 4);
1498 if (max == NGX_ERROR) {
1499 goto failed;
1500 }
1501
1502 continue;
1503 }
1504
1505 if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
1506
1507 s.len = value[i].len - 9;
1508 s.data = value[i].data + 9;
1509
1510 inactive = ngx_parse_time(&s, 1);
1511 if (inactive == (time_t) NGX_ERROR) {
1512 goto failed;
1513 }
1514
1515 continue;
1516 }
1517
1518 if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) {
1519
1520 min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
1521 if (min_uses == NGX_ERROR) {
1522 goto failed;
1523 }
1524
1525 continue;
1526 }
1527
1528 if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
1529
1530 s.len = value[i].len - 6;
1531 s.data = value[i].data + 6;
1532
1533 valid = ngx_parse_time(&s, 1);
1534 if (valid == (time_t) NGX_ERROR) {
1535 goto failed;
1536 }
1537
1538 continue;
1539 }
1540
1541 if (ngx_strcmp(value[i].data, "off") == 0) {
1542
1543 lscf->open_file_cache = NULL;
1544
1545 continue;
1546 }
1547
1548 failed:
1549
1550 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1551 "invalid \"open_log_file_cache\" parameter \"%V\"",
1552 &value[i]);
1553 return NGX_CONF_ERROR;
1554 }
1555
1556 if (lscf->open_file_cache == NULL) {
1557 return NGX_CONF_OK;
1558 }
1559
1560 if (max == 0) {
1561 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1562 "\"open_log_file_cache\" must have \"max\" parameter");
1563 return NGX_CONF_ERROR;
1564 }
1565
1566 lscf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
1567
1568 if (lscf->open_file_cache) {
1569
1570 lscf->open_file_cache_valid = valid;
1571 lscf->open_file_cache_min_uses = min_uses;
1572
1573 return NGX_CONF_OK;
1574 }
1575
1576 return NGX_CONF_ERROR;
1577 }
1578
1579
1580 static ngx_int_t
ngx_stream_log_init(ngx_conf_t * cf)1581 ngx_stream_log_init(ngx_conf_t *cf)
1582 {
1583 ngx_stream_handler_pt *h;
1584 ngx_stream_core_main_conf_t *cmcf;
1585
1586 cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
1587
1588 h = ngx_array_push(&cmcf->phases[NGX_STREAM_LOG_PHASE].handlers);
1589 if (h == NULL) {
1590 return NGX_ERROR;
1591 }
1592
1593 *h = ngx_stream_log_handler;
1594
1595 return NGX_OK;
1596 }
1597