~nginx/nginx/1.0

« back to all changes in this revision

Viewing changes to src/http/modules/ngx_http_log_module.c

  • Committer: Michael Lustfield
  • Date: 2010-12-01 08:06:25 UTC
  • Revision ID: michael@profarius.com-20101201080625-y8i4bq0e54ev2qwy
Tags: 0.9.0
Nginx v0.9.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
 * Copyright (C) Igor Sysoev
 
4
 */
 
5
 
 
6
 
 
7
#include <ngx_config.h>
 
8
#include <ngx_core.h>
 
9
#include <ngx_http.h>
 
10
 
 
11
 
 
12
typedef struct ngx_http_log_op_s  ngx_http_log_op_t;
 
13
 
 
14
typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf,
 
15
    ngx_http_log_op_t *op);
 
16
 
 
17
typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r,
 
18
    uintptr_t data);
 
19
 
 
20
 
 
21
struct ngx_http_log_op_s {
 
22
    size_t                      len;
 
23
    ngx_http_log_op_getlen_pt   getlen;
 
24
    ngx_http_log_op_run_pt      run;
 
25
    uintptr_t                   data;
 
26
};
 
27
 
 
28
 
 
29
typedef struct {
 
30
    ngx_str_t                   name;
 
31
    ngx_array_t                *flushes;
 
32
    ngx_array_t                *ops;        /* array of ngx_http_log_op_t */
 
33
} ngx_http_log_fmt_t;
 
34
 
 
35
 
 
36
typedef 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
 
 
41
 
 
42
typedef struct {
 
43
    ngx_array_t                *lengths;
 
44
    ngx_array_t                *values;
 
45
} ngx_http_log_script_t;
 
46
 
 
47
 
 
48
typedef struct {
 
49
    ngx_open_file_t            *file;
 
50
    ngx_http_log_script_t      *script;
 
51
    time_t                      disk_full_time;
 
52
    time_t                      error_log_time;
 
53
    ngx_http_log_fmt_t         *format;
 
54
} ngx_http_log_t;
 
55
 
 
56
 
 
57
typedef struct {
 
58
    ngx_array_t                *logs;       /* array of ngx_http_log_t */
 
59
 
 
60
    ngx_open_file_cache_t      *open_file_cache;
 
61
    time_t                      open_file_cache_valid;
 
62
    ngx_uint_t                  open_file_cache_min_uses;
 
63
 
 
64
    ngx_uint_t                  off;        /* unsigned  off:1 */
 
65
} ngx_http_log_loc_conf_t;
 
66
 
 
67
 
 
68
typedef struct {
 
69
    ngx_str_t                   name;
 
70
    size_t                      len;
 
71
    ngx_http_log_op_run_pt      run;
 
72
} ngx_http_log_var_t;
 
73
 
 
74
 
 
75
static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
 
76
    u_char *buf, size_t len);
 
77
static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
 
78
    ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len);
 
79
 
 
80
static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf,
 
81
    ngx_http_log_op_t *op);
 
82
static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
 
83
    ngx_http_log_op_t *op);
 
84
static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
 
85
    ngx_http_log_op_t *op);
 
86
static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
 
87
    ngx_http_log_op_t *op);
 
88
static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
 
89
    ngx_http_log_op_t *op);
 
90
static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf,
 
91
    ngx_http_log_op_t *op);
 
92
static u_char *ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
 
93
    ngx_http_log_op_t *op);
 
94
static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r,
 
95
    u_char *buf, ngx_http_log_op_t *op);
 
96
static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
 
97
    ngx_http_log_op_t *op);
 
98
 
 
99
static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
 
100
    ngx_http_log_op_t *op, ngx_str_t *value);
 
101
static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
 
102
    uintptr_t data);
 
103
static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
 
104
    ngx_http_log_op_t *op);
 
105
static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size);
 
106
 
 
107
 
 
108
static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
 
109
static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf);
 
110
static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
 
111
    void *child);
 
112
static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
 
113
    void *conf);
 
114
static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
 
115
    void *conf);
 
116
static char *ngx_http_log_compile_format(ngx_conf_t *cf,
 
117
    ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
 
118
static char *ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
 
119
    void *conf);
 
120
static ngx_int_t ngx_http_log_init(ngx_conf_t *cf);
 
121
 
 
122
 
 
123
static ngx_command_t  ngx_http_log_commands[] = {
 
124
 
 
125
    { ngx_string("log_format"),
 
126
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
 
127
      ngx_http_log_set_format,
 
128
      NGX_HTTP_MAIN_CONF_OFFSET,
 
129
      0,
 
130
      NULL },
 
131
 
 
132
    { ngx_string("access_log"),
 
133
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
 
134
                        |NGX_HTTP_LMT_CONF|NGX_CONF_TAKE123,
 
135
      ngx_http_log_set_log,
 
136
      NGX_HTTP_LOC_CONF_OFFSET,
 
137
      0,
 
138
      NULL },
 
139
 
 
140
    { ngx_string("open_log_file_cache"),
 
141
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
 
142
      ngx_http_log_open_file_cache,
 
143
      NGX_HTTP_LOC_CONF_OFFSET,
 
144
      0,
 
145
      NULL },
 
146
 
 
147
      ngx_null_command
 
148
};
 
149
 
 
150
 
 
151
static ngx_http_module_t  ngx_http_log_module_ctx = {
 
152
    NULL,                                  /* preconfiguration */
 
153
    ngx_http_log_init,                     /* postconfiguration */
 
154
 
 
155
    ngx_http_log_create_main_conf,         /* create main configuration */
 
156
    NULL,                                  /* init main configuration */
 
157
 
 
158
    NULL,                                  /* create server configuration */
 
159
    NULL,                                  /* merge server configuration */
 
160
 
 
161
    ngx_http_log_create_loc_conf,          /* create location configration */
 
162
    ngx_http_log_merge_loc_conf            /* merge location configration */
 
163
};
 
164
 
 
165
 
 
166
ngx_module_t  ngx_http_log_module = {
 
167
    NGX_MODULE_V1,
 
168
    &ngx_http_log_module_ctx,              /* module context */
 
169
    ngx_http_log_commands,                 /* module directives */
 
170
    NGX_HTTP_MODULE,                       /* module type */
 
171
    NULL,                                  /* init master */
 
172
    NULL,                                  /* init module */
 
173
    NULL,                                  /* init process */
 
174
    NULL,                                  /* init thread */
 
175
    NULL,                                  /* exit thread */
 
176
    NULL,                                  /* exit process */
 
177
    NULL,                                  /* exit master */
 
178
    NGX_MODULE_V1_PADDING
 
179
};
 
180
 
 
181
 
 
182
static ngx_str_t  ngx_http_access_log = ngx_string(NGX_HTTP_LOG_PATH);
 
183
 
 
184
 
 
185
static ngx_str_t  ngx_http_combined_fmt =
 
186
    ngx_string("$remote_addr - $remote_user [$time_local] "
 
187
               "\"$request\" $status $body_bytes_sent "
 
188
               "\"$http_referer\" \"$http_user_agent\"");
 
189
 
 
190
 
 
191
static ngx_http_log_var_t  ngx_http_log_vars[] = {
 
192
    { ngx_string("connection"), NGX_ATOMIC_T_LEN, ngx_http_log_connection },
 
193
    { ngx_string("pipe"), 1, ngx_http_log_pipe },
 
194
    { ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1,
 
195
                          ngx_http_log_time },
 
196
    { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec },
 
197
    { ngx_string("request_time"), NGX_TIME_T_LEN + 4,
 
198
                          ngx_http_log_request_time },
 
199
    { ngx_string("status"), 3, ngx_http_log_status },
 
200
    { ngx_string("bytes_sent"), NGX_OFF_T_LEN, ngx_http_log_bytes_sent },
 
201
    { ngx_string("body_bytes_sent"), NGX_OFF_T_LEN,
 
202
                          ngx_http_log_body_bytes_sent },
 
203
    { ngx_string("apache_bytes_sent"), NGX_OFF_T_LEN,
 
204
                          ngx_http_log_body_bytes_sent },
 
205
    { ngx_string("request_length"), NGX_SIZE_T_LEN,
 
206
                          ngx_http_log_request_length },
 
207
 
 
208
    { ngx_null_string, 0, NULL }
 
209
};
 
210
 
 
211
 
 
212
ngx_int_t
 
213
ngx_http_log_handler(ngx_http_request_t *r)
 
214
{
 
215
    u_char                   *line, *p;
 
216
    size_t                    len;
 
217
    ngx_uint_t                i, l;
 
218
    ngx_http_log_t           *log;
 
219
    ngx_open_file_t          *file;
 
220
    ngx_http_log_op_t        *op;
 
221
    ngx_http_log_loc_conf_t  *lcf;
 
222
 
 
223
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
 
224
                   "http log handler");
 
225
 
 
226
    lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
 
227
 
 
228
    if (lcf->off) {
 
229
        return NGX_OK;
 
230
    }
 
231
 
 
232
    log = lcf->logs->elts;
 
233
    for (l = 0; l < lcf->logs->nelts; l++) {
 
234
 
 
235
        if (ngx_time() == log[l].disk_full_time) {
 
236
 
 
237
            /*
 
238
             * on FreeBSD writing to a full filesystem with enabled softupdates
 
239
             * may block process for much longer time than writing to non-full
 
240
             * filesystem, so we skip writing to a log for one second
 
241
             */
 
242
 
 
243
            continue;
 
244
        }
 
245
 
 
246
        ngx_http_script_flush_no_cacheable_variables(r, log[l].format->flushes);
 
247
 
 
248
        len = 0;
 
249
        op = log[l].format->ops->elts;
 
250
        for (i = 0; i < log[l].format->ops->nelts; i++) {
 
251
            if (op[i].len == 0) {
 
252
                len += op[i].getlen(r, op[i].data);
 
253
 
 
254
            } else {
 
255
                len += op[i].len;
 
256
            }
 
257
        }
 
258
 
 
259
        len += NGX_LINEFEED_SIZE;
 
260
 
 
261
        file = log[l].file;
 
262
 
 
263
        if (file && file->buffer) {
 
264
 
 
265
            if (len > (size_t) (file->last - file->pos)) {
 
266
 
 
267
                ngx_http_log_write(r, &log[l], file->buffer,
 
268
                                   file->pos - file->buffer);
 
269
 
 
270
                file->pos = file->buffer;
 
271
            }
 
272
 
 
273
            if (len <= (size_t) (file->last - file->pos)) {
 
274
 
 
275
                p = file->pos;
 
276
 
 
277
                for (i = 0; i < log[l].format->ops->nelts; i++) {
 
278
                    p = op[i].run(r, p, &op[i]);
 
279
                }
 
280
 
 
281
                ngx_linefeed(p);
 
282
 
 
283
                file->pos = p;
 
284
 
 
285
                continue;
 
286
            }
 
287
        }
 
288
 
 
289
        line = ngx_pnalloc(r->pool, len);
 
290
        if (line == NULL) {
 
291
            return NGX_ERROR;
 
292
        }
 
293
 
 
294
        p = line;
 
295
 
 
296
        for (i = 0; i < log[l].format->ops->nelts; i++) {
 
297
            p = op[i].run(r, p, &op[i]);
 
298
        }
 
299
 
 
300
        ngx_linefeed(p);
 
301
 
 
302
        ngx_http_log_write(r, &log[l], line, p - line);
 
303
    }
 
304
 
 
305
    return NGX_OK;
 
306
}
 
307
 
 
308
 
 
309
static void
 
310
ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
 
311
    size_t len)
 
312
{
 
313
    u_char     *name;
 
314
    time_t      now;
 
315
    ssize_t     n;
 
316
    ngx_err_t   err;
 
317
 
 
318
    if (log->script == NULL) {
 
319
        name = log->file->name.data;
 
320
        n = ngx_write_fd(log->file->fd, buf, len);
 
321
 
 
322
    } else {
 
323
        name = NULL;
 
324
        n = ngx_http_log_script_write(r, log->script, &name, buf, len);
 
325
    }
 
326
 
 
327
    if (n == (ssize_t) len) {
 
328
        return;
 
329
    }
 
330
 
 
331
    now = ngx_time();
 
332
 
 
333
    if (n == -1) {
 
334
        err = ngx_errno;
 
335
 
 
336
        if (err == NGX_ENOSPC) {
 
337
            log->disk_full_time = now;
 
338
        }
 
339
 
 
340
        if (now - log->error_log_time > 59) {
 
341
            ngx_log_error(NGX_LOG_ALERT, r->connection->log, err,
 
342
                          ngx_write_fd_n " to \"%s\" failed", name);
 
343
 
 
344
            log->error_log_time = now;
 
345
        }
 
346
 
 
347
        return;
 
348
    }
 
349
 
 
350
    if (now - log->error_log_time > 59) {
 
351
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
 
352
                      ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
 
353
                      name, n, len);
 
354
 
 
355
        log->error_log_time = now;
 
356
    }
 
357
}
 
358
 
 
359
 
 
360
static ssize_t
 
361
ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
 
362
    u_char **name, u_char *buf, size_t len)
 
363
{
 
364
    size_t                     root;
 
365
    ssize_t                    n;
 
366
    ngx_str_t                  log, path;
 
367
    ngx_open_file_info_t       of;
 
368
    ngx_http_log_loc_conf_t   *llcf;
 
369
    ngx_http_core_loc_conf_t  *clcf;
 
370
 
 
371
    if (!r->root_tested) {
 
372
 
 
373
        /* test root directory existance */
 
374
 
 
375
        if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
 
376
            /* simulate successfull logging */
 
377
            return len;
 
378
        }
 
379
 
 
380
        path.data[root] = '\0';
 
381
 
 
382
        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
383
 
 
384
        ngx_memzero(&of, sizeof(ngx_open_file_info_t));
 
385
 
 
386
        of.valid = clcf->open_file_cache_valid;
 
387
        of.min_uses = clcf->open_file_cache_min_uses;
 
388
        of.test_dir = 1;
 
389
        of.test_only = 1;
 
390
        of.errors = clcf->open_file_cache_errors;
 
391
        of.events = clcf->open_file_cache_events;
 
392
 
 
393
        if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
 
394
            != NGX_OK)
 
395
        {
 
396
            if (of.err == 0) {
 
397
                /* simulate successfull logging */
 
398
                return len;
 
399
            }
 
400
 
 
401
            ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err,
 
402
                          "testing \"%s\" existence failed", path.data);
 
403
 
 
404
            /* simulate successfull logging */
 
405
            return len;
 
406
        }
 
407
 
 
408
        if (!of.is_dir) {
 
409
            ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ENOTDIR,
 
410
                          "testing \"%s\" existence failed", path.data);
 
411
 
 
412
            /* simulate successfull logging */
 
413
            return len;
 
414
        }
 
415
    }
 
416
 
 
417
    if (ngx_http_script_run(r, &log, script->lengths->elts, 1,
 
418
                            script->values->elts)
 
419
        == NULL)
 
420
    {
 
421
        /* simulate successfull logging */
 
422
        return len;
 
423
    }
 
424
 
 
425
    log.data[log.len - 1] = '\0';
 
426
    *name = log.data;
 
427
 
 
428
    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
 
429
                   "http log \"%s\"", log.data);
 
430
 
 
431
    llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
 
432
 
 
433
    ngx_memzero(&of, sizeof(ngx_open_file_info_t));
 
434
 
 
435
    of.log = 1;
 
436
    of.valid = llcf->open_file_cache_valid;
 
437
    of.min_uses = llcf->open_file_cache_min_uses;
 
438
    of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
 
439
 
 
440
    if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool)
 
441
        != NGX_OK)
 
442
    {
 
443
        ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
 
444
                      "%s \"%s\" failed", of.failed, log.data);
 
445
        /* simulate successfull logging */
 
446
        return len;
 
447
    }
 
448
 
 
449
    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
 
450
                   "http log #%d", of.fd);
 
451
 
 
452
    n = ngx_write_fd(of.fd, buf, len);
 
453
 
 
454
    return n;
 
455
}
 
456
 
 
457
 
 
458
static u_char *
 
459
ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
 
460
    ngx_http_log_op_t *op)
 
461
{
 
462
    size_t     len;
 
463
    uintptr_t  data;
 
464
 
 
465
    len = op->len;
 
466
    data = op->data;
 
467
 
 
468
    while (len--) {
 
469
        *buf++ = (u_char) (data & 0xff);
 
470
        data >>= 8;
 
471
    }
 
472
 
 
473
    return buf;
 
474
}
 
475
 
 
476
 
 
477
static u_char *
 
478
ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf,
 
479
    ngx_http_log_op_t *op)
 
480
{
 
481
    return ngx_cpymem(buf, (u_char *) op->data, op->len);
 
482
}
 
483
 
 
484
 
 
485
static u_char *
 
486
ngx_http_log_connection(ngx_http_request_t *r, u_char *buf,
 
487
    ngx_http_log_op_t *op)
 
488
{
 
489
    return ngx_sprintf(buf, "%ui", r->connection->number);
 
490
}
 
491
 
 
492
 
 
493
static u_char *
 
494
ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
 
495
{
 
496
    if (r->pipeline) {
 
497
        *buf = 'p';
 
498
    } else {
 
499
        *buf = '.';
 
500
    }
 
501
 
 
502
    return buf + 1;
 
503
}
 
504
 
 
505
 
 
506
static u_char *
 
507
ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
 
508
{
 
509
    return ngx_cpymem(buf, ngx_cached_http_log_time.data,
 
510
                      ngx_cached_http_log_time.len);
 
511
}
 
512
 
 
513
 
 
514
static u_char *
 
515
ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
 
516
{
 
517
    ngx_time_t  *tp;
 
518
 
 
519
    tp = ngx_timeofday();
 
520
 
 
521
    return ngx_sprintf(buf, "%T.%03M", tp->sec, tp->msec);
 
522
}
 
523
 
 
524
 
 
525
static u_char *
 
526
ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
 
527
    ngx_http_log_op_t *op)
 
528
{
 
529
    ngx_time_t      *tp;
 
530
    ngx_msec_int_t   ms;
 
531
 
 
532
    tp = ngx_timeofday();
 
533
 
 
534
    ms = (ngx_msec_int_t)
 
535
             ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
 
536
    ms = ngx_max(ms, 0);
 
537
 
 
538
    return ngx_sprintf(buf, "%T.%03M", ms / 1000, ms % 1000);
 
539
}
 
540
 
 
541
 
 
542
static u_char *
 
543
ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
 
544
{
 
545
    ngx_uint_t  status;
 
546
 
 
547
    if (r->err_status) {
 
548
        status = r->err_status;
 
549
 
 
550
    } else if (r->headers_out.status) {
 
551
        status = r->headers_out.status;
 
552
 
 
553
    } else if (r->http_version == NGX_HTTP_VERSION_9) {
 
554
        *buf++ = '0';
 
555
        *buf++ = '0';
 
556
        *buf++ = '9';
 
557
        return buf;
 
558
 
 
559
    } else {
 
560
        status = 0;
 
561
    }
 
562
 
 
563
    return ngx_sprintf(buf, "%ui", status);
 
564
}
 
565
 
 
566
 
 
567
static u_char *
 
568
ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
 
569
    ngx_http_log_op_t *op)
 
570
{
 
571
    return ngx_sprintf(buf, "%O", r->connection->sent);
 
572
}
 
573
 
 
574
 
 
575
/*
 
576
 * although there is a real $body_bytes_sent variable,
 
577
 * this log operation code function is more optimized for logging
 
578
 */
 
579
 
 
580
static u_char *
 
581
ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
 
582
    ngx_http_log_op_t *op)
 
583
{
 
584
    off_t  length;
 
585
 
 
586
    length = r->connection->sent - r->header_size;
 
587
 
 
588
    if (length > 0) {
 
589
        return ngx_sprintf(buf, "%O", length);
 
590
    }
 
591
 
 
592
    *buf = '0';
 
593
 
 
594
    return buf + 1;
 
595
}
 
596
 
 
597
 
 
598
static u_char *
 
599
ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
 
600
    ngx_http_log_op_t *op)
 
601
{
 
602
    return ngx_sprintf(buf, "%O", r->request_length);
 
603
}
 
604
 
 
605
 
 
606
static ngx_int_t
 
607
ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
 
608
    ngx_str_t *value)
 
609
{
 
610
    ngx_int_t  index;
 
611
 
 
612
    index = ngx_http_get_variable_index(cf, value);
 
613
    if (index == NGX_ERROR) {
 
614
        return NGX_ERROR;
 
615
    }
 
616
 
 
617
    op->len = 0;
 
618
    op->getlen = ngx_http_log_variable_getlen;
 
619
    op->run = ngx_http_log_variable;
 
620
    op->data = index;
 
621
 
 
622
    return NGX_OK;
 
623
}
 
624
 
 
625
 
 
626
static size_t
 
627
ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data)
 
628
{
 
629
    uintptr_t                   len;
 
630
    ngx_http_variable_value_t  *value;
 
631
 
 
632
    value = ngx_http_get_indexed_variable(r, data);
 
633
 
 
634
    if (value == NULL || value->not_found) {
 
635
        return 1;
 
636
    }
 
637
 
 
638
    len = ngx_http_log_escape(NULL, value->data, value->len);
 
639
 
 
640
    value->escape = len ? 1 : 0;
 
641
 
 
642
    return value->len + len * 3;
 
643
}
 
644
 
 
645
 
 
646
static u_char *
 
647
ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
 
648
{
 
649
    ngx_http_variable_value_t  *value;
 
650
 
 
651
    value = ngx_http_get_indexed_variable(r, op->data);
 
652
 
 
653
    if (value == NULL || value->not_found) {
 
654
        *buf = '-';
 
655
        return buf + 1;
 
656
    }
 
657
 
 
658
    if (value->escape == 0) {
 
659
        return ngx_cpymem(buf, value->data, value->len);
 
660
 
 
661
    } else {
 
662
        return (u_char *) ngx_http_log_escape(buf, value->data, value->len);
 
663
    }
 
664
}
 
665
 
 
666
 
 
667
static uintptr_t
 
668
ngx_http_log_escape(u_char *dst, u_char *src, size_t size)
 
669
{
 
670
    ngx_uint_t      n;
 
671
    static u_char   hex[] = "0123456789ABCDEF";
 
672
 
 
673
    static uint32_t   escape[] = {
 
674
        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
 
675
 
 
676
                    /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
 
677
        0x00000004, /* 0000 0000 0000 0000  0000 0000 0000 0100 */
 
678
 
 
679
                    /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
 
680
        0x10000000, /* 0001 0000 0000 0000  0000 0000 0000 0000 */
 
681
 
 
682
                    /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
 
683
        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */
 
684
 
 
685
        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */
 
686
        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */
 
687
        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */
 
688
        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */
 
689
    };
 
690
 
 
691
 
 
692
    if (dst == NULL) {
 
693
 
 
694
        /* find the number of the characters to be escaped */
 
695
 
 
696
        n = 0;
 
697
 
 
698
        while (size) {
 
699
            if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
 
700
                n++;
 
701
            }
 
702
            src++;
 
703
            size--;
 
704
        }
 
705
 
 
706
        return (uintptr_t) n;
 
707
    }
 
708
 
 
709
    while (size) {
 
710
        if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
 
711
            *dst++ = '\\';
 
712
            *dst++ = 'x';
 
713
            *dst++ = hex[*src >> 4];
 
714
            *dst++ = hex[*src & 0xf];
 
715
            src++;
 
716
 
 
717
        } else {
 
718
            *dst++ = *src++;
 
719
        }
 
720
        size--;
 
721
    }
 
722
 
 
723
    return (uintptr_t) dst;
 
724
}
 
725
 
 
726
 
 
727
static void *
 
728
ngx_http_log_create_main_conf(ngx_conf_t *cf)
 
729
{
 
730
    ngx_http_log_main_conf_t  *conf;
 
731
 
 
732
    ngx_http_log_fmt_t  *fmt;
 
733
 
 
734
    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
 
735
    if (conf == NULL) {
 
736
        return NULL;
 
737
    }
 
738
 
 
739
    if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t))
 
740
        != NGX_OK)
 
741
    {
 
742
        return NULL;
 
743
    }
 
744
 
 
745
    fmt = ngx_array_push(&conf->formats);
 
746
    if (fmt == NULL) {
 
747
        return NULL;
 
748
    }
 
749
 
 
750
    ngx_str_set(&fmt->name, "combined");
 
751
 
 
752
    fmt->flushes = NULL;
 
753
 
 
754
    fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
 
755
    if (fmt->ops == NULL) {
 
756
        return NULL;
 
757
    }
 
758
 
 
759
    return conf;
 
760
}
 
761
 
 
762
 
 
763
static void *
 
764
ngx_http_log_create_loc_conf(ngx_conf_t *cf)
 
765
{
 
766
    ngx_http_log_loc_conf_t  *conf;
 
767
 
 
768
    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t));
 
769
    if (conf == NULL) {
 
770
        return NULL;
 
771
    }
 
772
 
 
773
    conf->open_file_cache = NGX_CONF_UNSET_PTR;
 
774
 
 
775
    return conf;
 
776
}
 
777
 
 
778
 
 
779
static char *
 
780
ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
 
781
{
 
782
    ngx_http_log_loc_conf_t *prev = parent;
 
783
    ngx_http_log_loc_conf_t *conf = child;
 
784
 
 
785
    ngx_http_log_t            *log;
 
786
    ngx_http_log_fmt_t        *fmt;
 
787
    ngx_http_log_main_conf_t  *lmcf;
 
788
 
 
789
    if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
 
790
 
 
791
        conf->open_file_cache = prev->open_file_cache;
 
792
        conf->open_file_cache_valid = prev->open_file_cache_valid;
 
793
        conf->open_file_cache_min_uses = prev->open_file_cache_min_uses;
 
794
 
 
795
        if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
 
796
            conf->open_file_cache = NULL;
 
797
        }
 
798
    }
 
799
 
 
800
    if (conf->logs || conf->off) {
 
801
        return NGX_CONF_OK;
 
802
    }
 
803
 
 
804
    conf->logs = prev->logs;
 
805
    conf->off = prev->off;
 
806
 
 
807
    if (conf->logs || conf->off) {
 
808
        return NGX_CONF_OK;
 
809
    }
 
810
 
 
811
    conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
 
812
    if (conf->logs == NULL) {
 
813
        return NGX_CONF_ERROR;
 
814
    }
 
815
 
 
816
    log = ngx_array_push(conf->logs);
 
817
    if (log == NULL) {
 
818
        return NGX_CONF_ERROR;
 
819
    }
 
820
 
 
821
    log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log);
 
822
    if (log->file == NULL) {
 
823
        return NGX_CONF_ERROR;
 
824
    }
 
825
 
 
826
    log->script = NULL;
 
827
    log->disk_full_time = 0;
 
828
    log->error_log_time = 0;
 
829
 
 
830
    lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
 
831
    fmt = lmcf->formats.elts;
 
832
 
 
833
    /* the default "combined" format */
 
834
    log->format = &fmt[0];
 
835
    lmcf->combined_used = 1;
 
836
 
 
837
    return NGX_CONF_OK;
 
838
}
 
839
 
 
840
 
 
841
static char *
 
842
ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 
843
{
 
844
    ngx_http_log_loc_conf_t *llcf = conf;
 
845
 
 
846
    ssize_t                     buf;
 
847
    ngx_uint_t                  i, n;
 
848
    ngx_str_t                  *value, name;
 
849
    ngx_http_log_t             *log;
 
850
    ngx_http_log_fmt_t         *fmt;
 
851
    ngx_http_log_main_conf_t   *lmcf;
 
852
    ngx_http_script_compile_t   sc;
 
853
 
 
854
    value = cf->args->elts;
 
855
 
 
856
    if (ngx_strcmp(value[1].data, "off") == 0) {
 
857
        llcf->off = 1;
 
858
        if (cf->args->nelts == 2) {
 
859
            return NGX_CONF_OK;
 
860
        }
 
861
 
 
862
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
 
863
                           "invalid parameter \"%V\"", &value[2]);
 
864
        return NGX_CONF_ERROR;
 
865
    }
 
866
 
 
867
    if (llcf->logs == NULL) {
 
868
        llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
 
869
        if (llcf->logs == NULL) {
 
870
            return NGX_CONF_ERROR;
 
871
        }
 
872
    }
 
873
 
 
874
    lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
 
875
 
 
876
    log = ngx_array_push(llcf->logs);
 
877
    if (log == NULL) {
 
878
        return NGX_CONF_ERROR;
 
879
    }
 
880
 
 
881
    ngx_memzero(log, sizeof(ngx_http_log_t));
 
882
 
 
883
    n = ngx_http_script_variables_count(&value[1]);
 
884
 
 
885
    if (n == 0) {
 
886
        log->file = ngx_conf_open_file(cf->cycle, &value[1]);
 
887
        if (log->file == NULL) {
 
888
            return NGX_CONF_ERROR;
 
889
        }
 
890
 
 
891
    } else {
 
892
        if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
 
893
            return NGX_CONF_ERROR;
 
894
        }
 
895
 
 
896
        log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t));
 
897
        if (log->script == NULL) {
 
898
            return NGX_CONF_ERROR;
 
899
        }
 
900
 
 
901
        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
 
902
 
 
903
        sc.cf = cf;
 
904
        sc.source = &value[1];
 
905
        sc.lengths = &log->script->lengths;
 
906
        sc.values = &log->script->values;
 
907
        sc.variables = n;
 
908
        sc.complete_lengths = 1;
 
909
        sc.complete_values = 1;
 
910
 
 
911
        if (ngx_http_script_compile(&sc) != NGX_OK) {
 
912
            return NGX_CONF_ERROR;
 
913
        }
 
914
    }
 
915
 
 
916
    if (cf->args->nelts >= 3) {
 
917
        name = value[2];
 
918
 
 
919
        if (ngx_strcmp(name.data, "combined") == 0) {
 
920
            lmcf->combined_used = 1;
 
921
        }
 
922
 
 
923
    } else {
 
924
        ngx_str_set(&name, "combined");
 
925
        lmcf->combined_used = 1;
 
926
    }
 
927
 
 
928
    fmt = lmcf->formats.elts;
 
929
    for (i = 0; i < lmcf->formats.nelts; i++) {
 
930
        if (fmt[i].name.len == name.len
 
931
            && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
 
932
        {
 
933
            log->format = &fmt[i];
 
934
            goto buffer;
 
935
        }
 
936
    }
 
937
 
 
938
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
 
939
                       "unknown log format \"%V\"", &name);
 
940
    return NGX_CONF_ERROR;
 
941
 
 
942
buffer:
 
943
 
 
944
    if (cf->args->nelts == 4) {
 
945
        if (ngx_strncmp(value[3].data, "buffer=", 7) != 0) {
 
946
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
 
947
                               "invalid parameter \"%V\"", &value[3]);
 
948
            return NGX_CONF_ERROR;
 
949
        }
 
950
 
 
951
        if (log->script) {
 
952
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
 
953
                               "buffered logs can not have variables in name");
 
954
            return NGX_CONF_ERROR;
 
955
        }
 
956
 
 
957
        name.len = value[3].len - 7;
 
958
        name.data = value[3].data + 7;
 
959
 
 
960
        buf = ngx_parse_size(&name);
 
961
 
 
962
        if (buf == NGX_ERROR) {
 
963
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
 
964
                               "invalid parameter \"%V\"", &value[3]);
 
965
            return NGX_CONF_ERROR;
 
966
        }
 
967
 
 
968
        if (log->file->buffer && log->file->last - log->file->pos != buf) {
 
969
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
 
970
                               "access_log \"%V\" already defined "
 
971
                               "with different buffer size", &value[1]);
 
972
            return NGX_CONF_ERROR;
 
973
        }
 
974
 
 
975
        log->file->buffer = ngx_palloc(cf->pool, buf);
 
976
        if (log->file->buffer == NULL) {
 
977
            return NGX_CONF_ERROR;
 
978
        }
 
979
 
 
980
        log->file->pos = log->file->buffer;
 
981
        log->file->last = log->file->buffer + buf;
 
982
    }
 
983
 
 
984
    return NGX_CONF_OK;
 
985
}
 
986
 
 
987
 
 
988
static char *
 
989
ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 
990
{
 
991
    ngx_http_log_main_conf_t *lmcf = conf;
 
992
 
 
993
    ngx_str_t           *value;
 
994
    ngx_uint_t           i;
 
995
    ngx_http_log_fmt_t  *fmt;
 
996
 
 
997
    value = cf->args->elts;
 
998
 
 
999
    fmt = lmcf->formats.elts;
 
1000
    for (i = 0; i < lmcf->formats.nelts; i++) {
 
1001
        if (fmt[i].name.len == value[1].len
 
1002
            && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
 
1003
        {
 
1004
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
 
1005
                               "duplicate \"log_format\" name \"%V\"",
 
1006
                               &value[1]);
 
1007
            return NGX_CONF_ERROR;
 
1008
        }
 
1009
    }
 
1010
 
 
1011
    fmt = ngx_array_push(&lmcf->formats);
 
1012
    if (fmt == NULL) {
 
1013
        return NGX_CONF_ERROR;
 
1014
    }
 
1015
 
 
1016
    fmt->name = value[1];
 
1017
 
 
1018
    fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
 
1019
    if (fmt->flushes == NULL) {
 
1020
        return NGX_CONF_ERROR;
 
1021
    }
 
1022
 
 
1023
    fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
 
1024
    if (fmt->ops == NULL) {
 
1025
        return NGX_CONF_ERROR;
 
1026
    }
 
1027
 
 
1028
    return ngx_http_log_compile_format(cf, fmt->flushes, fmt->ops, cf->args, 2);
 
1029
}
 
1030
 
 
1031
 
 
1032
static char *
 
1033
ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
 
1034
    ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
 
1035
{
 
1036
    u_char              *data, *p, ch;
 
1037
    size_t               i, len;
 
1038
    ngx_str_t           *value, var;
 
1039
    ngx_int_t           *flush;
 
1040
    ngx_uint_t           bracket;
 
1041
    ngx_http_log_op_t   *op;
 
1042
    ngx_http_log_var_t  *v;
 
1043
 
 
1044
    value = args->elts;
 
1045
 
 
1046
    for ( /* void */ ; s < args->nelts; s++) {
 
1047
 
 
1048
        for (i = 0; i < value[s].len; i++) {
 
1049
            if (value[s].data[i] != '%') {
 
1050
                continue;
 
1051
            }
 
1052
 
 
1053
            ch = value[s].data[i + 1];
 
1054
 
 
1055
            if ((ch >= 'A' && ch <= 'Z')
 
1056
                 || (ch >= 'a' && ch <= 'z')
 
1057
                 || ch == '{')
 
1058
            {
 
1059
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
 
1060
                     "the parameters in the \"%%name\" form are not supported, "
 
1061
                     "use the \"$variable\" instead");
 
1062
 
 
1063
                return NGX_CONF_ERROR;
 
1064
            }
 
1065
        }
 
1066
 
 
1067
        i = 0;
 
1068
 
 
1069
        while (i < value[s].len) {
 
1070
 
 
1071
            op = ngx_array_push(ops);
 
1072
            if (op == NULL) {
 
1073
                return NGX_CONF_ERROR;
 
1074
            }
 
1075
 
 
1076
            data = &value[s].data[i];
 
1077
 
 
1078
            if (value[s].data[i] == '$') {
 
1079
 
 
1080
                if (++i == value[s].len) {
 
1081
                    goto invalid;
 
1082
                }
 
1083
 
 
1084
                if (value[s].data[i] == '{') {
 
1085
                    bracket = 1;
 
1086
 
 
1087
                    if (++i == value[s].len) {
 
1088
                        goto invalid;
 
1089
                    }
 
1090
 
 
1091
                    var.data = &value[s].data[i];
 
1092
 
 
1093
                } else {
 
1094
                    bracket = 0;
 
1095
                    var.data = &value[s].data[i];
 
1096
                }
 
1097
 
 
1098
                for (var.len = 0; i < value[s].len; i++, var.len++) {
 
1099
                    ch = value[s].data[i];
 
1100
 
 
1101
                    if (ch == '}' && bracket) {
 
1102
                        i++;
 
1103
                        bracket = 0;
 
1104
                        break;
 
1105
                    }
 
1106
 
 
1107
                    if ((ch >= 'A' && ch <= 'Z')
 
1108
                        || (ch >= 'a' && ch <= 'z')
 
1109
                        || (ch >= '0' && ch <= '9')
 
1110
                        || ch == '_')
 
1111
                    {
 
1112
                        continue;
 
1113
                    }
 
1114
 
 
1115
                    break;
 
1116
                }
 
1117
 
 
1118
                if (bracket) {
 
1119
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
 
1120
                                       "the closing bracket in \"%V\" "
 
1121
                                       "variable is missing", &var);
 
1122
                    return NGX_CONF_ERROR;
 
1123
                }
 
1124
 
 
1125
                if (var.len == 0) {
 
1126
                    goto invalid;
 
1127
                }
 
1128
 
 
1129
                if (ngx_strncmp(var.data, "apache_bytes_sent", 17) == 0) {
 
1130
                    ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
 
1131
                        "use \"$body_bytes_sent\" instead of "
 
1132
                        "\"$apache_bytes_sent\"");
 
1133
                }
 
1134
 
 
1135
                for (v = ngx_http_log_vars; v->name.len; v++) {
 
1136
 
 
1137
                    if (v->name.len == var.len
 
1138
                        && ngx_strncmp(v->name.data, var.data, var.len) == 0)
 
1139
                    {
 
1140
                        op->len = v->len;
 
1141
                        op->getlen = NULL;
 
1142
                        op->run = v->run;
 
1143
                        op->data = 0;
 
1144
 
 
1145
                        goto found;
 
1146
                    }
 
1147
                }
 
1148
 
 
1149
                if (ngx_http_log_variable_compile(cf, op, &var) != NGX_OK) {
 
1150
                    return NGX_CONF_ERROR;
 
1151
                }
 
1152
 
 
1153
                if (flushes) {
 
1154
 
 
1155
                    flush = ngx_array_push(flushes);
 
1156
                    if (flush == NULL) {
 
1157
                        return NGX_CONF_ERROR;
 
1158
                    }
 
1159
 
 
1160
                    *flush = op->data; /* variable index */
 
1161
                }
 
1162
 
 
1163
            found:
 
1164
 
 
1165
                continue;
 
1166
            }
 
1167
 
 
1168
            i++;
 
1169
 
 
1170
            while (i < value[s].len && value[s].data[i] != '$') {
 
1171
                i++;
 
1172
            }
 
1173
 
 
1174
            len = &value[s].data[i] - data;
 
1175
 
 
1176
            if (len) {
 
1177
 
 
1178
                op->len = len;
 
1179
                op->getlen = NULL;
 
1180
 
 
1181
                if (len <= sizeof(uintptr_t)) {
 
1182
                    op->run = ngx_http_log_copy_short;
 
1183
                    op->data = 0;
 
1184
 
 
1185
                    while (len--) {
 
1186
                        op->data <<= 8;
 
1187
                        op->data |= data[len];
 
1188
                    }
 
1189
 
 
1190
                } else {
 
1191
                    op->run = ngx_http_log_copy_long;
 
1192
 
 
1193
                    p = ngx_pnalloc(cf->pool, len);
 
1194
                    if (p == NULL) {
 
1195
                        return NGX_CONF_ERROR;
 
1196
                    }
 
1197
 
 
1198
                    ngx_memcpy(p, data, len);
 
1199
                    op->data = (uintptr_t) p;
 
1200
                }
 
1201
            }
 
1202
        }
 
1203
    }
 
1204
 
 
1205
    return NGX_CONF_OK;
 
1206
 
 
1207
invalid:
 
1208
 
 
1209
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);
 
1210
 
 
1211
    return NGX_CONF_ERROR;
 
1212
}
 
1213
 
 
1214
 
 
1215
static char *
 
1216
ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 
1217
{
 
1218
    ngx_http_log_loc_conf_t *llcf = conf;
 
1219
 
 
1220
    time_t       inactive, valid;
 
1221
    ngx_str_t   *value, s;
 
1222
    ngx_int_t    max, min_uses;
 
1223
    ngx_uint_t   i;
 
1224
 
 
1225
    if (llcf->open_file_cache != NGX_CONF_UNSET_PTR) {
 
1226
        return "is duplicate";
 
1227
    }
 
1228
 
 
1229
    value = cf->args->elts;
 
1230
 
 
1231
    max = 0;
 
1232
    inactive = 10;
 
1233
    valid = 60;
 
1234
    min_uses = 1;
 
1235
 
 
1236
    for (i = 1; i < cf->args->nelts; i++) {
 
1237
 
 
1238
        if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
 
1239
 
 
1240
            max = ngx_atoi(value[i].data + 4, value[i].len - 4);
 
1241
            if (max == NGX_ERROR) {
 
1242
                goto failed;
 
1243
            }
 
1244
 
 
1245
            continue;
 
1246
        }
 
1247
 
 
1248
        if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
 
1249
 
 
1250
            s.len = value[i].len - 9;
 
1251
            s.data = value[i].data + 9;
 
1252
 
 
1253
            inactive = ngx_parse_time(&s, 1);
 
1254
            if (inactive < 0) {
 
1255
                goto failed;
 
1256
            }
 
1257
 
 
1258
            continue;
 
1259
        }
 
1260
 
 
1261
        if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) {
 
1262
 
 
1263
            min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
 
1264
            if (min_uses == NGX_ERROR) {
 
1265
                goto failed;
 
1266
            }
 
1267
 
 
1268
            continue;
 
1269
        }
 
1270
 
 
1271
        if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
 
1272
 
 
1273
            s.len = value[i].len - 6;
 
1274
            s.data = value[i].data + 6;
 
1275
 
 
1276
            valid = ngx_parse_time(&s, 1);
 
1277
            if (valid < 0) {
 
1278
                goto failed;
 
1279
            }
 
1280
 
 
1281
            continue;
 
1282
        }
 
1283
 
 
1284
        if (ngx_strcmp(value[i].data, "off") == 0) {
 
1285
 
 
1286
            llcf->open_file_cache = NULL;
 
1287
 
 
1288
            continue;
 
1289
        }
 
1290
 
 
1291
    failed:
 
1292
 
 
1293
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
 
1294
                           "invalid \"open_log_file_cache\" parameter \"%V\"",
 
1295
                           &value[i]);
 
1296
        return NGX_CONF_ERROR;
 
1297
    }
 
1298
 
 
1299
    if (llcf->open_file_cache == NULL) {
 
1300
        return NGX_CONF_OK;
 
1301
    }
 
1302
 
 
1303
    if (max == 0) {
 
1304
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
 
1305
                        "\"open_log_file_cache\" must have \"max\" parameter");
 
1306
        return NGX_CONF_ERROR;
 
1307
    }
 
1308
 
 
1309
    llcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
 
1310
 
 
1311
    if (llcf->open_file_cache) {
 
1312
 
 
1313
        llcf->open_file_cache_valid = valid;
 
1314
        llcf->open_file_cache_min_uses = min_uses;
 
1315
 
 
1316
        return NGX_CONF_OK;
 
1317
    }
 
1318
 
 
1319
    return NGX_CONF_ERROR;
 
1320
}
 
1321
 
 
1322
 
 
1323
static ngx_int_t
 
1324
ngx_http_log_init(ngx_conf_t *cf)
 
1325
{
 
1326
    ngx_str_t                  *value;
 
1327
    ngx_array_t                 a;
 
1328
    ngx_http_handler_pt        *h;
 
1329
    ngx_http_log_fmt_t         *fmt;
 
1330
    ngx_http_log_main_conf_t   *lmcf;
 
1331
    ngx_http_core_main_conf_t  *cmcf;
 
1332
 
 
1333
    lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
 
1334
 
 
1335
    if (lmcf->combined_used) {
 
1336
        if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) {
 
1337
            return NGX_ERROR;
 
1338
        }
 
1339
 
 
1340
        value = ngx_array_push(&a);
 
1341
        if (value == NULL) {
 
1342
            return NGX_ERROR;
 
1343
        }
 
1344
 
 
1345
        *value = ngx_http_combined_fmt;
 
1346
        fmt = lmcf->formats.elts;
 
1347
 
 
1348
        if (ngx_http_log_compile_format(cf, NULL, fmt->ops, &a, 0)
 
1349
            != NGX_CONF_OK)
 
1350
        {
 
1351
            return NGX_ERROR;
 
1352
        }
 
1353
    }
 
1354
 
 
1355
    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
 
1356
 
 
1357
    h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
 
1358
    if (h == NULL) {
 
1359
        return NGX_ERROR;
 
1360
    }
 
1361
 
 
1362
    *h = ngx_http_log_handler;
 
1363
 
 
1364
    return NGX_OK;
 
1365
}