blob: 55328312c1c31de8bad613abb877d100a87643e1 [file] [log] [blame]
Igor Sysoev74e95c22003-11-09 20:03:38 +00001
Igor Sysoevd90282d2004-09-28 08:34:51 +00002/*
Igor Sysoevff8da912004-09-29 16:00:49 +00003 * Copyright (C) Igor Sysoev
Igor Sysoevd90282d2004-09-28 08:34:51 +00004 */
5
6
Igor Sysoev74e95c22003-11-09 20:03:38 +00007#include <ngx_config.h>
8#include <ngx_core.h>
9#include <ngx_http.h>
10#include <nginx.h>
11
12
Igor Sysoeva8c54c02006-11-27 14:46:15 +000013typedef struct ngx_http_log_op_s ngx_http_log_op_t;
14
15typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf,
16 ngx_http_log_op_t *op);
17
18typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r,
19 uintptr_t data);
20
21
22struct ngx_http_log_op_s {
23 size_t len;
24 ngx_http_log_op_getlen_pt getlen;
25 ngx_http_log_op_run_pt run;
26 uintptr_t data;
27};
28
Igor Sysoev09c684b2005-11-09 17:25:55 +000029
30typedef struct {
31 ngx_str_t name;
32 ngx_array_t *ops; /* array of ngx_http_log_op_t */
33} ngx_http_log_fmt_t;
34
Igor Sysoevef809b82006-06-28 16:00:26 +000035
Igor Sysoev09c684b2005-11-09 17:25:55 +000036typedef struct {
37 ngx_array_t formats; /* array of ngx_http_log_fmt_t */
38 ngx_uint_t combined_used; /* unsigned combined_used:1 */
39} ngx_http_log_main_conf_t;
40
Igor Sysoevef809b82006-06-28 16:00:26 +000041
Igor Sysoev09c684b2005-11-09 17:25:55 +000042typedef struct {
43 ngx_open_file_t *file;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +000044 time_t disk_full_time;
Igor Sysoevd0863c12007-01-21 19:01:01 +000045 time_t error_log_time;
Igor Sysoev09c684b2005-11-09 17:25:55 +000046 ngx_array_t *ops; /* array of ngx_http_log_op_t */
47} ngx_http_log_t;
48
Igor Sysoevef809b82006-06-28 16:00:26 +000049
Igor Sysoev09c684b2005-11-09 17:25:55 +000050typedef struct {
51 ngx_array_t *logs; /* array of ngx_http_log_t */
52 ngx_uint_t off; /* unsigned off:1 */
53} ngx_http_log_loc_conf_t;
54
55
56typedef struct {
57 ngx_str_t name;
58 size_t len;
59 ngx_http_log_op_run_pt run;
60} ngx_http_log_var_t;
61
62
Igor Sysoevd0863c12007-01-21 19:01:01 +000063static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
64 u_char *buf, size_t len);
65
Igor Sysoev10a543a2004-03-16 07:10:12 +000066static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf,
Igor Sysoev11d75322005-03-01 15:20:36 +000067 ngx_http_log_op_t *op);
Igor Sysoev10a543a2004-03-16 07:10:12 +000068static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
Igor Sysoev11d75322005-03-01 15:20:36 +000069 ngx_http_log_op_t *op);
Igor Sysoev10a543a2004-03-16 07:10:12 +000070static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
Igor Sysoev11d75322005-03-01 15:20:36 +000071 ngx_http_log_op_t *op);
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +000072static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
Igor Sysoev11d75322005-03-01 15:20:36 +000073 ngx_http_log_op_t *op);
74static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
75 ngx_http_log_op_t *op);
Igor Sysoev10a543a2004-03-16 07:10:12 +000076static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf,
Igor Sysoev11d75322005-03-01 15:20:36 +000077 ngx_http_log_op_t *op);
Igor Sysoev09c684b2005-11-09 17:25:55 +000078static u_char *ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
Igor Sysoev11d75322005-03-01 15:20:36 +000079 ngx_http_log_op_t *op);
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +000080static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r,
Igor Sysoev09c684b2005-11-09 17:25:55 +000081 u_char *buf, ngx_http_log_op_t *op);
Igor Sysoev6a12fc92004-12-06 14:45:08 +000082static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
Igor Sysoev11d75322005-03-01 15:20:36 +000083 ngx_http_log_op_t *op);
Igor Sysoev02025fd2005-01-18 13:03:58 +000084
Igor Sysoevc1571722005-03-19 12:38:37 +000085static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
86 ngx_http_log_op_t *op, ngx_str_t *value);
87static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
88 uintptr_t data);
89static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
90 ngx_http_log_op_t *op);
91
92
Igor Sysoev74e95c22003-11-09 20:03:38 +000093static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
94static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf);
95static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
Igor Sysoev11d75322005-03-01 15:20:36 +000096 void *child);
Igor Sysoev74e95c22003-11-09 20:03:38 +000097static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
Igor Sysoev11d75322005-03-01 15:20:36 +000098 void *conf);
Igor Sysoev74e95c22003-11-09 20:03:38 +000099static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
Igor Sysoev11d75322005-03-01 15:20:36 +0000100 void *conf);
Igor Sysoev09c684b2005-11-09 17:25:55 +0000101static char *ngx_http_log_compile_format(ngx_conf_t *cf,
102 ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
103static ngx_int_t ngx_http_log_init(ngx_conf_t *cf);
Igor Sysoev74e95c22003-11-09 20:03:38 +0000104
105
106static ngx_command_t ngx_http_log_commands[] = {
107
Igor Sysoev11d75322005-03-01 15:20:36 +0000108 { ngx_string("log_format"),
109 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
110 ngx_http_log_set_format,
111 NGX_HTTP_MAIN_CONF_OFFSET,
112 0,
113 NULL },
Igor Sysoev74e95c22003-11-09 20:03:38 +0000114
Igor Sysoev11d75322005-03-01 15:20:36 +0000115 { ngx_string("access_log"),
Igor Sysoevac72bd12006-05-04 15:32:46 +0000116 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
117 |NGX_CONF_TAKE123,
Igor Sysoev11d75322005-03-01 15:20:36 +0000118 ngx_http_log_set_log,
119 NGX_HTTP_LOC_CONF_OFFSET,
120 0,
121 NULL },
Igor Sysoev74e95c22003-11-09 20:03:38 +0000122
Igor Sysoev11d75322005-03-01 15:20:36 +0000123 ngx_null_command
Igor Sysoev74e95c22003-11-09 20:03:38 +0000124};
125
126
Igor Sysoev8f125582006-07-28 15:16:17 +0000127static ngx_http_module_t ngx_http_log_module_ctx = {
Igor Sysoeva8c54c02006-11-27 14:46:15 +0000128 NULL, /* preconfiguration */
Igor Sysoev09c684b2005-11-09 17:25:55 +0000129 ngx_http_log_init, /* postconfiguration */
Igor Sysoev78329332003-11-10 17:17:31 +0000130
Igor Sysoev74e95c22003-11-09 20:03:38 +0000131 ngx_http_log_create_main_conf, /* create main configuration */
132 NULL, /* init main configuration */
133
134 NULL, /* create server configuration */
135 NULL, /* merge server configuration */
136
137 ngx_http_log_create_loc_conf, /* create location configration */
138 ngx_http_log_merge_loc_conf /* merge location configration */
139};
140
141
142ngx_module_t ngx_http_log_module = {
Igor Sysoev899b44e2005-05-12 14:58:06 +0000143 NGX_MODULE_V1,
Igor Sysoev74e95c22003-11-09 20:03:38 +0000144 &ngx_http_log_module_ctx, /* module context */
145 ngx_http_log_commands, /* module directives */
146 NGX_HTTP_MODULE, /* module type */
Igor Sysoeve5733802005-09-08 14:36:09 +0000147 NULL, /* init master */
Igor Sysoev09c684b2005-11-09 17:25:55 +0000148 NULL, /* init module */
Igor Sysoeve5733802005-09-08 14:36:09 +0000149 NULL, /* init process */
150 NULL, /* init thread */
151 NULL, /* exit thread */
152 NULL, /* exit process */
153 NULL, /* exit master */
154 NGX_MODULE_V1_PADDING
Igor Sysoev74e95c22003-11-09 20:03:38 +0000155};
156
157
Igor Sysoev3a58cc92007-01-24 09:15:25 +0000158static ngx_str_t ngx_http_access_log = ngx_string(NGX_HTTP_LOG_PATH);
Igor Sysoev74e95c22003-11-09 20:03:38 +0000159
160
Igor Sysoev09c684b2005-11-09 17:25:55 +0000161static ngx_str_t ngx_http_combined_fmt =
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000162 ngx_string("$remote_addr - $remote_user [$time_local] "
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000163 "\"$request\" $status $body_bytes_sent "
Igor Sysoev9ac946b2005-10-24 15:09:41 +0000164 "\"$http_referer\" \"$http_user_agent\"");
Igor Sysoev74e95c22003-11-09 20:03:38 +0000165
166
Igor Sysoev09c684b2005-11-09 17:25:55 +0000167static ngx_http_log_var_t ngx_http_log_vars[] = {
168 { ngx_string("connection"), NGX_ATOMIC_T_LEN, ngx_http_log_connection },
169 { ngx_string("pipe"), 1, ngx_http_log_pipe },
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000170 { ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1,
Igor Sysoev09c684b2005-11-09 17:25:55 +0000171 ngx_http_log_time },
172 { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec },
173 { ngx_string("request_time"), NGX_TIME_T_LEN, ngx_http_log_request_time },
174 { ngx_string("status"), 3, ngx_http_log_status },
175 { ngx_string("bytes_sent"), NGX_OFF_T_LEN, ngx_http_log_bytes_sent },
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000176 { ngx_string("body_bytes_sent"), NGX_OFF_T_LEN,
177 ngx_http_log_body_bytes_sent },
Igor Sysoev09c684b2005-11-09 17:25:55 +0000178 { ngx_string("apache_bytes_sent"), NGX_OFF_T_LEN,
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000179 ngx_http_log_body_bytes_sent },
Igor Sysoev09c684b2005-11-09 17:25:55 +0000180 { ngx_string("request_length"), NGX_SIZE_T_LEN,
181 ngx_http_log_request_length },
182
183 { ngx_null_string, 0, NULL }
184};
185
186
Igor Sysoev11d75322005-03-01 15:20:36 +0000187ngx_int_t
188ngx_http_log_handler(ngx_http_request_t *r)
Igor Sysoev74e95c22003-11-09 20:03:38 +0000189{
Igor Sysoev10a543a2004-03-16 07:10:12 +0000190 u_char *line, *p;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000191 size_t len;
Igor Sysoevd0863c12007-01-21 19:01:01 +0000192 ngx_uint_t i, l;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000193 ngx_http_log_t *log;
Igor Sysoev697d1ae2005-10-27 15:46:13 +0000194 ngx_open_file_t *file;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000195 ngx_http_log_op_t *op;
196 ngx_http_log_loc_conf_t *lcf;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000197
Igor Sysoevdc867cd2003-12-14 20:10:27 +0000198 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
199 "http log handler");
Igor Sysoev74e95c22003-11-09 20:03:38 +0000200
201 lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
202
Igor Sysoev85cccfb2004-09-15 16:00:43 +0000203 if (lcf->off) {
204 return NGX_OK;
205 }
206
Igor Sysoev74e95c22003-11-09 20:03:38 +0000207 log = lcf->logs->elts;
208 for (l = 0; l < lcf->logs->nelts; l++) {
209
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000210 if (ngx_time() == log[l].disk_full_time) {
211
212 /*
Igor Sysoevd0863c12007-01-21 19:01:01 +0000213 * on FreeBSD writing to a full filesystem with enabled softupdates
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000214 * may block process for much longer time than writing to non-full
Igor Sysoevd0863c12007-01-21 19:01:01 +0000215 * filesystem, so we skip writing to a log for one second
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000216 */
217
218 continue;
219 }
220
Igor Sysoev74e95c22003-11-09 20:03:38 +0000221 len = 0;
222 op = log[l].ops->elts;
223 for (i = 0; i < log[l].ops->nelts; i++) {
224 if (op[i].len == 0) {
Igor Sysoev02025fd2005-01-18 13:03:58 +0000225 len += op[i].getlen(r, op[i].data);
Igor Sysoev74e95c22003-11-09 20:03:38 +0000226
227 } else {
228 len += op[i].len;
229 }
230 }
231
Igor Sysoev697d1ae2005-10-27 15:46:13 +0000232 len += NGX_LINEFEED_SIZE;
233
234 file = log[l].file;
235
236 if (file->buffer) {
237
238 if (len > (size_t) (file->last - file->pos)) {
239
Igor Sysoevd0863c12007-01-21 19:01:01 +0000240 ngx_http_log_write(r, &log[l], file->buffer,
241 file->pos - file->buffer);
Igor Sysoev697d1ae2005-10-27 15:46:13 +0000242
243 file->pos = file->buffer;
244 }
245
246 if (len <= (size_t) (file->last - file->pos)) {
247
248 p = file->pos;
249
250 for (i = 0; i < log[l].ops->nelts; i++) {
251 p = op[i].run(r, p, &op[i]);
252 }
253
254 ngx_linefeed(p);
255
256 file->pos = p;
257
258 continue;
259 }
260 }
Igor Sysoev74e95c22003-11-09 20:03:38 +0000261
Igor Sysoevc1571722005-03-19 12:38:37 +0000262 line = ngx_palloc(r->pool, len);
263 if (line == NULL) {
Igor Sysoev42b12b32004-12-02 18:40:46 +0000264 return NGX_ERROR;
265 }
266
Igor Sysoev74e95c22003-11-09 20:03:38 +0000267 p = line;
268
269 for (i = 0; i < log[l].ops->nelts; i++) {
Igor Sysoev02025fd2005-01-18 13:03:58 +0000270 p = op[i].run(r, p, &op[i]);
Igor Sysoev74e95c22003-11-09 20:03:38 +0000271 }
272
Igor Sysoev697d1ae2005-10-27 15:46:13 +0000273 ngx_linefeed(p);
274
Igor Sysoevd0863c12007-01-21 19:01:01 +0000275 ngx_http_log_write(r, &log[l], line, p - line);
Igor Sysoev74e95c22003-11-09 20:03:38 +0000276 }
277
278 return NGX_OK;
279}
280
281
Igor Sysoevd0863c12007-01-21 19:01:01 +0000282static void
283ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
284 size_t len)
285{
286 time_t now;
287 ssize_t n;
288 ngx_err_t err;
289
290 n = ngx_write_fd(log->file->fd, buf, len);
291
292 if (n == (ssize_t) len) {
293 return;
294 }
295
296 now = ngx_time();
297
298 if (n == -1) {
299 err = ngx_errno;
300
301 if (err == NGX_ENOSPC) {
302 log->disk_full_time = now;
303 }
304
305 if (now - log->error_log_time > 60) {
306 ngx_log_error(NGX_LOG_ALERT, r->connection->log, err,
307 ngx_write_fd_n " to \"%V\" failed",
308 &log->file->name);
309
310 log->error_log_time = now;
311 }
312
313 return;
314 }
315
316 if (now - log->error_log_time > 60) {
317 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
318 ngx_write_fd_n " to \"%V\" was incomplete: %z of %uz",
319 &log->file->name, n, len);
320
321 log->error_log_time = now;
322 }
323}
324
325
Igor Sysoev11d75322005-03-01 15:20:36 +0000326static u_char *
327ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
328 ngx_http_log_op_t *op)
Igor Sysoev02025fd2005-01-18 13:03:58 +0000329{
330 size_t len;
331 uintptr_t data;
332
333 len = op->len;
334 data = op->data;
335
336 while (len--) {
337 *buf++ = (u_char) (data & 0xff);
338 data >>= 8;
339 }
340
341 return buf;
342}
343
344
Igor Sysoev11d75322005-03-01 15:20:36 +0000345static u_char *
346ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf,
347 ngx_http_log_op_t *op)
Igor Sysoev02025fd2005-01-18 13:03:58 +0000348{
349 return ngx_cpymem(buf, (u_char *) op->data, op->len);
350}
351
352
Igor Sysoev11d75322005-03-01 15:20:36 +0000353static u_char *
Igor Sysoev11d75322005-03-01 15:20:36 +0000354ngx_http_log_connection(ngx_http_request_t *r, u_char *buf,
355 ngx_http_log_op_t *op)
Igor Sysoev74e95c22003-11-09 20:03:38 +0000356{
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000357 return ngx_sprintf(buf, "%ui", r->connection->number);
Igor Sysoev74e95c22003-11-09 20:03:38 +0000358}
359
360
Igor Sysoev11d75322005-03-01 15:20:36 +0000361static u_char *
362ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
Igor Sysoev74e95c22003-11-09 20:03:38 +0000363{
364 if (r->pipeline) {
365 *buf = 'p';
366 } else {
367 *buf = '.';
368 }
369
370 return buf + 1;
371}
372
373
Igor Sysoev11d75322005-03-01 15:20:36 +0000374static u_char *
375ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
Igor Sysoev74e95c22003-11-09 20:03:38 +0000376{
Igor Sysoevd59a0472003-11-10 21:09:22 +0000377 return ngx_cpymem(buf, ngx_cached_http_log_time.data,
378 ngx_cached_http_log_time.len);
Igor Sysoev74e95c22003-11-09 20:03:38 +0000379}
380
381
Igor Sysoev11d75322005-03-01 15:20:36 +0000382static u_char *
383ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +0000384{
Igor Sysoevc2068d02005-10-19 12:33:58 +0000385 ngx_time_t *tp;
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +0000386
Igor Sysoevc2068d02005-10-19 12:33:58 +0000387 tp = ngx_timeofday();
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +0000388
Igor Sysoevc2068d02005-10-19 12:33:58 +0000389 return ngx_sprintf(buf, "%T.%03M", tp->sec, tp->msec);
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +0000390}
391
392
Igor Sysoev11d75322005-03-01 15:20:36 +0000393static u_char *
394ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
395 ngx_http_log_op_t *op)
396{
397 time_t elapsed;
398
399 elapsed = ngx_time() - r->start_time;
400
401 return ngx_sprintf(buf, "%T", elapsed);
402}
403
404
Igor Sysoev11d75322005-03-01 15:20:36 +0000405static u_char *
406ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
Igor Sysoev74e95c22003-11-09 20:03:38 +0000407{
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000408 return ngx_sprintf(buf, "%ui",
409 r->err_status ? r->err_status : r->headers_out.status);
Igor Sysoev74e95c22003-11-09 20:03:38 +0000410}
411
412
Igor Sysoev11d75322005-03-01 15:20:36 +0000413static u_char *
Igor Sysoev09c684b2005-11-09 17:25:55 +0000414ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
415 ngx_http_log_op_t *op)
Igor Sysoev74e95c22003-11-09 20:03:38 +0000416{
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000417 return ngx_sprintf(buf, "%O", r->connection->sent);
Igor Sysoev74e95c22003-11-09 20:03:38 +0000418}
419
420
Igor Sysoev11d75322005-03-01 15:20:36 +0000421static u_char *
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000422ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
Igor Sysoev11d75322005-03-01 15:20:36 +0000423 ngx_http_log_op_t *op)
Igor Sysoevdc867cd2003-12-14 20:10:27 +0000424{
Igor Sysoev11d75322005-03-01 15:20:36 +0000425 off_t length;
426
427 length = r->connection->sent - r->header_size;
428
429 if (length > 0) {
430 return ngx_sprintf(buf, "%O", length);
431 }
432
433 *buf = '0';
434
435 return buf + 1;
Igor Sysoevdc867cd2003-12-14 20:10:27 +0000436}
437
438
Igor Sysoev11d75322005-03-01 15:20:36 +0000439static u_char *
440ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
441 ngx_http_log_op_t *op)
Igor Sysoev6a12fc92004-12-06 14:45:08 +0000442{
Igor Sysoev1765f472006-07-07 16:33:19 +0000443 return ngx_sprintf(buf, "%O", r->request_length);
Igor Sysoev6a12fc92004-12-06 14:45:08 +0000444}
445
446
Igor Sysoev11d75322005-03-01 15:20:36 +0000447static ngx_int_t
Igor Sysoevc1571722005-03-19 12:38:37 +0000448ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
449 ngx_str_t *value)
450{
Igor Sysoev899b44e2005-05-12 14:58:06 +0000451 ngx_int_t index;
Igor Sysoevc1571722005-03-19 12:38:37 +0000452
Igor Sysoev899b44e2005-05-12 14:58:06 +0000453 index = ngx_http_get_variable_index(cf, value);
454 if (index == NGX_ERROR) {
Igor Sysoevc1571722005-03-19 12:38:37 +0000455 return NGX_ERROR;
456 }
457
458 op->len = 0;
459 op->getlen = ngx_http_log_variable_getlen;
460 op->run = ngx_http_log_variable;
Igor Sysoev899b44e2005-05-12 14:58:06 +0000461 op->data = index;
Igor Sysoevc1571722005-03-19 12:38:37 +0000462
463 return NGX_OK;
464}
465
466
467static size_t
468ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data)
469{
470 ngx_http_variable_value_t *value;
471
472 value = ngx_http_get_indexed_variable(r, data);
473
Igor Sysoev09c684b2005-11-09 17:25:55 +0000474 if (value == NULL || value->not_found) {
Igor Sysoevc1571722005-03-19 12:38:37 +0000475 return 1;
476 }
477
Igor Sysoev09c684b2005-11-09 17:25:55 +0000478 return value->len;
Igor Sysoevc1571722005-03-19 12:38:37 +0000479}
480
481
482static u_char *
483ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
484{
485 ngx_http_variable_value_t *value;
486
487 value = ngx_http_get_indexed_variable(r, op->data);
488
Igor Sysoev09c684b2005-11-09 17:25:55 +0000489 if (value == NULL || value->not_found) {
Igor Sysoevc1571722005-03-19 12:38:37 +0000490 *buf = '-';
491 return buf + 1;
492 }
493
Igor Sysoev09c684b2005-11-09 17:25:55 +0000494 return ngx_cpymem(buf, value->data, value->len);
Igor Sysoevc1571722005-03-19 12:38:37 +0000495}
496
497
Igor Sysoev11d75322005-03-01 15:20:36 +0000498static void *
499ngx_http_log_create_main_conf(ngx_conf_t *cf)
Igor Sysoev74e95c22003-11-09 20:03:38 +0000500{
501 ngx_http_log_main_conf_t *conf;
502
Igor Sysoev09c684b2005-11-09 17:25:55 +0000503 ngx_http_log_fmt_t *fmt;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000504
Igor Sysoevc1571722005-03-19 12:38:37 +0000505 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
506 if (conf == NULL) {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000507 return NGX_CONF_ERROR;
508 }
509
Igor Sysoev11d75322005-03-01 15:20:36 +0000510 if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t))
Igor Sysoev09c684b2005-11-09 17:25:55 +0000511 != NGX_OK)
Igor Sysoev11d75322005-03-01 15:20:36 +0000512 {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000513 return NGX_CONF_ERROR;
514 }
515
Igor Sysoev09c684b2005-11-09 17:25:55 +0000516 fmt = ngx_array_push(&conf->formats);
517 if (fmt == NULL) {
Igor Sysoev11d75322005-03-01 15:20:36 +0000518 return NGX_CONF_ERROR;
519 }
520
Igor Sysoev09c684b2005-11-09 17:25:55 +0000521 fmt->name.len = sizeof("combined") - 1;
522 fmt->name.data = (u_char *) "combined";
Igor Sysoev9ac946b2005-10-24 15:09:41 +0000523
Igor Sysoev09c684b2005-11-09 17:25:55 +0000524 fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
525 if (fmt->ops == NULL) {
Igor Sysoev9ac946b2005-10-24 15:09:41 +0000526 return NGX_CONF_ERROR;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000527 }
528
529 return conf;
530}
531
532
Igor Sysoev11d75322005-03-01 15:20:36 +0000533static void *
534ngx_http_log_create_loc_conf(ngx_conf_t *cf)
Igor Sysoev74e95c22003-11-09 20:03:38 +0000535{
536 ngx_http_log_loc_conf_t *conf;
537
Igor Sysoevc1571722005-03-19 12:38:37 +0000538 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t));
539 if (conf == NULL) {
Igor Sysoev85cccfb2004-09-15 16:00:43 +0000540 return NGX_CONF_ERROR;
541 }
Igor Sysoev74e95c22003-11-09 20:03:38 +0000542
543 return conf;
544}
545
546
Igor Sysoev11d75322005-03-01 15:20:36 +0000547static char *
548ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
Igor Sysoev74e95c22003-11-09 20:03:38 +0000549{
550 ngx_http_log_loc_conf_t *prev = parent;
551 ngx_http_log_loc_conf_t *conf = child;
552
553 ngx_http_log_t *log;
554 ngx_http_log_fmt_t *fmt;
555 ngx_http_log_main_conf_t *lmcf;
556
Igor Sysoev3a58cc92007-01-24 09:15:25 +0000557 if (conf->logs || conf->off) {
558 return NGX_CONF_OK;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000559 }
560
Igor Sysoev3a58cc92007-01-24 09:15:25 +0000561 *conf = *prev;
562
563 if (conf->logs || conf->off) {
564 return NGX_CONF_OK;
565 }
566
567 conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
568 if (conf->logs == NULL) {
569 return NGX_CONF_ERROR;
570 }
571
572 log = ngx_array_push(conf->logs);
573 if (log == NULL) {
574 return NGX_CONF_ERROR;
575 }
576
577 log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log);
578 if (log->file == NULL) {
579 return NGX_CONF_ERROR;
580 }
581
582 log->disk_full_time = 0;
583 log->error_log_time = 0;
584
585 lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
586 fmt = lmcf->formats.elts;
587
588 /* the default "combined" format */
589 log->ops = fmt[0].ops;
590 lmcf->combined_used = 1;
591
Igor Sysoev74e95c22003-11-09 20:03:38 +0000592 return NGX_CONF_OK;
593}
594
595
Igor Sysoev11d75322005-03-01 15:20:36 +0000596static char *
597ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
Igor Sysoev74e95c22003-11-09 20:03:38 +0000598{
599 ngx_http_log_loc_conf_t *llcf = conf;
600
Igor Sysoev697d1ae2005-10-27 15:46:13 +0000601 ssize_t buf;
Igor Sysoev10a543a2004-03-16 07:10:12 +0000602 ngx_uint_t i;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000603 ngx_str_t *value, name;
604 ngx_http_log_t *log;
605 ngx_http_log_fmt_t *fmt;
606 ngx_http_log_main_conf_t *lmcf;
607
Igor Sysoev85cccfb2004-09-15 16:00:43 +0000608 value = cf->args->elts;
609
610 if (ngx_strcmp(value[1].data, "off") == 0) {
611 llcf->off = 1;
612 return NGX_CONF_OK;
613 }
614
Igor Sysoev74e95c22003-11-09 20:03:38 +0000615 if (llcf->logs == NULL) {
Igor Sysoev85cccfb2004-09-15 16:00:43 +0000616 llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
617 if (llcf->logs == NULL) {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000618 return NGX_CONF_ERROR;
619 }
620 }
621
Igor Sysoev1c3567e2004-07-15 16:35:51 +0000622 lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
Igor Sysoev74e95c22003-11-09 20:03:38 +0000623
Igor Sysoevc1571722005-03-19 12:38:37 +0000624 log = ngx_array_push(llcf->logs);
625 if (log == NULL) {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000626 return NGX_CONF_ERROR;
627 }
628
Igor Sysoevc1571722005-03-19 12:38:37 +0000629 log->file = ngx_conf_open_file(cf->cycle, &value[1]);
630 if (log->file == NULL) {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000631 return NGX_CONF_ERROR;
632 }
633
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000634 log->disk_full_time = 0;
Igor Sysoevd0863c12007-01-21 19:01:01 +0000635 log->error_log_time = 0;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000636
Igor Sysoev697d1ae2005-10-27 15:46:13 +0000637 if (cf->args->nelts >= 3) {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000638 name = value[2];
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000639
640 if (ngx_strcmp(name.data, "combined") == 0) {
641 lmcf->combined_used = 1;
642 }
643
Igor Sysoev74e95c22003-11-09 20:03:38 +0000644 } else {
645 name.len = sizeof("combined") - 1;
Igor Sysoevda85f7f2004-03-16 21:26:01 +0000646 name.data = (u_char *) "combined";
Igor Sysoev09c684b2005-11-09 17:25:55 +0000647 lmcf->combined_used = 1;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000648 }
649
650 fmt = lmcf->formats.elts;
651 for (i = 0; i < lmcf->formats.nelts; i++) {
652 if (fmt[i].name.len == name.len
653 && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
654 {
655 log->ops = fmt[i].ops;
Igor Sysoev697d1ae2005-10-27 15:46:13 +0000656 goto buffer;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000657 }
658 }
659
Igor Sysoevaa828612005-02-09 14:31:07 +0000660 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
661 "unknown log format \"%V\"", &name);
Igor Sysoevaa828612005-02-09 14:31:07 +0000662 return NGX_CONF_ERROR;
Igor Sysoev697d1ae2005-10-27 15:46:13 +0000663
664buffer:
665
666 if (cf->args->nelts == 4) {
667 if (ngx_strncmp(value[3].data, "buffer=", 7) != 0) {
668 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
669 "invalid parameter \"%V\"", &value[3]);
670 return NGX_CONF_ERROR;
671 }
672
673 name.len = value[3].len - 7;
674 name.data = value[3].data + 7;
675
676 buf = ngx_parse_size(&name);
677
678 if (buf == NGX_ERROR) {
679 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
680 "invalid parameter \"%V\"", &value[3]);
681 return NGX_CONF_ERROR;
682 }
683
684 if (log->file->buffer && log->file->last - log->file->pos != buf) {
685 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
686 "access_log \"%V\" already defined "
687 "with different buffer size", &value[1]);
688 return NGX_CONF_ERROR;
689 }
690
691 log->file->buffer = ngx_palloc(cf->pool, buf);
692 if (log->file->buffer == NULL) {
693 return NGX_CONF_ERROR;
694 }
695
696 log->file->pos = log->file->buffer;
697 log->file->last = log->file->buffer + buf;
698 }
699
700 return NGX_CONF_OK;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000701}
702
703
Igor Sysoev11d75322005-03-01 15:20:36 +0000704static char *
705ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
Igor Sysoev74e95c22003-11-09 20:03:38 +0000706{
707 ngx_http_log_main_conf_t *lmcf = conf;
708
Igor Sysoev09c684b2005-11-09 17:25:55 +0000709 ngx_str_t *value;
710 ngx_uint_t i;
711 ngx_http_log_fmt_t *fmt;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000712
713 value = cf->args->elts;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000714
715 fmt = lmcf->formats.elts;
Igor Sysoev09c684b2005-11-09 17:25:55 +0000716 for (i = 0; i < lmcf->formats.nelts; i++) {
717 if (fmt[i].name.len == value[1].len
718 && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
Igor Sysoev74e95c22003-11-09 20:03:38 +0000719 {
720 return "duplicate \"log_format\" name";
721 }
722 }
723
Igor Sysoevc1571722005-03-19 12:38:37 +0000724 fmt = ngx_array_push(&lmcf->formats);
725 if (fmt == NULL) {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000726 return NGX_CONF_ERROR;
727 }
728
729 fmt->name = value[1];
730
Igor Sysoev09c684b2005-11-09 17:25:55 +0000731 fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
Igor Sysoevc1571722005-03-19 12:38:37 +0000732 if (fmt->ops == NULL) {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000733 return NGX_CONF_ERROR;
734 }
735
Igor Sysoev09c684b2005-11-09 17:25:55 +0000736 return ngx_http_log_compile_format(cf, fmt->ops, cf->args, 2);
737}
Igor Sysoev74e95c22003-11-09 20:03:38 +0000738
Igor Sysoev09c684b2005-11-09 17:25:55 +0000739
740static char *
741ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *ops,
742 ngx_array_t *args, ngx_uint_t s)
743{
Igor Sysoeva8c54c02006-11-27 14:46:15 +0000744 u_char *data, *p, ch;
745 size_t i, len;
746 ngx_str_t *value, var;
747 ngx_uint_t bracket;
748 ngx_http_log_op_t *op;
749 ngx_http_log_var_t *v;
Igor Sysoev09c684b2005-11-09 17:25:55 +0000750
751 value = args->elts;
Igor Sysoev09c684b2005-11-09 17:25:55 +0000752
753 for ( /* void */ ; s < args->nelts; s++) {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000754
Igor Sysoeva8c54c02006-11-27 14:46:15 +0000755 for (i = 0; i < value[s].len; i++) {
756 if (value[s].data[i] != '%') {
757 continue;
758 }
759
760 ch = value[s].data[i + 1];
761
762 if ((ch >= 'A' && ch <= 'Z')
763 || (ch >= 'a' && ch <= 'z')
764 || ch == '{')
765 {
766 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
767 "the parameters in the \"%%name\" form are not supported, "
768 "use the \"$variable\" instead");
769
770 return NGX_CONF_ERROR;
771 }
772 }
773
Igor Sysoev74e95c22003-11-09 20:03:38 +0000774 i = 0;
775
776 while (i < value[s].len) {
777
Igor Sysoev09c684b2005-11-09 17:25:55 +0000778 op = ngx_array_push(ops);
Igor Sysoevc1571722005-03-19 12:38:37 +0000779 if (op == NULL) {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000780 return NGX_CONF_ERROR;
781 }
782
783 data = &value[s].data[i];
784
Igor Sysoeva8c54c02006-11-27 14:46:15 +0000785 if (value[s].data[i] == '$') {
Igor Sysoev9ac946b2005-10-24 15:09:41 +0000786
787 if (++i == value[s].len) {
788 goto invalid;
789 }
790
791 if (value[s].data[i] == '{') {
792 bracket = 1;
793
794 if (++i == value[s].len) {
795 goto invalid;
796 }
797
798 var.data = &value[s].data[i];
799
800 } else {
801 bracket = 0;
802 var.data = &value[s].data[i];
803 }
804
805 for (var.len = 0; i < value[s].len; i++, var.len++) {
806 ch = value[s].data[i];
807
808 if (ch == '}' && bracket) {
809 i++;
810 bracket = 0;
811 break;
812 }
813
814 if ((ch >= 'A' && ch <= 'Z')
815 || (ch >= 'a' && ch <= 'z')
816 || (ch >= '0' && ch <= '9')
817 || ch == '_')
818 {
819 continue;
820 }
821
Igor Sysoev74e95c22003-11-09 20:03:38 +0000822 break;
823 }
824
Igor Sysoev9ac946b2005-10-24 15:09:41 +0000825 if (bracket) {
826 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
827 "the closing bracket in \"%V\" "
828 "variable is missing", &var);
829 return NGX_CONF_ERROR;
830 }
831
832 if (var.len == 0) {
833 goto invalid;
834 }
835
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000836 if (ngx_strncmp(var.data, "apache_bytes_sent", 17) == 0) {
837 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
838 "use \"$body_bytes_sent\" instead of "
839 "\"$apache_bytes_sent\"");
840 }
841
Igor Sysoev09c684b2005-11-09 17:25:55 +0000842 for (v = ngx_http_log_vars; v->name.len; v++) {
843
844 if (v->name.len == var.len
845 && ngx_strncmp(v->name.data, var.data, var.len) == 0)
846 {
847 op->len = v->len;
848 op->getlen = NULL;
849 op->run = v->run;
850 op->data = 0;
851
852 goto found;
853 }
854 }
855
Igor Sysoev9ac946b2005-10-24 15:09:41 +0000856 if (ngx_http_log_variable_compile(cf, op, &var) != NGX_OK) {
857 return NGX_CONF_ERROR;
858 }
859
Igor Sysoev09c684b2005-11-09 17:25:55 +0000860 found:
861
862 continue;
863 }
864
865 i++;
866
Igor Sysoeva8c54c02006-11-27 14:46:15 +0000867 while (i < value[s].len && value[s].data[i] != '$') {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000868 i++;
Igor Sysoev09c684b2005-11-09 17:25:55 +0000869 }
Igor Sysoev74e95c22003-11-09 20:03:38 +0000870
Igor Sysoev09c684b2005-11-09 17:25:55 +0000871 len = &value[s].data[i] - data;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000872
Igor Sysoev09c684b2005-11-09 17:25:55 +0000873 if (len) {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000874
Igor Sysoev09c684b2005-11-09 17:25:55 +0000875 op->len = len;
876 op->getlen = NULL;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000877
Igor Sysoev09c684b2005-11-09 17:25:55 +0000878 if (len <= sizeof(uintptr_t)) {
879 op->run = ngx_http_log_copy_short;
880 op->data = 0;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000881
Igor Sysoev09c684b2005-11-09 17:25:55 +0000882 while (len--) {
883 op->data <<= 8;
884 op->data |= data[len];
Igor Sysoev74e95c22003-11-09 20:03:38 +0000885 }
Igor Sysoev09c684b2005-11-09 17:25:55 +0000886
887 } else {
888 op->run = ngx_http_log_copy_long;
889
890 p = ngx_palloc(cf->pool, len);
891 if (p == NULL) {
892 return NGX_CONF_ERROR;
893 }
894
895 ngx_memcpy(p, data, len);
896 op->data = (uintptr_t) p;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000897 }
898 }
899 }
900 }
901
Igor Sysoev74e95c22003-11-09 20:03:38 +0000902 return NGX_CONF_OK;
Igor Sysoev9ac946b2005-10-24 15:09:41 +0000903
904invalid:
905
906 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);
907
908 return NGX_CONF_ERROR;
909}
910
911
912static ngx_int_t
Igor Sysoev09c684b2005-11-09 17:25:55 +0000913ngx_http_log_init(ngx_conf_t *cf)
Igor Sysoev9ac946b2005-10-24 15:09:41 +0000914{
Igor Sysoev09c684b2005-11-09 17:25:55 +0000915 ngx_str_t *value;
916 ngx_array_t a;
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000917 ngx_http_handler_pt *h;
Igor Sysoev09c684b2005-11-09 17:25:55 +0000918 ngx_http_log_fmt_t *fmt;
919 ngx_http_log_main_conf_t *lmcf;
Igor Sysoev9ac946b2005-10-24 15:09:41 +0000920 ngx_http_core_main_conf_t *cmcf;
921
Igor Sysoev09c684b2005-11-09 17:25:55 +0000922 lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
923
924 if (lmcf->combined_used) {
925 if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) {
926 return NGX_ERROR;
927 }
928
929 value = ngx_array_push(&a);
930 if (value == NULL) {
931 return NGX_ERROR;
932 }
933
934 *value = ngx_http_combined_fmt;
935 fmt = lmcf->formats.elts;
936
937 if (ngx_http_log_compile_format(cf, fmt->ops, &a, 0)
938 != NGX_CONF_OK)
939 {
940 return NGX_ERROR;
941 }
942 }
943
944 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
Igor Sysoev9ac946b2005-10-24 15:09:41 +0000945
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000946 h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
947 if (h == NULL) {
948 return NGX_ERROR;
949 }
950
951 *h = ngx_http_log_handler;
Igor Sysoev9ac946b2005-10-24 15:09:41 +0000952
953 return NGX_OK;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000954}