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