comparison src/http/ngx_http_log_handler.c @ 176:c0552e5ab567

nginx-0.0.1-2003-11-09-23:03:38 import; separate building
author Igor Sysoev <igor@sysoev.ru>
date Sun, 09 Nov 2003 20:03:38 +0000
parents src/http/modules/ngx_http_log_handler.c@cd54bcbaf3b5
children 4db54fdbcbe7
comparison
equal deleted inserted replaced
175:e92c2c647c57 176:c0552e5ab567
1
2 #include <ngx_config.h>
3 #include <ngx_core.h>
4 #include <ngx_http.h>
5 #include <nginx.h>
6
7
8 static char *ngx_http_log_addr(ngx_http_request_t *r, char *buf,
9 uintptr_t data);
10 static char *ngx_http_log_connection(ngx_http_request_t *r, char *buf,
11 uintptr_t data);
12 static char *ngx_http_log_pipe(ngx_http_request_t *r, char *buf,
13 uintptr_t data);
14 static char *ngx_http_log_time(ngx_http_request_t *r, char *buf,
15 uintptr_t data);
16 static char *ngx_http_log_request(ngx_http_request_t *r, char *buf,
17 uintptr_t data);
18 static char *ngx_http_log_status(ngx_http_request_t *r, char *buf,
19 uintptr_t data);
20 static char *ngx_http_log_length(ngx_http_request_t *r, char *buf,
21 uintptr_t data);
22 static char *ngx_http_log_header_in(ngx_http_request_t *r, char *buf,
23 uintptr_t data);
24 static char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, char *buf,
25 uintptr_t data);
26 static char *ngx_http_log_header_out(ngx_http_request_t *r, char *buf,
27 uintptr_t data);
28 static char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, char *buf,
29 uintptr_t data);
30
31 static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
32 static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf);
33 static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
34 void *child);
35 static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
36 void *conf);
37 static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
38 void *conf);
39 static int ngx_http_log_parse_format(ngx_conf_t *cf, ngx_array_t *ops,
40 ngx_str_t *line);
41
42
43 static ngx_command_t ngx_http_log_commands[] = {
44
45 {ngx_string("log_format"),
46 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
47 ngx_http_log_set_format,
48 NGX_HTTP_MAIN_CONF_OFFSET,
49 0,
50 NULL},
51
52 {ngx_string("access_log"),
53 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
54 ngx_http_log_set_log,
55 NGX_HTTP_LOC_CONF_OFFSET,
56 0,
57 NULL},
58
59 ngx_null_command
60 };
61
62
63 ngx_http_module_t ngx_http_log_module_ctx = {
64 ngx_http_log_create_main_conf, /* create main configuration */
65 NULL, /* init main configuration */
66
67 NULL, /* create server configuration */
68 NULL, /* merge server configuration */
69
70 ngx_http_log_create_loc_conf, /* create location configration */
71 ngx_http_log_merge_loc_conf /* merge location configration */
72 };
73
74
75 ngx_module_t ngx_http_log_module = {
76 NGX_MODULE,
77 &ngx_http_log_module_ctx, /* module context */
78 ngx_http_log_commands, /* module directives */
79 NGX_HTTP_MODULE, /* module type */
80 NULL, /* init module */
81 NULL /* init child */
82 };
83
84
85 static ngx_str_t http_access_log = ngx_string("access.log");
86
87
88 static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
89 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
90
91 static ngx_str_t ngx_http_combined_fmt =
92 ngx_string("%addr - - [%time] \"%request\" %status %length "
93 "\"%{Referer}i\" %{User-Agent}i\"");
94
95
96 static ngx_http_log_op_name_t ngx_http_log_fmt_ops[] = {
97 { ngx_string("addr"), INET_ADDRSTRLEN - 1, ngx_http_log_addr },
98 { ngx_string("conn"), NGX_INT32_LEN, ngx_http_log_connection },
99 { ngx_string("pipe"), 1, ngx_http_log_pipe },
100 { ngx_string("time"), sizeof("28/Sep/1970:12:00:00") - 1,
101 ngx_http_log_time },
102 { ngx_string("request"), 0, ngx_http_log_request },
103 { ngx_string("status"), 3, ngx_http_log_status },
104 { ngx_string("length"), NGX_OFF_LEN, ngx_http_log_length },
105 { ngx_string("i"), NGX_HTTP_LOG_ARG, ngx_http_log_header_in },
106 { ngx_string("o"), NGX_HTTP_LOG_ARG, ngx_http_log_header_out },
107 { ngx_null_string, 0, NULL }
108 };
109
110
111 int ngx_http_log_handler(ngx_http_request_t *r)
112 {
113 int i, l;
114 u_int data;
115 char *line, *p;
116 size_t len;
117 ngx_http_log_t *log;
118 ngx_http_log_op_t *op;
119 ngx_http_log_loc_conf_t *lcf;
120 #if (WIN32)
121 u_int written;
122 #endif
123
124 ngx_log_debug(r->connection->log, "log handler");
125
126 lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
127
128 log = lcf->logs->elts;
129 for (l = 0; l < lcf->logs->nelts; l++) {
130
131 len = 0;
132 op = log[l].ops->elts;
133 for (i = 0; i < log[l].ops->nelts; i++) {
134 if (op[i].len == 0) {
135 len += (size_t) op[i].op(r, NULL, op[i].data);
136
137 } else {
138 len += op[i].len;
139 }
140 }
141
142 #if (WIN32)
143 len += 2;
144 #else
145 len++;
146 #endif
147
148 ngx_test_null(line, ngx_palloc(r->pool, len), NGX_ERROR);
149 p = line;
150
151 for (i = 0; i < log[l].ops->nelts; i++) {
152 if (op[i].op == NGX_HTTP_LOG_COPY_SHORT) {
153 len = op[i].len;
154 data = op[i].data;
155 while (len--) {
156 *p++ = data & 0xff;
157 data >>= 8;
158 }
159
160 } else if (op[i].op == NGX_HTTP_LOG_COPY_LONG) {
161 p = ngx_cpymem(p, (void *) op[i].data, op[i].len);
162
163 } else {
164 p = op[i].op(r, p, op[i].data);
165 }
166 }
167
168 #if (WIN32)
169 *p++ = CR; *p++ = LF;
170 WriteFile(log[l].file->fd, line, p - line, &written, NULL);
171 #else
172 *p++ = LF;
173 write(log[l].file->fd, line, p - line);
174 #endif
175 }
176
177 return NGX_OK;
178 }
179
180
181 static char *ngx_http_log_addr(ngx_http_request_t *r, char *buf, uintptr_t data)
182 {
183 return ngx_cpymem(buf, r->connection->addr_text.data,
184 r->connection->addr_text.len);
185 }
186
187
188 static char *ngx_http_log_connection(ngx_http_request_t *r, char *buf,
189 uintptr_t data)
190 {
191 return buf + ngx_snprintf(buf, NGX_INT32_LEN + 1, "%u",
192 r->connection->number);
193 }
194
195
196 static char *ngx_http_log_pipe(ngx_http_request_t *r, char *buf, uintptr_t data)
197 {
198 if (r->pipeline) {
199 *buf = 'p';
200 } else {
201 *buf = '.';
202 }
203
204 return buf + 1;
205 }
206
207
208 static char *ngx_http_log_time(ngx_http_request_t *r, char *buf, uintptr_t data)
209 {
210 ngx_tm_t tm;
211
212 ngx_localtime(&tm);
213
214 return buf + ngx_snprintf(buf, sizeof("28/Sep/1970:12:00:00"),
215 "%02d/%s/%d:%02d:%02d:%02d",
216 tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1],
217 tm.ngx_tm_year,
218 tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
219 }
220
221
222 static char *ngx_http_log_request(ngx_http_request_t *r, char *buf,
223 uintptr_t data)
224 {
225 if (buf == NULL) {
226 /* find the request line length */
227 return (char *) r->request_line.len;
228 }
229
230 return ngx_cpymem(buf, r->request_line.data, r->request_line.len);
231 }
232
233
234 static char *ngx_http_log_status(ngx_http_request_t *r, char *buf,
235 uintptr_t data)
236 {
237 return buf + ngx_snprintf(buf, 4, "%d", r->headers_out.status);
238 }
239
240
241 static char *ngx_http_log_length(ngx_http_request_t *r, char *buf,
242 uintptr_t data)
243 {
244 return buf + ngx_snprintf(buf, NGX_OFF_LEN + 1, OFF_FMT,
245 r->connection->sent);
246 }
247
248
249 static char *ngx_http_log_header_in(ngx_http_request_t *r, char *buf,
250 uintptr_t data)
251 {
252 int i;
253 ngx_str_t *s;
254 ngx_table_elt_t *h;
255 ngx_http_log_op_t *op;
256
257 if (r) {
258 h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data);
259
260 if (h == NULL) {
261
262 /* no header */
263
264 if (buf) {
265 *buf = '-';
266 }
267
268 return buf + 1;
269 }
270
271 if (buf == NULL) {
272 /* find the header length */
273 return (char *) h->value.len;
274 }
275
276 return ngx_cpymem(buf, h->value.data, h->value.len);
277 }
278
279 /* find an offset while a format string compilation */
280
281 op = (ngx_http_log_op_t *) buf;
282 s = (ngx_str_t *) data;
283
284 op->len = 0;
285
286 for (i = 0; ngx_http_headers_in[i].name.len != 0; i++) {
287 if (ngx_http_headers_in[i].name.len != s->len) {
288 continue;
289 }
290
291 if (ngx_strncasecmp(ngx_http_headers_in[i].name.data, s->data, s->len)
292 == 0)
293 {
294 op->op = ngx_http_log_header_in;
295 op->data = ngx_http_headers_in[i].offset;
296 return NULL;
297 }
298 }
299
300 op->op = ngx_http_log_unknown_header_in;
301 op->data = (uintptr_t) s;
302
303 return NULL;
304 }
305
306
307 static char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, char *buf,
308 uintptr_t data)
309 {
310 int i;
311 ngx_str_t *s;
312 ngx_table_elt_t *h;
313
314 s = (ngx_str_t *) data;
315
316 h = r->headers_in.headers->elts;
317 for (i = 0; i < r->headers_in.headers->nelts; i++) {
318 if (h[i].key.len != s->len) {
319 continue;
320 }
321
322 if (ngx_strncasecmp(h[i].key.data, s->data, s->len) == 0) {
323 if (buf == NULL) {
324 /* find the header length */
325 return (char *) h[i].value.len;
326 }
327
328 return ngx_cpymem(buf, h[i].value.data, h[i].value.len);
329 }
330 }
331
332 /* no header */
333
334 if (buf) {
335 *buf = '-';
336 }
337
338 return buf + 1;
339 }
340
341
342 static char *ngx_http_log_header_out(ngx_http_request_t *r, char *buf,
343 uintptr_t data)
344 {
345 int i;
346 ngx_str_t *s;
347 ngx_table_elt_t *h;
348 ngx_http_log_op_t *op;
349
350 if (r) {
351 h = *(ngx_table_elt_t **) ((char *) &r->headers_out + data);
352
353 if (h == NULL) {
354
355 /* no header */
356
357 if (data == offsetof(ngx_http_headers_out_t, server)) {
358 if (buf == NULL) {
359 return (char *) (sizeof(NGINX_VER) - 1);
360 }
361 return ngx_cpymem(buf, NGINX_VER, sizeof(NGINX_VER) - 1);
362 }
363
364 if (buf) {
365 *buf = '-';
366 }
367
368 return buf + 1;
369 }
370
371 if (buf == NULL) {
372 /* find the header length */
373 return (char *) h->value.len;
374 }
375
376 return ngx_cpymem(buf, h->value.data, h->value.len);
377 }
378
379 /* find an offset while a format string compilation */
380
381 op = (ngx_http_log_op_t *) buf;
382 s = (ngx_str_t *) data;
383
384 op->len = 0;
385
386 for (i = 0; ngx_http_headers_out[i].name.len != 0; i++) {
387 if (ngx_http_headers_out[i].name.len != s->len) {
388 continue;
389 }
390
391 if (ngx_strncasecmp(ngx_http_headers_out[i].name.data, s->data, s->len)
392 == 0)
393 {
394 op->op = ngx_http_log_header_out;
395 op->data = ngx_http_headers_out[i].offset;
396 return NULL;
397 }
398 }
399
400 op->op = ngx_http_log_unknown_header_out;
401 op->data = (uintptr_t) s;
402
403 return NULL;
404 }
405
406
407 static char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, char *buf,
408 uintptr_t data)
409 {
410 int i;
411 ngx_str_t *s;
412 ngx_table_elt_t *h;
413
414 s = (ngx_str_t *) data;
415
416 h = r->headers_out.headers->elts;
417 for (i = 0; i < r->headers_out.headers->nelts; i++) {
418 if (h[i].key.len != s->len) {
419 continue;
420 }
421
422 if (ngx_strncasecmp(h[i].key.data, s->data, s->len) == 0) {
423 if (buf == NULL) {
424 /* find the header length */
425 return (char *) h[i].value.len;
426 }
427
428 return ngx_cpymem(buf, h[i].value.data, h[i].value.len);
429 }
430 }
431
432 /* no header */
433
434 if (buf) {
435 *buf = '-';
436 }
437
438 return buf + 1;
439 }
440
441
442 static void *ngx_http_log_create_main_conf(ngx_conf_t *cf)
443 {
444 ngx_http_log_main_conf_t *conf;
445
446 char *rc;
447 ngx_str_t *value;
448
449 if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t)))) {
450 return NGX_CONF_ERROR;
451 }
452
453 ngx_init_array(conf->formats, cf->pool, 5, sizeof(ngx_http_log_fmt_t),
454 NGX_CONF_ERROR);
455
456 cf->args->nelts = 0;
457
458 if (!(value = ngx_push_array(cf->args))) {
459 return NGX_CONF_ERROR;
460 }
461
462 if (!(value = ngx_push_array(cf->args))) {
463 return NGX_CONF_ERROR;
464 }
465
466 value->len = sizeof("combined") - 1;
467 value->data = "combined";
468
469 if (!(value = ngx_push_array(cf->args))) {
470 return NGX_CONF_ERROR;
471 }
472
473 *value = ngx_http_combined_fmt;
474
475 rc = ngx_http_log_set_format(cf, NULL, conf);
476 if (rc != NGX_CONF_OK) {
477 return rc;
478 }
479
480 return conf;
481 }
482
483
484 static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf)
485 {
486 ngx_http_log_loc_conf_t *conf;
487
488 ngx_test_null(conf, ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t)),
489 NGX_CONF_ERROR);
490
491 return conf;
492 }
493
494
495 static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
496 void *child)
497 {
498 ngx_http_log_loc_conf_t *prev = parent;
499 ngx_http_log_loc_conf_t *conf = child;
500
501 ngx_http_log_t *log;
502 ngx_http_log_fmt_t *fmt;
503 ngx_http_log_main_conf_t *lmcf;
504
505 if (conf->logs == NULL) {
506 if (prev->logs) {
507 conf->logs = prev->logs;
508
509 } else {
510
511 conf->logs = ngx_create_array(cf->pool, 2, sizeof(ngx_http_log_t));
512 if (conf->logs == NULL) {
513 return NGX_CONF_ERROR;
514 }
515
516 if (!(log = ngx_push_array(conf->logs))) {
517 return NGX_CONF_ERROR;
518 }
519
520 log->file = ngx_conf_open_file(cf->cycle, &http_access_log);
521 if (log->file == NULL) {
522 return NGX_CONF_ERROR;
523 }
524
525 lmcf = ngx_http_conf_module_main_conf(cf, ngx_http_log_module);
526 fmt = lmcf->formats.elts;
527 /* the default "combined" format */
528 log->ops = fmt[0].ops;
529 }
530 }
531
532 return NGX_CONF_OK;
533 }
534
535
536 static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
537 void *conf)
538 {
539 ngx_http_log_loc_conf_t *llcf = conf;
540
541 int i;
542 ngx_str_t *value, name;
543 ngx_http_log_t *log;
544 ngx_http_log_fmt_t *fmt;
545 ngx_http_log_main_conf_t *lmcf;
546
547 if (llcf->logs == NULL) {
548 if (!(llcf->logs = ngx_create_array(cf->pool, 2,
549 sizeof(ngx_http_log_t)))) {
550 return NGX_CONF_ERROR;
551 }
552 }
553
554 value = cf->args->elts;
555 lmcf = ngx_http_conf_module_main_conf(cf, ngx_http_log_module);
556
557 if (!(log = ngx_push_array(llcf->logs))) {
558 return NGX_CONF_ERROR;
559 }
560
561 if (!(log->file = ngx_conf_open_file(cf->cycle, &value[1]))) {
562 return NGX_CONF_ERROR;
563 }
564
565 if (cf->args->nelts == 3) {
566 name = value[2];
567 } else {
568 name.len = sizeof("combined") - 1;
569 name.data = "combined";
570 }
571
572 fmt = lmcf->formats.elts;
573 for (i = 0; i < lmcf->formats.nelts; i++) {
574 if (fmt[i].name.len == name.len
575 && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
576 {
577 log->ops = fmt[i].ops;
578 return NGX_CONF_OK;
579 }
580 }
581
582 return NGX_CONF_OK;
583 }
584
585
586 static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
587 void *conf)
588 {
589 ngx_http_log_main_conf_t *lmcf = conf;
590
591 int s, f, invalid;
592 char *data, *p, *fname;
593 size_t i, len, fname_len;
594 ngx_str_t *value, arg, *a;
595 ngx_http_log_op_t *op;
596 ngx_http_log_fmt_t *fmt;
597 ngx_http_log_op_name_t *name;
598
599 value = cf->args->elts;
600 #if 0
601 lmcf = ngx_http_conf_module_main_conf(cf, ngx_http_log_module);
602 #endif
603
604 fmt = lmcf->formats.elts;
605 for (f = 0; f < lmcf->formats.nelts; f++) {
606 if (fmt[f].name.len == value[1].len
607 && ngx_strcmp(fmt->name.data, value[1].data) == 0)
608 {
609 return "duplicate \"log_format\" name";
610 }
611 }
612
613 if (!(fmt = ngx_push_array(&lmcf->formats))) {
614 return NGX_CONF_ERROR;
615 }
616
617 fmt->name = value[1];
618
619 if (!(fmt->ops = ngx_create_array(cf->pool, 20,
620 sizeof(ngx_http_log_op_t)))) {
621 return NGX_CONF_ERROR;
622 }
623
624 invalid = 0;
625 data = NULL;
626
627 for (s = 2; s < cf->args->nelts && !invalid; s++) {
628
629 i = 0;
630
631 while (i < value[s].len) {
632
633 if (!(op = ngx_push_array(fmt->ops))) {
634 return NGX_CONF_ERROR;
635 }
636
637 data = &value[s].data[i];
638
639 if (value[s].data[i] == '%') {
640 i++;
641
642 if (i == value[s].len) {
643 invalid = 1;
644 break;
645 }
646
647 if (value[s].data[i] == '{') {
648 i++;
649
650 arg.data = &value[s].data[i];
651
652 while (i < value[s].len && value[s].data[i] != '}') {
653 i++;
654 }
655
656 arg.len = &value[s].data[i] - arg.data;
657
658 if (i == value[s].len || arg.len == 0) {
659 invalid = 1;
660 break;
661 }
662
663 i++;
664
665 } else {
666 arg.len = 0;
667 }
668
669 fname = &value[s].data[i];
670
671 while (i < value[s].len
672 && value[s].data[i] >= 'a'
673 && value[s].data[i] <= 'z')
674 {
675 i++;
676 }
677
678 fname_len = &value[s].data[i] - fname;
679
680 if (fname_len == 0) {
681 invalid = 1;
682 break;
683 }
684
685 for (name = ngx_http_log_fmt_ops; name->name.len; name++) {
686 if (name->name.len == fname_len
687 && ngx_strncmp(name->name.data, fname, fname_len) == 0)
688 {
689 if (name->len != NGX_HTTP_LOG_ARG) {
690 if (arg.len) {
691 fname[fname_len] = '\0';
692 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
693 "\"%s\" must not have argument",
694 data);
695 return NGX_CONF_ERROR;
696 }
697
698 op->len = name->len;
699 op->op = name->op;
700 op->data = 0;
701
702 break;
703 }
704
705 if (arg.len == 0) {
706 fname[fname_len] = '\0';
707 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
708 "\"%s\" requires argument",
709 data);
710 return NGX_CONF_ERROR;
711 }
712
713 if (!(a = ngx_palloc(cf->pool, sizeof(ngx_str_t)))) {
714 return NGX_CONF_ERROR;
715 }
716
717 *a = arg;
718 name->op(NULL, (char *) op, (uintptr_t) a);
719
720 break;
721 }
722 }
723
724 if (name->name.len == 0) {
725 invalid = 1;
726 break;
727 }
728
729 } else {
730 i++;
731
732 while (i < value[s].len && value[s].data[i] != '%') {
733 i++;
734 }
735
736 len = &value[s].data[i] - data;
737
738 if (len) {
739
740 op->len = len;
741
742 if (len <= sizeof(uintptr_t)) {
743 op->op = NGX_HTTP_LOG_COPY_SHORT;
744 op->data = 0;
745
746 while (len--) {
747 op->data <<= 8;
748 op->data |= data[len];
749 }
750
751 } else {
752 op->op = NGX_HTTP_LOG_COPY_LONG;
753
754 if (!(p = ngx_palloc(cf->pool, len))) {
755 return NGX_CONF_ERROR;
756 }
757
758 ngx_memcpy(p, data, len);
759 op->data = (uintptr_t) p;
760 }
761 }
762 }
763 }
764 }
765
766 if (invalid) {
767 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
768 "invalid parameter \"%s\"", data);
769 return NGX_CONF_ERROR;
770 }
771
772 return NGX_CONF_OK;
773 }