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