Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_stream.h>
0011 
0012 #if (NGX_ZLIB)
0013 #include <zlib.h>
0014 #endif
0015 
0016 
0017 typedef struct ngx_stream_log_op_s  ngx_stream_log_op_t;
0018 
0019 typedef u_char *(*ngx_stream_log_op_run_pt) (ngx_stream_session_t *s,
0020     u_char *buf, ngx_stream_log_op_t *op);
0021 
0022 typedef size_t (*ngx_stream_log_op_getlen_pt) (ngx_stream_session_t *s,
0023     uintptr_t data);
0024 
0025 
0026 struct ngx_stream_log_op_s {
0027     size_t                       len;
0028     ngx_stream_log_op_getlen_pt  getlen;
0029     ngx_stream_log_op_run_pt     run;
0030     uintptr_t                    data;
0031 };
0032 
0033 
0034 typedef struct {
0035     ngx_str_t                    name;
0036     ngx_array_t                 *flushes;
0037     ngx_array_t                 *ops;        /* array of ngx_stream_log_op_t */
0038 } ngx_stream_log_fmt_t;
0039 
0040 
0041 typedef struct {
0042     ngx_array_t                  formats;    /* array of ngx_stream_log_fmt_t */
0043 } ngx_stream_log_main_conf_t;
0044 
0045 
0046 typedef struct {
0047     u_char                      *start;
0048     u_char                      *pos;
0049     u_char                      *last;
0050 
0051     ngx_event_t                 *event;
0052     ngx_msec_t                   flush;
0053     ngx_int_t                    gzip;
0054 } ngx_stream_log_buf_t;
0055 
0056 
0057 typedef struct {
0058     ngx_array_t                 *lengths;
0059     ngx_array_t                 *values;
0060 } ngx_stream_log_script_t;
0061 
0062 
0063 typedef struct {
0064     ngx_open_file_t             *file;
0065     ngx_stream_log_script_t     *script;
0066     time_t                       disk_full_time;
0067     time_t                       error_log_time;
0068     ngx_syslog_peer_t           *syslog_peer;
0069     ngx_stream_log_fmt_t        *format;
0070     ngx_stream_complex_value_t  *filter;
0071 } ngx_stream_log_t;
0072 
0073 
0074 typedef struct {
0075     ngx_array_t                 *logs;       /* array of ngx_stream_log_t */
0076 
0077     ngx_open_file_cache_t       *open_file_cache;
0078     time_t                       open_file_cache_valid;
0079     ngx_uint_t                   open_file_cache_min_uses;
0080 
0081     ngx_uint_t                   off;        /* unsigned  off:1 */
0082 } ngx_stream_log_srv_conf_t;
0083 
0084 
0085 typedef struct {
0086     ngx_str_t                    name;
0087     size_t                       len;
0088     ngx_stream_log_op_run_pt     run;
0089 } ngx_stream_log_var_t;
0090 
0091 
0092 static void ngx_stream_log_write(ngx_stream_session_t *s, ngx_stream_log_t *log,
0093     u_char *buf, size_t len);
0094 static ssize_t ngx_stream_log_script_write(ngx_stream_session_t *s,
0095     ngx_stream_log_script_t *script, u_char **name, u_char *buf, size_t len);
0096 
0097 #if (NGX_ZLIB)
0098 static ssize_t ngx_stream_log_gzip(ngx_fd_t fd, u_char *buf, size_t len,
0099     ngx_int_t level, ngx_log_t *log);
0100 
0101 static void *ngx_stream_log_gzip_alloc(void *opaque, u_int items, u_int size);
0102 static void ngx_stream_log_gzip_free(void *opaque, void *address);
0103 #endif
0104 
0105 static void ngx_stream_log_flush(ngx_open_file_t *file, ngx_log_t *log);
0106 static void ngx_stream_log_flush_handler(ngx_event_t *ev);
0107 
0108 static ngx_int_t ngx_stream_log_variable_compile(ngx_conf_t *cf,
0109     ngx_stream_log_op_t *op, ngx_str_t *value, ngx_uint_t json);
0110 static size_t ngx_stream_log_variable_getlen(ngx_stream_session_t *s,
0111     uintptr_t data);
0112 static u_char *ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf,
0113     ngx_stream_log_op_t *op);
0114 static uintptr_t ngx_stream_log_escape(u_char *dst, u_char *src, size_t size);
0115 static size_t ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s,
0116     uintptr_t data);
0117 static u_char *ngx_stream_log_json_variable(ngx_stream_session_t *s,
0118     u_char *buf, ngx_stream_log_op_t *op);
0119 
0120 
0121 static void *ngx_stream_log_create_main_conf(ngx_conf_t *cf);
0122 static void *ngx_stream_log_create_srv_conf(ngx_conf_t *cf);
0123 static char *ngx_stream_log_merge_srv_conf(ngx_conf_t *cf, void *parent,
0124     void *child);
0125 static char *ngx_stream_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
0126     void *conf);
0127 static char *ngx_stream_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
0128     void *conf);
0129 static char *ngx_stream_log_compile_format(ngx_conf_t *cf,
0130     ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
0131 static char *ngx_stream_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
0132     void *conf);
0133 static ngx_int_t ngx_stream_log_init(ngx_conf_t *cf);
0134 
0135 
0136 static ngx_command_t  ngx_stream_log_commands[] = {
0137 
0138     { ngx_string("log_format"),
0139       NGX_STREAM_MAIN_CONF|NGX_CONF_2MORE,
0140       ngx_stream_log_set_format,
0141       NGX_STREAM_MAIN_CONF_OFFSET,
0142       0,
0143       NULL },
0144 
0145     { ngx_string("access_log"),
0146       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
0147       ngx_stream_log_set_log,
0148       NGX_STREAM_SRV_CONF_OFFSET,
0149       0,
0150       NULL },
0151 
0152     { ngx_string("open_log_file_cache"),
0153       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1234,
0154       ngx_stream_log_open_file_cache,
0155       NGX_STREAM_SRV_CONF_OFFSET,
0156       0,
0157       NULL },
0158 
0159       ngx_null_command
0160 };
0161 
0162 
0163 static ngx_stream_module_t  ngx_stream_log_module_ctx = {
0164     NULL,                                  /* preconfiguration */
0165     ngx_stream_log_init,                   /* postconfiguration */
0166 
0167     ngx_stream_log_create_main_conf,       /* create main configuration */
0168     NULL,                                  /* init main configuration */
0169 
0170     ngx_stream_log_create_srv_conf,        /* create server configuration */
0171     ngx_stream_log_merge_srv_conf          /* merge server configuration */
0172 };
0173 
0174 
0175 ngx_module_t  ngx_stream_log_module = {
0176     NGX_MODULE_V1,
0177     &ngx_stream_log_module_ctx,            /* module context */
0178     ngx_stream_log_commands,               /* module directives */
0179     NGX_STREAM_MODULE,                     /* module type */
0180     NULL,                                  /* init master */
0181     NULL,                                  /* init module */
0182     NULL,                                  /* init process */
0183     NULL,                                  /* init thread */
0184     NULL,                                  /* exit thread */
0185     NULL,                                  /* exit process */
0186     NULL,                                  /* exit master */
0187     NGX_MODULE_V1_PADDING
0188 };
0189 
0190 
0191 static ngx_int_t
0192 ngx_stream_log_handler(ngx_stream_session_t *s)
0193 {
0194     u_char                     *line, *p;
0195     size_t                      len, size;
0196     ssize_t                     n;
0197     ngx_str_t                   val;
0198     ngx_uint_t                  i, l;
0199     ngx_stream_log_t           *log;
0200     ngx_stream_log_op_t        *op;
0201     ngx_stream_log_buf_t       *buffer;
0202     ngx_stream_log_srv_conf_t  *lscf;
0203 
0204     ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
0205                    "stream log handler");
0206 
0207     lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_log_module);
0208 
0209     if (lscf->off || lscf->logs == NULL) {
0210         return NGX_OK;
0211     }
0212 
0213     log = lscf->logs->elts;
0214     for (l = 0; l < lscf->logs->nelts; l++) {
0215 
0216         if (log[l].filter) {
0217             if (ngx_stream_complex_value(s, log[l].filter, &val) != NGX_OK) {
0218                 return NGX_ERROR;
0219             }
0220 
0221             if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) {
0222                 continue;
0223             }
0224         }
0225 
0226         if (ngx_time() == log[l].disk_full_time) {
0227 
0228             /*
0229              * on FreeBSD writing to a full filesystem with enabled softupdates
0230              * may block process for much longer time than writing to non-full
0231              * filesystem, so we skip writing to a log for one second
0232              */
0233 
0234             continue;
0235         }
0236 
0237         ngx_stream_script_flush_no_cacheable_variables(s,
0238                                                        log[l].format->flushes);
0239 
0240         len = 0;
0241         op = log[l].format->ops->elts;
0242         for (i = 0; i < log[l].format->ops->nelts; i++) {
0243             if (op[i].len == 0) {
0244                 len += op[i].getlen(s, op[i].data);
0245 
0246             } else {
0247                 len += op[i].len;
0248             }
0249         }
0250 
0251         if (log[l].syslog_peer) {
0252 
0253             /* length of syslog's PRI and HEADER message parts */
0254             len += sizeof("<255>Jan 01 00:00:00 ") - 1
0255                    + ngx_cycle->hostname.len + 1
0256                    + log[l].syslog_peer->tag.len + 2;
0257 
0258             goto alloc_line;
0259         }
0260 
0261         len += NGX_LINEFEED_SIZE;
0262 
0263         buffer = log[l].file ? log[l].file->data : NULL;
0264 
0265         if (buffer) {
0266 
0267             if (len > (size_t) (buffer->last - buffer->pos)) {
0268 
0269                 ngx_stream_log_write(s, &log[l], buffer->start,
0270                                      buffer->pos - buffer->start);
0271 
0272                 buffer->pos = buffer->start;
0273             }
0274 
0275             if (len <= (size_t) (buffer->last - buffer->pos)) {
0276 
0277                 p = buffer->pos;
0278 
0279                 if (buffer->event && p == buffer->start) {
0280                     ngx_add_timer(buffer->event, buffer->flush);
0281                 }
0282 
0283                 for (i = 0; i < log[l].format->ops->nelts; i++) {
0284                     p = op[i].run(s, p, &op[i]);
0285                 }
0286 
0287                 ngx_linefeed(p);
0288 
0289                 buffer->pos = p;
0290 
0291                 continue;
0292             }
0293 
0294             if (buffer->event && buffer->event->timer_set) {
0295                 ngx_del_timer(buffer->event);
0296             }
0297         }
0298 
0299     alloc_line:
0300 
0301         line = ngx_pnalloc(s->connection->pool, len);
0302         if (line == NULL) {
0303             return NGX_ERROR;
0304         }
0305 
0306         p = line;
0307 
0308         if (log[l].syslog_peer) {
0309             p = ngx_syslog_add_header(log[l].syslog_peer, line);
0310         }
0311 
0312         for (i = 0; i < log[l].format->ops->nelts; i++) {
0313             p = op[i].run(s, p, &op[i]);
0314         }
0315 
0316         if (log[l].syslog_peer) {
0317 
0318             size = p - line;
0319 
0320             n = ngx_syslog_send(log[l].syslog_peer, line, size);
0321 
0322             if (n < 0) {
0323                 ngx_log_error(NGX_LOG_WARN, s->connection->log, 0,
0324                               "send() to syslog failed");
0325 
0326             } else if ((size_t) n != size) {
0327                 ngx_log_error(NGX_LOG_WARN, s->connection->log, 0,
0328                               "send() to syslog has written only %z of %uz",
0329                               n, size);
0330             }
0331 
0332             continue;
0333         }
0334 
0335         ngx_linefeed(p);
0336 
0337         ngx_stream_log_write(s, &log[l], line, p - line);
0338     }
0339 
0340     return NGX_OK;
0341 }
0342 
0343 
0344 static void
0345 ngx_stream_log_write(ngx_stream_session_t *s, ngx_stream_log_t *log,
0346     u_char *buf, size_t len)
0347 {
0348     u_char                *name;
0349     time_t                 now;
0350     ssize_t                n;
0351     ngx_err_t              err;
0352 #if (NGX_ZLIB)
0353     ngx_stream_log_buf_t  *buffer;
0354 #endif
0355 
0356     if (log->script == NULL) {
0357         name = log->file->name.data;
0358 
0359 #if (NGX_ZLIB)
0360         buffer = log->file->data;
0361 
0362         if (buffer && buffer->gzip) {
0363             n = ngx_stream_log_gzip(log->file->fd, buf, len, buffer->gzip,
0364                                     s->connection->log);
0365         } else {
0366             n = ngx_write_fd(log->file->fd, buf, len);
0367         }
0368 #else
0369         n = ngx_write_fd(log->file->fd, buf, len);
0370 #endif
0371 
0372     } else {
0373         name = NULL;
0374         n = ngx_stream_log_script_write(s, log->script, &name, buf, len);
0375     }
0376 
0377     if (n == (ssize_t) len) {
0378         return;
0379     }
0380 
0381     now = ngx_time();
0382 
0383     if (n == -1) {
0384         err = ngx_errno;
0385 
0386         if (err == NGX_ENOSPC) {
0387             log->disk_full_time = now;
0388         }
0389 
0390         if (now - log->error_log_time > 59) {
0391             ngx_log_error(NGX_LOG_ALERT, s->connection->log, err,
0392                           ngx_write_fd_n " to \"%s\" failed", name);
0393 
0394             log->error_log_time = now;
0395         }
0396 
0397         return;
0398     }
0399 
0400     if (now - log->error_log_time > 59) {
0401         ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
0402                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
0403                       name, n, len);
0404 
0405         log->error_log_time = now;
0406     }
0407 }
0408 
0409 
0410 static ssize_t
0411 ngx_stream_log_script_write(ngx_stream_session_t *s,
0412     ngx_stream_log_script_t *script, u_char **name, u_char *buf, size_t len)
0413 {
0414     ssize_t                     n;
0415     ngx_str_t                   log;
0416     ngx_open_file_info_t        of;
0417     ngx_stream_log_srv_conf_t  *lscf;
0418 
0419     if (ngx_stream_script_run(s, &log, script->lengths->elts, 1,
0420                               script->values->elts)
0421         == NULL)
0422     {
0423         /* simulate successful logging */
0424         return len;
0425     }
0426 
0427     log.data[log.len - 1] = '\0';
0428     *name = log.data;
0429 
0430     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
0431                    "stream log \"%s\"", log.data);
0432 
0433     lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_log_module);
0434 
0435     ngx_memzero(&of, sizeof(ngx_open_file_info_t));
0436 
0437     of.log = 1;
0438     of.valid = lscf->open_file_cache_valid;
0439     of.min_uses = lscf->open_file_cache_min_uses;
0440     of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
0441 
0442     if (ngx_open_cached_file(lscf->open_file_cache, &log, &of,
0443                              s->connection->pool)
0444         != NGX_OK)
0445     {
0446         if (of.err == 0) {
0447             /* simulate successful logging */
0448             return len;
0449         }
0450 
0451         ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno,
0452                       "%s \"%s\" failed", of.failed, log.data);
0453         /* simulate successful logging */
0454         return len;
0455     }
0456 
0457     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
0458                    "stream log #%d", of.fd);
0459 
0460     n = ngx_write_fd(of.fd, buf, len);
0461 
0462     return n;
0463 }
0464 
0465 
0466 #if (NGX_ZLIB)
0467 
0468 static ssize_t
0469 ngx_stream_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,
0470     ngx_log_t *log)
0471 {
0472     int          rc, wbits, memlevel;
0473     u_char      *out;
0474     size_t       size;
0475     ssize_t      n;
0476     z_stream     zstream;
0477     ngx_err_t    err;
0478     ngx_pool_t  *pool;
0479 
0480     wbits = MAX_WBITS;
0481     memlevel = MAX_MEM_LEVEL - 1;
0482 
0483     while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) {
0484         wbits--;
0485         memlevel--;
0486     }
0487 
0488     /*
0489      * This is a formula from deflateBound() for conservative upper bound of
0490      * compressed data plus 18 bytes of gzip wrapper.
0491      */
0492 
0493     size = len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5 + 18;
0494 
0495     ngx_memzero(&zstream, sizeof(z_stream));
0496 
0497     pool = ngx_create_pool(256, log);
0498     if (pool == NULL) {
0499         /* simulate successful logging */
0500         return len;
0501     }
0502 
0503     pool->log = log;
0504 
0505     zstream.zalloc = ngx_stream_log_gzip_alloc;
0506     zstream.zfree = ngx_stream_log_gzip_free;
0507     zstream.opaque = pool;
0508 
0509     out = ngx_pnalloc(pool, size);
0510     if (out == NULL) {
0511         goto done;
0512     }
0513 
0514     zstream.next_in = buf;
0515     zstream.avail_in = len;
0516     zstream.next_out = out;
0517     zstream.avail_out = size;
0518 
0519     rc = deflateInit2(&zstream, (int) level, Z_DEFLATED, wbits + 16, memlevel,
0520                       Z_DEFAULT_STRATEGY);
0521 
0522     if (rc != Z_OK) {
0523         ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateInit2() failed: %d", rc);
0524         goto done;
0525     }
0526 
0527     ngx_log_debug4(NGX_LOG_DEBUG_STREAM, log, 0,
0528                    "deflate in: ni:%p no:%p ai:%ud ao:%ud",
0529                    zstream.next_in, zstream.next_out,
0530                    zstream.avail_in, zstream.avail_out);
0531 
0532     rc = deflate(&zstream, Z_FINISH);
0533 
0534     if (rc != Z_STREAM_END) {
0535         ngx_log_error(NGX_LOG_ALERT, log, 0,
0536                       "deflate(Z_FINISH) failed: %d", rc);
0537         goto done;
0538     }
0539 
0540     ngx_log_debug5(NGX_LOG_DEBUG_STREAM, log, 0,
0541                    "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
0542                    zstream.next_in, zstream.next_out,
0543                    zstream.avail_in, zstream.avail_out,
0544                    rc);
0545 
0546     size -= zstream.avail_out;
0547 
0548     rc = deflateEnd(&zstream);
0549 
0550     if (rc != Z_OK) {
0551         ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc);
0552         goto done;
0553     }
0554 
0555     n = ngx_write_fd(fd, out, size);
0556 
0557     if (n != (ssize_t) size) {
0558         err = (n == -1) ? ngx_errno : 0;
0559 
0560         ngx_destroy_pool(pool);
0561 
0562         ngx_set_errno(err);
0563         return -1;
0564     }
0565 
0566 done:
0567 
0568     ngx_destroy_pool(pool);
0569 
0570     /* simulate successful logging */
0571     return len;
0572 }
0573 
0574 
0575 static void *
0576 ngx_stream_log_gzip_alloc(void *opaque, u_int items, u_int size)
0577 {
0578     ngx_pool_t *pool = opaque;
0579 
0580     ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pool->log, 0,
0581                    "gzip alloc: n:%ud s:%ud", items, size);
0582 
0583     return ngx_palloc(pool, items * size);
0584 }
0585 
0586 
0587 static void
0588 ngx_stream_log_gzip_free(void *opaque, void *address)
0589 {
0590 #if 0
0591     ngx_pool_t *pool = opaque;
0592 
0593     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pool->log, 0,
0594                    "gzip free: %p", address);
0595 #endif
0596 }
0597 
0598 #endif
0599 
0600 
0601 static void
0602 ngx_stream_log_flush(ngx_open_file_t *file, ngx_log_t *log)
0603 {
0604     size_t                 len;
0605     ssize_t                n;
0606     ngx_stream_log_buf_t  *buffer;
0607 
0608     buffer = file->data;
0609 
0610     len = buffer->pos - buffer->start;
0611 
0612     if (len == 0) {
0613         return;
0614     }
0615 
0616 #if (NGX_ZLIB)
0617     if (buffer->gzip) {
0618         n = ngx_stream_log_gzip(file->fd, buffer->start, len, buffer->gzip,
0619                                 log);
0620     } else {
0621         n = ngx_write_fd(file->fd, buffer->start, len);
0622     }
0623 #else
0624     n = ngx_write_fd(file->fd, buffer->start, len);
0625 #endif
0626 
0627     if (n == -1) {
0628         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
0629                       ngx_write_fd_n " to \"%s\" failed",
0630                       file->name.data);
0631 
0632     } else if ((size_t) n != len) {
0633         ngx_log_error(NGX_LOG_ALERT, log, 0,
0634                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
0635                       file->name.data, n, len);
0636     }
0637 
0638     buffer->pos = buffer->start;
0639 
0640     if (buffer->event && buffer->event->timer_set) {
0641         ngx_del_timer(buffer->event);
0642     }
0643 }
0644 
0645 
0646 static void
0647 ngx_stream_log_flush_handler(ngx_event_t *ev)
0648 {
0649     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
0650                    "stream log buffer flush handler");
0651 
0652     ngx_stream_log_flush(ev->data, ev->log);
0653 }
0654 
0655 
0656 static u_char *
0657 ngx_stream_log_copy_short(ngx_stream_session_t *s, u_char *buf,
0658     ngx_stream_log_op_t *op)
0659 {
0660     size_t     len;
0661     uintptr_t  data;
0662 
0663     len = op->len;
0664     data = op->data;
0665 
0666     while (len--) {
0667         *buf++ = (u_char) (data & 0xff);
0668         data >>= 8;
0669     }
0670 
0671     return buf;
0672 }
0673 
0674 
0675 static u_char *
0676 ngx_stream_log_copy_long(ngx_stream_session_t *s, u_char *buf,
0677     ngx_stream_log_op_t *op)
0678 {
0679     return ngx_cpymem(buf, (u_char *) op->data, op->len);
0680 }
0681 
0682 
0683 static ngx_int_t
0684 ngx_stream_log_variable_compile(ngx_conf_t *cf, ngx_stream_log_op_t *op,
0685     ngx_str_t *value, ngx_uint_t json)
0686 {
0687     ngx_int_t  index;
0688 
0689     index = ngx_stream_get_variable_index(cf, value);
0690     if (index == NGX_ERROR) {
0691         return NGX_ERROR;
0692     }
0693 
0694     op->len = 0;
0695 
0696     if (json) {
0697         op->getlen = ngx_stream_log_json_variable_getlen;
0698         op->run = ngx_stream_log_json_variable;
0699 
0700     } else {
0701         op->getlen = ngx_stream_log_variable_getlen;
0702         op->run = ngx_stream_log_variable;
0703     }
0704 
0705     op->data = index;
0706 
0707     return NGX_OK;
0708 }
0709 
0710 
0711 static size_t
0712 ngx_stream_log_variable_getlen(ngx_stream_session_t *s, uintptr_t data)
0713 {
0714     uintptr_t                     len;
0715     ngx_stream_variable_value_t  *value;
0716 
0717     value = ngx_stream_get_indexed_variable(s, data);
0718 
0719     if (value == NULL || value->not_found) {
0720         return 1;
0721     }
0722 
0723     len = ngx_stream_log_escape(NULL, value->data, value->len);
0724 
0725     value->escape = len ? 1 : 0;
0726 
0727     return value->len + len * 3;
0728 }
0729 
0730 
0731 static u_char *
0732 ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf,
0733     ngx_stream_log_op_t *op)
0734 {
0735     ngx_stream_variable_value_t  *value;
0736 
0737     value = ngx_stream_get_indexed_variable(s, op->data);
0738 
0739     if (value == NULL || value->not_found) {
0740         *buf = '-';
0741         return buf + 1;
0742     }
0743 
0744     if (value->escape == 0) {
0745         return ngx_cpymem(buf, value->data, value->len);
0746 
0747     } else {
0748         return (u_char *) ngx_stream_log_escape(buf, value->data, value->len);
0749     }
0750 }
0751 
0752 
0753 static uintptr_t
0754 ngx_stream_log_escape(u_char *dst, u_char *src, size_t size)
0755 {
0756     ngx_uint_t      n;
0757     static u_char   hex[] = "0123456789ABCDEF";
0758 
0759     static uint32_t   escape[] = {
0760         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
0761 
0762                     /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
0763         0x00000004, /* 0000 0000 0000 0000  0000 0000 0000 0100 */
0764 
0765                     /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
0766         0x10000000, /* 0001 0000 0000 0000  0000 0000 0000 0000 */
0767 
0768                     /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
0769         0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */
0770 
0771         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
0772         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
0773         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
0774         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
0775     };
0776 
0777 
0778     if (dst == NULL) {
0779 
0780         /* find the number of the characters to be escaped */
0781 
0782         n = 0;
0783 
0784         while (size) {
0785             if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
0786                 n++;
0787             }
0788             src++;
0789             size--;
0790         }
0791 
0792         return (uintptr_t) n;
0793     }
0794 
0795     while (size) {
0796         if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
0797             *dst++ = '\\';
0798             *dst++ = 'x';
0799             *dst++ = hex[*src >> 4];
0800             *dst++ = hex[*src & 0xf];
0801             src++;
0802 
0803         } else {
0804             *dst++ = *src++;
0805         }
0806         size--;
0807     }
0808 
0809     return (uintptr_t) dst;
0810 }
0811 
0812 
0813 static size_t
0814 ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s, uintptr_t data)
0815 {
0816     uintptr_t                     len;
0817     ngx_stream_variable_value_t  *value;
0818 
0819     value = ngx_stream_get_indexed_variable(s, data);
0820 
0821     if (value == NULL || value->not_found) {
0822         return 0;
0823     }
0824 
0825     len = ngx_escape_json(NULL, value->data, value->len);
0826 
0827     value->escape = len ? 1 : 0;
0828 
0829     return value->len + len;
0830 }
0831 
0832 
0833 static u_char *
0834 ngx_stream_log_json_variable(ngx_stream_session_t *s, u_char *buf,
0835     ngx_stream_log_op_t *op)
0836 {
0837     ngx_stream_variable_value_t  *value;
0838 
0839     value = ngx_stream_get_indexed_variable(s, op->data);
0840 
0841     if (value == NULL || value->not_found) {
0842         return buf;
0843     }
0844 
0845     if (value->escape == 0) {
0846         return ngx_cpymem(buf, value->data, value->len);
0847 
0848     } else {
0849         return (u_char *) ngx_escape_json(buf, value->data, value->len);
0850     }
0851 }
0852 
0853 
0854 static void *
0855 ngx_stream_log_create_main_conf(ngx_conf_t *cf)
0856 {
0857     ngx_stream_log_main_conf_t  *conf;
0858 
0859     conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_main_conf_t));
0860     if (conf == NULL) {
0861         return NULL;
0862     }
0863 
0864     if (ngx_array_init(&conf->formats, cf->pool, 4,
0865                        sizeof(ngx_stream_log_fmt_t))
0866         != NGX_OK)
0867     {
0868         return NULL;
0869     }
0870 
0871     return conf;
0872 }
0873 
0874 
0875 static void *
0876 ngx_stream_log_create_srv_conf(ngx_conf_t *cf)
0877 {
0878     ngx_stream_log_srv_conf_t  *conf;
0879 
0880     conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_srv_conf_t));
0881     if (conf == NULL) {
0882         return NULL;
0883     }
0884 
0885     conf->open_file_cache = NGX_CONF_UNSET_PTR;
0886 
0887     return conf;
0888 }
0889 
0890 
0891 static char *
0892 ngx_stream_log_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
0893 {
0894     ngx_stream_log_srv_conf_t *prev = parent;
0895     ngx_stream_log_srv_conf_t *conf = child;
0896 
0897     if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
0898 
0899         conf->open_file_cache = prev->open_file_cache;
0900         conf->open_file_cache_valid = prev->open_file_cache_valid;
0901         conf->open_file_cache_min_uses = prev->open_file_cache_min_uses;
0902 
0903         if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
0904             conf->open_file_cache = NULL;
0905         }
0906     }
0907 
0908     if (conf->logs || conf->off) {
0909         return NGX_CONF_OK;
0910     }
0911 
0912     conf->logs = prev->logs;
0913     conf->off = prev->off;
0914 
0915     return NGX_CONF_OK;
0916 }
0917 
0918 
0919 static char *
0920 ngx_stream_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0921 {
0922     ngx_stream_log_srv_conf_t *lscf = conf;
0923 
0924     ssize_t                              size;
0925     ngx_int_t                            gzip;
0926     ngx_uint_t                           i, n;
0927     ngx_msec_t                           flush;
0928     ngx_str_t                           *value, name, s;
0929     ngx_stream_log_t                    *log;
0930     ngx_syslog_peer_t                   *peer;
0931     ngx_stream_log_buf_t                *buffer;
0932     ngx_stream_log_fmt_t                *fmt;
0933     ngx_stream_script_compile_t          sc;
0934     ngx_stream_log_main_conf_t          *lmcf;
0935     ngx_stream_compile_complex_value_t   ccv;
0936 
0937     value = cf->args->elts;
0938 
0939     if (ngx_strcmp(value[1].data, "off") == 0) {
0940         lscf->off = 1;
0941         if (cf->args->nelts == 2) {
0942             return NGX_CONF_OK;
0943         }
0944 
0945         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0946                            "invalid parameter \"%V\"", &value[2]);
0947         return NGX_CONF_ERROR;
0948     }
0949 
0950     if (lscf->logs == NULL) {
0951         lscf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_stream_log_t));
0952         if (lscf->logs == NULL) {
0953             return NGX_CONF_ERROR;
0954         }
0955     }
0956 
0957     lmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_log_module);
0958 
0959     log = ngx_array_push(lscf->logs);
0960     if (log == NULL) {
0961         return NGX_CONF_ERROR;
0962     }
0963 
0964     ngx_memzero(log, sizeof(ngx_stream_log_t));
0965 
0966 
0967     if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {
0968 
0969         peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
0970         if (peer == NULL) {
0971             return NGX_CONF_ERROR;
0972         }
0973 
0974         if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
0975             return NGX_CONF_ERROR;
0976         }
0977 
0978         log->syslog_peer = peer;
0979 
0980         goto process_formats;
0981     }
0982 
0983     n = ngx_stream_script_variables_count(&value[1]);
0984 
0985     if (n == 0) {
0986         log->file = ngx_conf_open_file(cf->cycle, &value[1]);
0987         if (log->file == NULL) {
0988             return NGX_CONF_ERROR;
0989         }
0990 
0991     } else {
0992         if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
0993             return NGX_CONF_ERROR;
0994         }
0995 
0996         log->script = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_script_t));
0997         if (log->script == NULL) {
0998             return NGX_CONF_ERROR;
0999         }
1000 
1001         ngx_memzero(&sc, sizeof(ngx_stream_script_compile_t));
1002 
1003         sc.cf = cf;
1004         sc.source = &value[1];
1005         sc.lengths = &log->script->lengths;
1006         sc.values = &log->script->values;
1007         sc.variables = n;
1008         sc.complete_lengths = 1;
1009         sc.complete_values = 1;
1010 
1011         if (ngx_stream_script_compile(&sc) != NGX_OK) {
1012             return NGX_CONF_ERROR;
1013         }
1014     }
1015 
1016 process_formats:
1017 
1018     if (cf->args->nelts >= 3) {
1019         name = value[2];
1020 
1021     } else {
1022         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1023                            "log format is not specified");
1024         return NGX_CONF_ERROR;
1025     }
1026 
1027     fmt = lmcf->formats.elts;
1028     for (i = 0; i < lmcf->formats.nelts; i++) {
1029         if (fmt[i].name.len == name.len
1030             && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
1031         {
1032             log->format = &fmt[i];
1033             break;
1034         }
1035     }
1036 
1037     if (log->format == NULL) {
1038         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1039                            "unknown log format \"%V\"", &name);
1040         return NGX_CONF_ERROR;
1041     }
1042 
1043     size = 0;
1044     flush = 0;
1045     gzip = 0;
1046 
1047     for (i = 3; i < cf->args->nelts; i++) {
1048 
1049         if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
1050             s.len = value[i].len - 7;
1051             s.data = value[i].data + 7;
1052 
1053             size = ngx_parse_size(&s);
1054 
1055             if (size == NGX_ERROR || size == 0) {
1056                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1057                                    "invalid buffer size \"%V\"", &s);
1058                 return NGX_CONF_ERROR;
1059             }
1060 
1061             continue;
1062         }
1063 
1064         if (ngx_strncmp(value[i].data, "flush=", 6) == 0) {
1065             s.len = value[i].len - 6;
1066             s.data = value[i].data + 6;
1067 
1068             flush = ngx_parse_time(&s, 0);
1069 
1070             if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) {
1071                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1072                                    "invalid flush time \"%V\"", &s);
1073                 return NGX_CONF_ERROR;
1074             }
1075 
1076             continue;
1077         }
1078 
1079         if (ngx_strncmp(value[i].data, "gzip", 4) == 0
1080             && (value[i].len == 4 || value[i].data[4] == '='))
1081         {
1082 #if (NGX_ZLIB)
1083             if (size == 0) {
1084                 size = 64 * 1024;
1085             }
1086 
1087             if (value[i].len == 4) {
1088                 gzip = Z_BEST_SPEED;
1089                 continue;
1090             }
1091 
1092             s.len = value[i].len - 5;
1093             s.data = value[i].data + 5;
1094 
1095             gzip = ngx_atoi(s.data, s.len);
1096 
1097             if (gzip < 1 || gzip > 9) {
1098                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1099                                    "invalid compression level \"%V\"", &s);
1100                 return NGX_CONF_ERROR;
1101             }
1102 
1103             continue;
1104 
1105 #else
1106             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1107                                "nginx was built without zlib support");
1108             return NGX_CONF_ERROR;
1109 #endif
1110         }
1111 
1112         if (ngx_strncmp(value[i].data, "if=", 3) == 0) {
1113             s.len = value[i].len - 3;
1114             s.data = value[i].data + 3;
1115 
1116             ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
1117 
1118             ccv.cf = cf;
1119             ccv.value = &s;
1120             ccv.complex_value = ngx_palloc(cf->pool,
1121                                            sizeof(ngx_stream_complex_value_t));
1122             if (ccv.complex_value == NULL) {
1123                 return NGX_CONF_ERROR;
1124             }
1125 
1126             if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
1127                 return NGX_CONF_ERROR;
1128             }
1129 
1130             log->filter = ccv.complex_value;
1131 
1132             continue;
1133         }
1134 
1135         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1136                            "invalid parameter \"%V\"", &value[i]);
1137         return NGX_CONF_ERROR;
1138     }
1139 
1140     if (flush && size == 0) {
1141         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1142                            "no buffer is defined for access_log \"%V\"",
1143                            &value[1]);
1144         return NGX_CONF_ERROR;
1145     }
1146 
1147     if (size) {
1148 
1149         if (log->script) {
1150             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1151                                "buffered logs cannot have variables in name");
1152             return NGX_CONF_ERROR;
1153         }
1154 
1155         if (log->syslog_peer) {
1156             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1157                                "logs to syslog cannot be buffered");
1158             return NGX_CONF_ERROR;
1159         }
1160 
1161         if (log->file->data) {
1162             buffer = log->file->data;
1163 
1164             if (buffer->last - buffer->start != size
1165                 || buffer->flush != flush
1166                 || buffer->gzip != gzip)
1167             {
1168                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1169                                    "access_log \"%V\" already defined "
1170                                    "with conflicting parameters",
1171                                    &value[1]);
1172                 return NGX_CONF_ERROR;
1173             }
1174 
1175             return NGX_CONF_OK;
1176         }
1177 
1178         buffer = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_buf_t));
1179         if (buffer == NULL) {
1180             return NGX_CONF_ERROR;
1181         }
1182 
1183         buffer->start = ngx_pnalloc(cf->pool, size);
1184         if (buffer->start == NULL) {
1185             return NGX_CONF_ERROR;
1186         }
1187 
1188         buffer->pos = buffer->start;
1189         buffer->last = buffer->start + size;
1190 
1191         if (flush) {
1192             buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
1193             if (buffer->event == NULL) {
1194                 return NGX_CONF_ERROR;
1195             }
1196 
1197             buffer->event->data = log->file;
1198             buffer->event->handler = ngx_stream_log_flush_handler;
1199             buffer->event->log = &cf->cycle->new_log;
1200             buffer->event->cancelable = 1;
1201 
1202             buffer->flush = flush;
1203         }
1204 
1205         buffer->gzip = gzip;
1206 
1207         log->file->flush = ngx_stream_log_flush;
1208         log->file->data = buffer;
1209     }
1210 
1211     return NGX_CONF_OK;
1212 }
1213 
1214 
1215 static char *
1216 ngx_stream_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1217 {
1218     ngx_stream_log_main_conf_t *lmcf = conf;
1219 
1220     ngx_str_t             *value;
1221     ngx_uint_t             i;
1222     ngx_stream_log_fmt_t  *fmt;
1223 
1224     value = cf->args->elts;
1225 
1226     fmt = lmcf->formats.elts;
1227     for (i = 0; i < lmcf->formats.nelts; i++) {
1228         if (fmt[i].name.len == value[1].len
1229             && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
1230         {
1231             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1232                                "duplicate \"log_format\" name \"%V\"",
1233                                &value[1]);
1234             return NGX_CONF_ERROR;
1235         }
1236     }
1237 
1238     fmt = ngx_array_push(&lmcf->formats);
1239     if (fmt == NULL) {
1240         return NGX_CONF_ERROR;
1241     }
1242 
1243     fmt->name = value[1];
1244 
1245     fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
1246     if (fmt->flushes == NULL) {
1247         return NGX_CONF_ERROR;
1248     }
1249 
1250     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_stream_log_op_t));
1251     if (fmt->ops == NULL) {
1252         return NGX_CONF_ERROR;
1253     }
1254 
1255     return ngx_stream_log_compile_format(cf, fmt->flushes, fmt->ops,
1256                                          cf->args, 2);
1257 }
1258 
1259 
1260 static char *
1261 ngx_stream_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
1262     ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
1263 {
1264     u_char                *data, *p, ch;
1265     size_t                 i, len;
1266     ngx_str_t             *value, var;
1267     ngx_int_t             *flush;
1268     ngx_uint_t             bracket, json;
1269     ngx_stream_log_op_t   *op;
1270 
1271     json = 0;
1272     value = args->elts;
1273 
1274     if (s < args->nelts && ngx_strncmp(value[s].data, "escape=", 7) == 0) {
1275         data = value[s].data + 7;
1276 
1277         if (ngx_strcmp(data, "json") == 0) {
1278             json = 1;
1279 
1280         } else if (ngx_strcmp(data, "default") != 0) {
1281             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1282                                "unknown log format escaping \"%s\"", data);
1283             return NGX_CONF_ERROR;
1284         }
1285 
1286         s++;
1287     }
1288 
1289     for ( /* void */ ; s < args->nelts; s++) {
1290 
1291         i = 0;
1292 
1293         while (i < value[s].len) {
1294 
1295             op = ngx_array_push(ops);
1296             if (op == NULL) {
1297                 return NGX_CONF_ERROR;
1298             }
1299 
1300             data = &value[s].data[i];
1301 
1302             if (value[s].data[i] == '$') {
1303 
1304                 if (++i == value[s].len) {
1305                     goto invalid;
1306                 }
1307 
1308                 if (value[s].data[i] == '{') {
1309                     bracket = 1;
1310 
1311                     if (++i == value[s].len) {
1312                         goto invalid;
1313                     }
1314 
1315                     var.data = &value[s].data[i];
1316 
1317                 } else {
1318                     bracket = 0;
1319                     var.data = &value[s].data[i];
1320                 }
1321 
1322                 for (var.len = 0; i < value[s].len; i++, var.len++) {
1323                     ch = value[s].data[i];
1324 
1325                     if (ch == '}' && bracket) {
1326                         i++;
1327                         bracket = 0;
1328                         break;
1329                     }
1330 
1331                     if ((ch >= 'A' && ch <= 'Z')
1332                         || (ch >= 'a' && ch <= 'z')
1333                         || (ch >= '0' && ch <= '9')
1334                         || ch == '_')
1335                     {
1336                         continue;
1337                     }
1338 
1339                     break;
1340                 }
1341 
1342                 if (bracket) {
1343                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1344                                        "the closing bracket in \"%V\" "
1345                                        "variable is missing", &var);
1346                     return NGX_CONF_ERROR;
1347                 }
1348 
1349                 if (var.len == 0) {
1350                     goto invalid;
1351                 }
1352 
1353                 if (ngx_stream_log_variable_compile(cf, op, &var, json)
1354                     != NGX_OK)
1355                 {
1356                     return NGX_CONF_ERROR;
1357                 }
1358 
1359                 if (flushes) {
1360 
1361                     flush = ngx_array_push(flushes);
1362                     if (flush == NULL) {
1363                         return NGX_CONF_ERROR;
1364                     }
1365 
1366                     *flush = op->data; /* variable index */
1367                 }
1368 
1369                 continue;
1370             }
1371 
1372             i++;
1373 
1374             while (i < value[s].len && value[s].data[i] != '$') {
1375                 i++;
1376             }
1377 
1378             len = &value[s].data[i] - data;
1379 
1380             if (len) {
1381 
1382                 op->len = len;
1383                 op->getlen = NULL;
1384 
1385                 if (len <= sizeof(uintptr_t)) {
1386                     op->run = ngx_stream_log_copy_short;
1387                     op->data = 0;
1388 
1389                     while (len--) {
1390                         op->data <<= 8;
1391                         op->data |= data[len];
1392                     }
1393 
1394                 } else {
1395                     op->run = ngx_stream_log_copy_long;
1396 
1397                     p = ngx_pnalloc(cf->pool, len);
1398                     if (p == NULL) {
1399                         return NGX_CONF_ERROR;
1400                     }
1401 
1402                     ngx_memcpy(p, data, len);
1403                     op->data = (uintptr_t) p;
1404                 }
1405             }
1406         }
1407     }
1408 
1409     return NGX_CONF_OK;
1410 
1411 invalid:
1412 
1413     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);
1414 
1415     return NGX_CONF_ERROR;
1416 }
1417 
1418 
1419 static char *
1420 ngx_stream_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1421 {
1422     ngx_stream_log_srv_conf_t *lscf = conf;
1423 
1424     time_t       inactive, valid;
1425     ngx_str_t   *value, s;
1426     ngx_int_t    max, min_uses;
1427     ngx_uint_t   i;
1428 
1429     if (lscf->open_file_cache != NGX_CONF_UNSET_PTR) {
1430         return "is duplicate";
1431     }
1432 
1433     value = cf->args->elts;
1434 
1435     max = 0;
1436     inactive = 10;
1437     valid = 60;
1438     min_uses = 1;
1439 
1440     for (i = 1; i < cf->args->nelts; i++) {
1441 
1442         if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
1443 
1444             max = ngx_atoi(value[i].data + 4, value[i].len - 4);
1445             if (max == NGX_ERROR) {
1446                 goto failed;
1447             }
1448 
1449             continue;
1450         }
1451 
1452         if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
1453 
1454             s.len = value[i].len - 9;
1455             s.data = value[i].data + 9;
1456 
1457             inactive = ngx_parse_time(&s, 1);
1458             if (inactive == (time_t) NGX_ERROR) {
1459                 goto failed;
1460             }
1461 
1462             continue;
1463         }
1464 
1465         if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) {
1466 
1467             min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
1468             if (min_uses == NGX_ERROR) {
1469                 goto failed;
1470             }
1471 
1472             continue;
1473         }
1474 
1475         if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
1476 
1477             s.len = value[i].len - 6;
1478             s.data = value[i].data + 6;
1479 
1480             valid = ngx_parse_time(&s, 1);
1481             if (valid == (time_t) NGX_ERROR) {
1482                 goto failed;
1483             }
1484 
1485             continue;
1486         }
1487 
1488         if (ngx_strcmp(value[i].data, "off") == 0) {
1489 
1490             lscf->open_file_cache = NULL;
1491 
1492             continue;
1493         }
1494 
1495     failed:
1496 
1497         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1498                            "invalid \"open_log_file_cache\" parameter \"%V\"",
1499                            &value[i]);
1500         return NGX_CONF_ERROR;
1501     }
1502 
1503     if (lscf->open_file_cache == NULL) {
1504         return NGX_CONF_OK;
1505     }
1506 
1507     if (max == 0) {
1508         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1509                         "\"open_log_file_cache\" must have \"max\" parameter");
1510         return NGX_CONF_ERROR;
1511     }
1512 
1513     lscf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
1514 
1515     if (lscf->open_file_cache) {
1516 
1517         lscf->open_file_cache_valid = valid;
1518         lscf->open_file_cache_min_uses = min_uses;
1519 
1520         return NGX_CONF_OK;
1521     }
1522 
1523     return NGX_CONF_ERROR;
1524 }
1525 
1526 
1527 static ngx_int_t
1528 ngx_stream_log_init(ngx_conf_t *cf)
1529 {
1530     ngx_stream_handler_pt        *h;
1531     ngx_stream_core_main_conf_t  *cmcf;
1532 
1533     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
1534 
1535     h = ngx_array_push(&cmcf->phases[NGX_STREAM_LOG_PHASE].handlers);
1536     if (h == NULL) {
1537         return NGX_ERROR;
1538     }
1539 
1540     *h = ngx_stream_log_handler;
1541 
1542     return NGX_OK;
1543 }