src/http/modules/ngx_http_log_module.c - nginx source code

Global variables defined

Data types defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>

  8. #if (NGX_ZLIB)
  9. #include <zlib.h>
  10. #endif


  11. typedef struct ngx_http_log_op_s  ngx_http_log_op_t;

  12. typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf,
  13.     ngx_http_log_op_t *op);

  14. typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r,
  15.     uintptr_t data);


  16. struct ngx_http_log_op_s {
  17.     size_t                      len;
  18.     ngx_http_log_op_getlen_pt   getlen;
  19.     ngx_http_log_op_run_pt      run;
  20.     uintptr_t                   data;
  21. };


  22. typedef struct {
  23.     ngx_str_t                   name;
  24.     ngx_array_t                *flushes;
  25.     ngx_array_t                *ops;        /* array of ngx_http_log_op_t */
  26. } ngx_http_log_fmt_t;


  27. typedef struct {
  28.     ngx_array_t                 formats;    /* array of ngx_http_log_fmt_t */
  29.     ngx_uint_t                  combined_used; /* unsigned  combined_used:1 */
  30. } ngx_http_log_main_conf_t;


  31. typedef struct {
  32.     u_char                     *start;
  33.     u_char                     *pos;
  34.     u_char                     *last;

  35.     ngx_event_t                *event;
  36.     ngx_msec_t                  flush;
  37.     ngx_int_t                   gzip;
  38. } ngx_http_log_buf_t;


  39. typedef struct {
  40.     ngx_array_t                *lengths;
  41.     ngx_array_t                *values;
  42. } ngx_http_log_script_t;


  43. typedef struct {
  44.     ngx_open_file_t            *file;
  45.     ngx_http_log_script_t      *script;
  46.     time_t                      disk_full_time;
  47.     time_t                      error_log_time;
  48.     ngx_syslog_peer_t          *syslog_peer;
  49.     ngx_http_log_fmt_t         *format;
  50.     ngx_http_complex_value_t   *filter;
  51. } ngx_http_log_t;


  52. typedef struct {
  53.     ngx_array_t                *logs;       /* array of ngx_http_log_t */

  54.     ngx_open_file_cache_t      *open_file_cache;
  55.     time_t                      open_file_cache_valid;
  56.     ngx_uint_t                  open_file_cache_min_uses;

  57.     ngx_uint_t                  off;        /* unsigned  off:1 */
  58. } ngx_http_log_loc_conf_t;


  59. typedef struct {
  60.     ngx_str_t                   name;
  61.     size_t                      len;
  62.     ngx_http_log_op_run_pt      run;
  63. } ngx_http_log_var_t;


  64. #define NGX_HTTP_LOG_ESCAPE_DEFAULT  0
  65. #define NGX_HTTP_LOG_ESCAPE_JSON     1
  66. #define NGX_HTTP_LOG_ESCAPE_NONE     2


  67. static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
  68.     u_char *buf, size_t len);
  69. static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
  70.     ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len);

  71. #if (NGX_ZLIB)
  72. static ssize_t ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len,
  73.     ngx_int_t level, ngx_log_t *log);

  74. static void *ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size);
  75. static void ngx_http_log_gzip_free(void *opaque, void *address);
  76. #endif

  77. static void ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log);
  78. static void ngx_http_log_flush_handler(ngx_event_t *ev);

  79. static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
  80.     ngx_http_log_op_t *op);
  81. static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
  82.     ngx_http_log_op_t *op);
  83. static u_char *ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf,
  84.     ngx_http_log_op_t *op);
  85. static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
  86.     ngx_http_log_op_t *op);
  87. static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
  88.     ngx_http_log_op_t *op);
  89. static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf,
  90.     ngx_http_log_op_t *op);
  91. static u_char *ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
  92.     ngx_http_log_op_t *op);
  93. static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r,
  94.     u_char *buf, ngx_http_log_op_t *op);
  95. static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
  96.     ngx_http_log_op_t *op);

  97. static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
  98.     ngx_http_log_op_t *op, ngx_str_t *value, ngx_uint_t escape);
  99. static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
  100.     uintptr_t data);
  101. static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
  102.     ngx_http_log_op_t *op);
  103. static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size);
  104. static size_t ngx_http_log_json_variable_getlen(ngx_http_request_t *r,
  105.     uintptr_t data);
  106. static u_char *ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf,
  107.     ngx_http_log_op_t *op);
  108. static size_t ngx_http_log_unescaped_variable_getlen(ngx_http_request_t *r,
  109.     uintptr_t data);
  110. static u_char *ngx_http_log_unescaped_variable(ngx_http_request_t *r,
  111.     u_char *buf, ngx_http_log_op_t *op);


  112. static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
  113. static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf);
  114. static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
  115.     void *child);
  116. static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
  117.     void *conf);
  118. static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
  119.     void *conf);
  120. static char *ngx_http_log_compile_format(ngx_conf_t *cf,
  121.     ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
  122. static char *ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
  123.     void *conf);
  124. static ngx_int_t ngx_http_log_init(ngx_conf_t *cf);


  125. static ngx_command_t  ngx_http_log_commands[] = {

  126.     { ngx_string("log_format"),
  127.       NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
  128.       ngx_http_log_set_format,
  129.       NGX_HTTP_MAIN_CONF_OFFSET,
  130.       0,
  131.       NULL },

  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_1MORE,
  135.       ngx_http_log_set_log,
  136.       NGX_HTTP_LOC_CONF_OFFSET,
  137.       0,
  138.       NULL },

  139.     { ngx_string("open_log_file_cache"),
  140.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
  141.       ngx_http_log_open_file_cache,
  142.       NGX_HTTP_LOC_CONF_OFFSET,
  143.       0,
  144.       NULL },

  145.       ngx_null_command
  146. };


  147. static ngx_http_module_t  ngx_http_log_module_ctx = {
  148.     NULL,                                  /* preconfiguration */
  149.     ngx_http_log_init,                     /* postconfiguration */

  150.     ngx_http_log_create_main_conf,         /* create main configuration */
  151.     NULL,                                  /* init main configuration */

  152.     NULL,                                  /* create server configuration */
  153.     NULL,                                  /* merge server configuration */

  154.     ngx_http_log_create_loc_conf,          /* create location configuration */
  155.     ngx_http_log_merge_loc_conf            /* merge location configuration */
  156. };


  157. ngx_module_t  ngx_http_log_module = {
  158.     NGX_MODULE_V1,
  159.     &ngx_http_log_module_ctx,              /* module context */
  160.     ngx_http_log_commands,                 /* module directives */
  161.     NGX_HTTP_MODULE,                       /* module type */
  162.     NULL,                                  /* init master */
  163.     NULL,                                  /* init module */
  164.     NULL,                                  /* init process */
  165.     NULL,                                  /* init thread */
  166.     NULL,                                  /* exit thread */
  167.     NULL,                                  /* exit process */
  168.     NULL,                                  /* exit master */
  169.     NGX_MODULE_V1_PADDING
  170. };


  171. static ngx_str_t  ngx_http_access_log = ngx_string(NGX_HTTP_LOG_PATH);


  172. static ngx_str_t  ngx_http_combined_fmt =
  173.     ngx_string("$remote_addr - $remote_user [$time_local] "
  174.                "\"$request\" $status $body_bytes_sent "
  175.                "\"$http_referer\" \"$http_user_agent\"");


  176. static ngx_http_log_var_t  ngx_http_log_vars[] = {
  177.     { ngx_string("pipe"), 1, ngx_http_log_pipe },
  178.     { ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1,
  179.                           ngx_http_log_time },
  180.     { ngx_string("time_iso8601"), sizeof("1970-09-28T12:00:00+06:00") - 1,
  181.                           ngx_http_log_iso8601 },
  182.     { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec },
  183.     { ngx_string("request_time"), NGX_TIME_T_LEN + 4,
  184.                           ngx_http_log_request_time },
  185.     { ngx_string("status"), NGX_INT_T_LEN, ngx_http_log_status },
  186.     { ngx_string("bytes_sent"), NGX_OFF_T_LEN, ngx_http_log_bytes_sent },
  187.     { ngx_string("body_bytes_sent"), NGX_OFF_T_LEN,
  188.                           ngx_http_log_body_bytes_sent },
  189.     { ngx_string("request_length"), NGX_SIZE_T_LEN,
  190.                           ngx_http_log_request_length },

  191.     { ngx_null_string, 0, NULL }
  192. };


  193. static ngx_int_t
  194. ngx_http_log_handler(ngx_http_request_t *r)
  195. {
  196.     u_char                   *line, *p;
  197.     size_t                    len, size;
  198.     ssize_t                   n;
  199.     ngx_str_t                 val;
  200.     ngx_uint_t                i, l;
  201.     ngx_http_log_t           *log;
  202.     ngx_http_log_op_t        *op;
  203.     ngx_http_log_buf_t       *buffer;
  204.     ngx_http_log_loc_conf_t  *lcf;

  205.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  206.                    "http log handler");

  207.     lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);

  208.     if (lcf->off) {
  209.         return NGX_OK;
  210.     }

  211.     log = lcf->logs->elts;
  212.     for (l = 0; l < lcf->logs->nelts; l++) {

  213.         if (log[l].filter) {
  214.             if (ngx_http_complex_value(r, log[l].filter, &val) != NGX_OK) {
  215.                 return NGX_ERROR;
  216.             }

  217.             if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) {
  218.                 continue;
  219.             }
  220.         }

  221.         if (ngx_time() == log[l].disk_full_time) {

  222.             /*
  223.              * on FreeBSD writing to a full filesystem with enabled softupdates
  224.              * may block process for much longer time than writing to non-full
  225.              * filesystem, so we skip writing to a log for one second
  226.              */

  227.             continue;
  228.         }

  229.         ngx_http_script_flush_no_cacheable_variables(r, log[l].format->flushes);

  230.         len = 0;
  231.         op = log[l].format->ops->elts;
  232.         for (i = 0; i < log[l].format->ops->nelts; i++) {
  233.             if (op[i].len == 0) {
  234.                 len += op[i].getlen(r, op[i].data);

  235.             } else {
  236.                 len += op[i].len;
  237.             }
  238.         }

  239.         if (log[l].syslog_peer) {

  240.             /* length of syslog's PRI and HEADER message parts */
  241.             len += sizeof("<255>Jan 01 00:00:00 ") - 1
  242.                    + ngx_cycle->hostname.len + 1
  243.                    + log[l].syslog_peer->tag.len + 2;

  244.             goto alloc_line;
  245.         }

  246.         len += NGX_LINEFEED_SIZE;

  247.         buffer = log[l].file ? log[l].file->data : NULL;

  248.         if (buffer) {

  249.             if (len > (size_t) (buffer->last - buffer->pos)) {

  250.                 ngx_http_log_write(r, &log[l], buffer->start,
  251.                                    buffer->pos - buffer->start);

  252.                 buffer->pos = buffer->start;
  253.             }

  254.             if (len <= (size_t) (buffer->last - buffer->pos)) {

  255.                 p = buffer->pos;

  256.                 if (buffer->event && p == buffer->start) {
  257.                     ngx_add_timer(buffer->event, buffer->flush);
  258.                 }

  259.                 for (i = 0; i < log[l].format->ops->nelts; i++) {
  260.                     p = op[i].run(r, p, &op[i]);
  261.                 }

  262.                 ngx_linefeed(p);

  263.                 buffer->pos = p;

  264.                 continue;
  265.             }

  266.             if (buffer->event && buffer->event->timer_set) {
  267.                 ngx_del_timer(buffer->event);
  268.             }
  269.         }

  270.     alloc_line:

  271.         line = ngx_pnalloc(r->pool, len);
  272.         if (line == NULL) {
  273.             return NGX_ERROR;
  274.         }

  275.         p = line;

  276.         if (log[l].syslog_peer) {
  277.             p = ngx_syslog_add_header(log[l].syslog_peer, line);
  278.         }

  279.         for (i = 0; i < log[l].format->ops->nelts; i++) {
  280.             p = op[i].run(r, p, &op[i]);
  281.         }

  282.         if (log[l].syslog_peer) {

  283.             size = p - line;

  284.             n = ngx_syslog_send(log[l].syslog_peer, line, size);

  285.             if (n < 0) {
  286.                 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  287.                               "send() to syslog failed");

  288.             } else if ((size_t) n != size) {
  289.                 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  290.                               "send() to syslog has written only %z of %uz",
  291.                               n, size);
  292.             }

  293.             continue;
  294.         }

  295.         ngx_linefeed(p);

  296.         ngx_http_log_write(r, &log[l], line, p - line);
  297.     }

  298.     return NGX_OK;
  299. }


  300. static void
  301. ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
  302.     size_t len)
  303. {
  304.     u_char              *name;
  305.     time_t               now;
  306.     ssize_t              n;
  307.     ngx_err_t            err;
  308. #if (NGX_ZLIB)
  309.     ngx_http_log_buf_t  *buffer;
  310. #endif

  311.     if (log->script == NULL) {
  312.         name = log->file->name.data;

  313. #if (NGX_ZLIB)
  314.         buffer = log->file->data;

  315.         if (buffer && buffer->gzip) {
  316.             n = ngx_http_log_gzip(log->file->fd, buf, len, buffer->gzip,
  317.                                   r->connection->log);
  318.         } else {
  319.             n = ngx_write_fd(log->file->fd, buf, len);
  320.         }
  321. #else
  322.         n = ngx_write_fd(log->file->fd, buf, len);
  323. #endif

  324.     } else {
  325.         name = NULL;
  326.         n = ngx_http_log_script_write(r, log->script, &name, buf, len);
  327.     }

  328.     if (n == (ssize_t) len) {
  329.         return;
  330.     }

  331.     now = ngx_time();

  332.     if (n == -1) {
  333.         err = ngx_errno;

  334.         if (err == NGX_ENOSPC) {
  335.             log->disk_full_time = now;
  336.         }

  337.         if (now - log->error_log_time > 59) {
  338.             ngx_log_error(NGX_LOG_ALERT, r->connection->log, err,
  339.                           ngx_write_fd_n " to \"%s\" failed", name);

  340.             log->error_log_time = now;
  341.         }

  342.         return;
  343.     }

  344.     if (now - log->error_log_time > 59) {
  345.         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  346.                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
  347.                       name, n, len);

  348.         log->error_log_time = now;
  349.     }
  350. }


  351. static ssize_t
  352. ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
  353.     u_char **name, u_char *buf, size_t len)
  354. {
  355.     size_t                     root;
  356.     ssize_t                    n;
  357.     ngx_str_t                  log, path;
  358.     ngx_open_file_info_t       of;
  359.     ngx_http_log_loc_conf_t   *llcf;
  360.     ngx_http_core_loc_conf_t  *clcf;

  361.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  362.     if (!r->root_tested) {

  363.         /* test root directory existence */

  364.         if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
  365.             /* simulate successful logging */
  366.             return len;
  367.         }

  368.         path.data[root] = '\0';

  369.         ngx_memzero(&of, sizeof(ngx_open_file_info_t));

  370.         of.valid = clcf->open_file_cache_valid;
  371.         of.min_uses = clcf->open_file_cache_min_uses;
  372.         of.test_dir = 1;
  373.         of.test_only = 1;
  374.         of.errors = clcf->open_file_cache_errors;
  375.         of.events = clcf->open_file_cache_events;

  376.         if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
  377.             /* simulate successful logging */
  378.             return len;
  379.         }

  380.         if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
  381.             != NGX_OK)
  382.         {
  383.             if (of.err == 0) {
  384.                 /* simulate successful logging */
  385.                 return len;
  386.             }

  387.             ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err,
  388.                           "testing \"%s\" existence failed", path.data);

  389.             /* simulate successful logging */
  390.             return len;
  391.         }

  392.         if (!of.is_dir) {
  393.             ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ENOTDIR,
  394.                           "testing \"%s\" existence failed", path.data);

  395.             /* simulate successful logging */
  396.             return len;
  397.         }
  398.     }

  399.     if (ngx_http_script_run(r, &log, script->lengths->elts, 1,
  400.                             script->values->elts)
  401.         == NULL)
  402.     {
  403.         /* simulate successful logging */
  404.         return len;
  405.     }

  406.     log.data[log.len - 1] = '\0';
  407.     *name = log.data;

  408.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  409.                    "http log \"%s\"", log.data);

  410.     llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);

  411.     ngx_memzero(&of, sizeof(ngx_open_file_info_t));

  412.     of.log = 1;
  413.     of.valid = llcf->open_file_cache_valid;
  414.     of.min_uses = llcf->open_file_cache_min_uses;
  415.     of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;

  416.     if (ngx_http_set_disable_symlinks(r, clcf, &log, &of) != NGX_OK) {
  417.         /* simulate successful logging */
  418.         return len;
  419.     }

  420.     if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool)
  421.         != NGX_OK)
  422.     {
  423.         if (of.err == 0) {
  424.             /* simulate successful logging */
  425.             return len;
  426.         }

  427.         ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
  428.                       "%s \"%s\" failed", of.failed, log.data);
  429.         /* simulate successful logging */
  430.         return len;
  431.     }

  432.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  433.                    "http log #%d", of.fd);

  434.     n = ngx_write_fd(of.fd, buf, len);

  435.     return n;
  436. }


  437. #if (NGX_ZLIB)

  438. static ssize_t
  439. ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,
  440.     ngx_log_t *log)
  441. {
  442.     int          rc, wbits, memlevel;
  443.     u_char      *out;
  444.     size_t       size;
  445.     ssize_t      n;
  446.     z_stream     zstream;
  447.     ngx_err_t    err;
  448.     ngx_pool_t  *pool;

  449.     wbits = MAX_WBITS;
  450.     memlevel = MAX_MEM_LEVEL - 1;

  451.     while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) {
  452.         wbits--;
  453.         memlevel--;
  454.     }

  455.     /*
  456.      * This is a formula from deflateBound() for conservative upper bound of
  457.      * compressed data plus 18 bytes of gzip wrapper.
  458.      */

  459.     size = len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5 + 18;

  460.     ngx_memzero(&zstream, sizeof(z_stream));

  461.     pool = ngx_create_pool(256, log);
  462.     if (pool == NULL) {
  463.         /* simulate successful logging */
  464.         return len;
  465.     }

  466.     pool->log = log;

  467.     zstream.zalloc = ngx_http_log_gzip_alloc;
  468.     zstream.zfree = ngx_http_log_gzip_free;
  469.     zstream.opaque = pool;

  470.     out = ngx_pnalloc(pool, size);
  471.     if (out == NULL) {
  472.         goto done;
  473.     }

  474.     zstream.next_in = buf;
  475.     zstream.avail_in = len;
  476.     zstream.next_out = out;
  477.     zstream.avail_out = size;

  478.     rc = deflateInit2(&zstream, (int) level, Z_DEFLATED, wbits + 16, memlevel,
  479.                       Z_DEFAULT_STRATEGY);

  480.     if (rc != Z_OK) {
  481.         ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateInit2() failed: %d", rc);
  482.         goto done;
  483.     }

  484.     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, log, 0,
  485.                    "deflate in: ni:%p no:%p ai:%ud ao:%ud",
  486.                    zstream.next_in, zstream.next_out,
  487.                    zstream.avail_in, zstream.avail_out);

  488.     rc = deflate(&zstream, Z_FINISH);

  489.     if (rc != Z_STREAM_END) {
  490.         ngx_log_error(NGX_LOG_ALERT, log, 0,
  491.                       "deflate(Z_FINISH) failed: %d", rc);
  492.         goto done;
  493.     }

  494.     ngx_log_debug5(NGX_LOG_DEBUG_HTTP, log, 0,
  495.                    "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
  496.                    zstream.next_in, zstream.next_out,
  497.                    zstream.avail_in, zstream.avail_out,
  498.                    rc);

  499.     size -= zstream.avail_out;

  500.     rc = deflateEnd(&zstream);

  501.     if (rc != Z_OK) {
  502.         ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc);
  503.         goto done;
  504.     }

  505.     n = ngx_write_fd(fd, out, size);

  506.     if (n != (ssize_t) size) {
  507.         err = (n == -1) ? ngx_errno : 0;

  508.         ngx_destroy_pool(pool);

  509.         ngx_set_errno(err);
  510.         return -1;
  511.     }

  512. done:

  513.     ngx_destroy_pool(pool);

  514.     /* simulate successful logging */
  515.     return len;
  516. }


  517. static void *
  518. ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size)
  519. {
  520.     ngx_pool_t *pool = opaque;

  521.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pool->log, 0,
  522.                    "gzip alloc: n:%ud s:%ud", items, size);

  523.     return ngx_palloc(pool, items * size);
  524. }


  525. static void
  526. ngx_http_log_gzip_free(void *opaque, void *address)
  527. {
  528. #if 0
  529.     ngx_pool_t *pool = opaque;

  530.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0, "gzip free: %p", address);
  531. #endif
  532. }

  533. #endif


  534. static void
  535. ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log)
  536. {
  537.     size_t               len;
  538.     ssize_t              n;
  539.     ngx_http_log_buf_t  *buffer;

  540.     buffer = file->data;

  541.     len = buffer->pos - buffer->start;

  542.     if (len == 0) {
  543.         return;
  544.     }

  545. #if (NGX_ZLIB)
  546.     if (buffer->gzip) {
  547.         n = ngx_http_log_gzip(file->fd, buffer->start, len, buffer->gzip, log);
  548.     } else {
  549.         n = ngx_write_fd(file->fd, buffer->start, len);
  550.     }
  551. #else
  552.     n = ngx_write_fd(file->fd, buffer->start, len);
  553. #endif

  554.     if (n == -1) {
  555.         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
  556.                       ngx_write_fd_n " to \"%s\" failed",
  557.                       file->name.data);

  558.     } else if ((size_t) n != len) {
  559.         ngx_log_error(NGX_LOG_ALERT, log, 0,
  560.                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
  561.                       file->name.data, n, len);
  562.     }

  563.     buffer->pos = buffer->start;

  564.     if (buffer->event && buffer->event->timer_set) {
  565.         ngx_del_timer(buffer->event);
  566.     }
  567. }


  568. static void
  569. ngx_http_log_flush_handler(ngx_event_t *ev)
  570. {
  571.     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  572.                    "http log buffer flush handler");

  573.     ngx_http_log_flush(ev->data, ev->log);
  574. }


  575. static u_char *
  576. ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
  577.     ngx_http_log_op_t *op)
  578. {
  579.     size_t     len;
  580.     uintptr_t  data;

  581.     len = op->len;
  582.     data = op->data;

  583.     while (len--) {
  584.         *buf++ = (u_char) (data & 0xff);
  585.         data >>= 8;
  586.     }

  587.     return buf;
  588. }


  589. static u_char *
  590. ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf,
  591.     ngx_http_log_op_t *op)
  592. {
  593.     return ngx_cpymem(buf, (u_char *) op->data, op->len);
  594. }


  595. static u_char *
  596. ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
  597. {
  598.     if (r->pipeline) {
  599.         *buf = 'p';
  600.     } else {
  601.         *buf = '.';
  602.     }

  603.     return buf + 1;
  604. }


  605. static u_char *
  606. ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
  607. {
  608.     return ngx_cpymem(buf, ngx_cached_http_log_time.data,
  609.                       ngx_cached_http_log_time.len);
  610. }

  611. static u_char *
  612. ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
  613. {
  614.     return ngx_cpymem(buf, ngx_cached_http_log_iso8601.data,
  615.                       ngx_cached_http_log_iso8601.len);
  616. }

  617. static u_char *
  618. ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
  619. {
  620.     ngx_time_t  *tp;

  621.     tp = ngx_timeofday();

  622.     return ngx_sprintf(buf, "%T.%03M", tp->sec, tp->msec);
  623. }


  624. static u_char *
  625. ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
  626.     ngx_http_log_op_t *op)
  627. {
  628.     ngx_time_t      *tp;
  629.     ngx_msec_int_t   ms;

  630.     tp = ngx_timeofday();

  631.     ms = (ngx_msec_int_t)
  632.              ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
  633.     ms = ngx_max(ms, 0);

  634.     return ngx_sprintf(buf, "%T.%03M", (time_t) ms / 1000, ms % 1000);
  635. }


  636. static u_char *
  637. ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
  638. {
  639.     ngx_uint_t  status;

  640.     if (r->err_status) {
  641.         status = r->err_status;

  642.     } else if (r->headers_out.status) {
  643.         status = r->headers_out.status;

  644.     } else if (r->http_version == NGX_HTTP_VERSION_9) {
  645.         status = 9;

  646.     } else {
  647.         status = 0;
  648.     }

  649.     return ngx_sprintf(buf, "%03ui", status);
  650. }


  651. static u_char *
  652. ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
  653.     ngx_http_log_op_t *op)
  654. {
  655.     return ngx_sprintf(buf, "%O", r->connection->sent);
  656. }


  657. /*
  658. * although there is a real $body_bytes_sent variable,
  659. * this log operation code function is more optimized for logging
  660. */

  661. static u_char *
  662. ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
  663.     ngx_http_log_op_t *op)
  664. {
  665.     off_t  length;

  666.     length = r->connection->sent - r->header_size;

  667.     if (length > 0) {
  668.         return ngx_sprintf(buf, "%O", length);
  669.     }

  670.     *buf = '0';

  671.     return buf + 1;
  672. }


  673. static u_char *
  674. ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
  675.     ngx_http_log_op_t *op)
  676. {
  677.     return ngx_sprintf(buf, "%O", r->request_length);
  678. }


  679. static ngx_int_t
  680. ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
  681.     ngx_str_t *value, ngx_uint_t escape)
  682. {
  683.     ngx_int_t  index;

  684.     index = ngx_http_get_variable_index(cf, value);
  685.     if (index == NGX_ERROR) {
  686.         return NGX_ERROR;
  687.     }

  688.     op->len = 0;

  689.     switch (escape) {
  690.     case NGX_HTTP_LOG_ESCAPE_JSON:
  691.         op->getlen = ngx_http_log_json_variable_getlen;
  692.         op->run = ngx_http_log_json_variable;
  693.         break;

  694.     case NGX_HTTP_LOG_ESCAPE_NONE:
  695.         op->getlen = ngx_http_log_unescaped_variable_getlen;
  696.         op->run = ngx_http_log_unescaped_variable;
  697.         break;

  698.     default: /* NGX_HTTP_LOG_ESCAPE_DEFAULT */
  699.         op->getlen = ngx_http_log_variable_getlen;
  700.         op->run = ngx_http_log_variable;
  701.     }

  702.     op->data = index;

  703.     return NGX_OK;
  704. }


  705. static size_t
  706. ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data)
  707. {
  708.     uintptr_t                   len;
  709.     ngx_http_variable_value_t  *value;

  710.     value = ngx_http_get_indexed_variable(r, data);

  711.     if (value == NULL || value->not_found) {
  712.         return 1;
  713.     }

  714.     len = ngx_http_log_escape(NULL, value->data, value->len);

  715.     value->escape = len ? 1 : 0;

  716.     return value->len + len * 3;
  717. }


  718. static u_char *
  719. ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
  720. {
  721.     ngx_http_variable_value_t  *value;

  722.     value = ngx_http_get_indexed_variable(r, op->data);

  723.     if (value == NULL || value->not_found) {
  724.         *buf = '-';
  725.         return buf + 1;
  726.     }

  727.     if (value->escape == 0) {
  728.         return ngx_cpymem(buf, value->data, value->len);

  729.     } else {
  730.         return (u_char *) ngx_http_log_escape(buf, value->data, value->len);
  731.     }
  732. }


  733. static uintptr_t
  734. ngx_http_log_escape(u_char *dst, u_char *src, size_t size)
  735. {
  736.     ngx_uint_t      n;
  737.     static u_char   hex[] = "0123456789ABCDEF";

  738.     static uint32_t   escape[] = {
  739.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */

  740.                     /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
  741.         0x00000004, /* 0000 0000 0000 0000  0000 0000 0000 0100 */

  742.                     /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
  743.         0x10000000, /* 0001 0000 0000 0000  0000 0000 0000 0000 */

  744.                     /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
  745.         0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */

  746.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  747.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  748.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  749.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  750.     };


  751.     if (dst == NULL) {

  752.         /* find the number of the characters to be escaped */

  753.         n = 0;

  754.         while (size) {
  755.             if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
  756.                 n++;
  757.             }
  758.             src++;
  759.             size--;
  760.         }

  761.         return (uintptr_t) n;
  762.     }

  763.     while (size) {
  764.         if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
  765.             *dst++ = '\\';
  766.             *dst++ = 'x';
  767.             *dst++ = hex[*src >> 4];
  768.             *dst++ = hex[*src & 0xf];
  769.             src++;

  770.         } else {
  771.             *dst++ = *src++;
  772.         }
  773.         size--;
  774.     }

  775.     return (uintptr_t) dst;
  776. }


  777. static size_t
  778. ngx_http_log_json_variable_getlen(ngx_http_request_t *r, uintptr_t data)
  779. {
  780.     uintptr_t                   len;
  781.     ngx_http_variable_value_t  *value;

  782.     value = ngx_http_get_indexed_variable(r, data);

  783.     if (value == NULL || value->not_found) {
  784.         return 0;
  785.     }

  786.     len = ngx_escape_json(NULL, value->data, value->len);

  787.     value->escape = len ? 1 : 0;

  788.     return value->len + len;
  789. }


  790. static u_char *
  791. ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf,
  792.     ngx_http_log_op_t *op)
  793. {
  794.     ngx_http_variable_value_t  *value;

  795.     value = ngx_http_get_indexed_variable(r, op->data);

  796.     if (value == NULL || value->not_found) {
  797.         return buf;
  798.     }

  799.     if (value->escape == 0) {
  800.         return ngx_cpymem(buf, value->data, value->len);

  801.     } else {
  802.         return (u_char *) ngx_escape_json(buf, value->data, value->len);
  803.     }
  804. }


  805. static size_t
  806. ngx_http_log_unescaped_variable_getlen(ngx_http_request_t *r, uintptr_t data)
  807. {
  808.     ngx_http_variable_value_t  *value;

  809.     value = ngx_http_get_indexed_variable(r, data);

  810.     if (value == NULL || value->not_found) {
  811.         return 0;
  812.     }

  813.     value->escape = 0;

  814.     return value->len;
  815. }


  816. static u_char *
  817. ngx_http_log_unescaped_variable(ngx_http_request_t *r, u_char *buf,
  818.     ngx_http_log_op_t *op)
  819. {
  820.     ngx_http_variable_value_t  *value;

  821.     value = ngx_http_get_indexed_variable(r, op->data);

  822.     if (value == NULL || value->not_found) {
  823.         return buf;
  824.     }

  825.     return ngx_cpymem(buf, value->data, value->len);
  826. }


  827. static void *
  828. ngx_http_log_create_main_conf(ngx_conf_t *cf)
  829. {
  830.     ngx_http_log_main_conf_t  *conf;

  831.     ngx_http_log_fmt_t  *fmt;

  832.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
  833.     if (conf == NULL) {
  834.         return NULL;
  835.     }

  836.     if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t))
  837.         != NGX_OK)
  838.     {
  839.         return NULL;
  840.     }

  841.     fmt = ngx_array_push(&conf->formats);
  842.     if (fmt == NULL) {
  843.         return NULL;
  844.     }

  845.     ngx_str_set(&fmt->name, "combined");

  846.     fmt->flushes = NULL;

  847.     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
  848.     if (fmt->ops == NULL) {
  849.         return NULL;
  850.     }

  851.     return conf;
  852. }


  853. static void *
  854. ngx_http_log_create_loc_conf(ngx_conf_t *cf)
  855. {
  856.     ngx_http_log_loc_conf_t  *conf;

  857.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t));
  858.     if (conf == NULL) {
  859.         return NULL;
  860.     }

  861.     conf->open_file_cache = NGX_CONF_UNSET_PTR;

  862.     return conf;
  863. }


  864. static char *
  865. ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  866. {
  867.     ngx_http_log_loc_conf_t *prev = parent;
  868.     ngx_http_log_loc_conf_t *conf = child;

  869.     ngx_http_log_t            *log;
  870.     ngx_http_log_fmt_t        *fmt;
  871.     ngx_http_log_main_conf_t  *lmcf;

  872.     if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {

  873.         conf->open_file_cache = prev->open_file_cache;
  874.         conf->open_file_cache_valid = prev->open_file_cache_valid;
  875.         conf->open_file_cache_min_uses = prev->open_file_cache_min_uses;

  876.         if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
  877.             conf->open_file_cache = NULL;
  878.         }
  879.     }

  880.     if (conf->logs || conf->off) {
  881.         return NGX_CONF_OK;
  882.     }

  883.     conf->logs = prev->logs;
  884.     conf->off = prev->off;

  885.     if (conf->logs || conf->off) {
  886.         return NGX_CONF_OK;
  887.     }

  888.     conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
  889.     if (conf->logs == NULL) {
  890.         return NGX_CONF_ERROR;
  891.     }

  892.     log = ngx_array_push(conf->logs);
  893.     if (log == NULL) {
  894.         return NGX_CONF_ERROR;
  895.     }

  896.     ngx_memzero(log, sizeof(ngx_http_log_t));

  897.     log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log);
  898.     if (log->file == NULL) {
  899.         return NGX_CONF_ERROR;
  900.     }

  901.     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
  902.     fmt = lmcf->formats.elts;

  903.     /* the default "combined" format */
  904.     log->format = &fmt[0];
  905.     lmcf->combined_used = 1;

  906.     return NGX_CONF_OK;
  907. }


  908. static char *
  909. ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  910. {
  911.     ngx_http_log_loc_conf_t *llcf = conf;

  912.     ssize_t                            size;
  913.     ngx_int_t                          gzip;
  914.     ngx_uint_t                         i, n;
  915.     ngx_msec_t                         flush;
  916.     ngx_str_t                         *value, name, s;
  917.     ngx_http_log_t                    *log;
  918.     ngx_syslog_peer_t                 *peer;
  919.     ngx_http_log_buf_t                *buffer;
  920.     ngx_http_log_fmt_t                *fmt;
  921.     ngx_http_log_main_conf_t          *lmcf;
  922.     ngx_http_script_compile_t          sc;
  923.     ngx_http_compile_complex_value_t   ccv;

  924.     value = cf->args->elts;

  925.     if (ngx_strcmp(value[1].data, "off") == 0) {
  926.         llcf->off = 1;
  927.         if (cf->args->nelts == 2) {
  928.             return NGX_CONF_OK;
  929.         }

  930.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  931.                            "invalid parameter \"%V\"", &value[2]);
  932.         return NGX_CONF_ERROR;
  933.     }

  934.     if (llcf->logs == NULL) {
  935.         llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
  936.         if (llcf->logs == NULL) {
  937.             return NGX_CONF_ERROR;
  938.         }
  939.     }

  940.     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);

  941.     log = ngx_array_push(llcf->logs);
  942.     if (log == NULL) {
  943.         return NGX_CONF_ERROR;
  944.     }

  945.     ngx_memzero(log, sizeof(ngx_http_log_t));


  946.     if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {

  947.         peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
  948.         if (peer == NULL) {
  949.             return NGX_CONF_ERROR;
  950.         }

  951.         if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
  952.             return NGX_CONF_ERROR;
  953.         }

  954.         log->syslog_peer = peer;

  955.         goto process_formats;
  956.     }

  957.     n = ngx_http_script_variables_count(&value[1]);

  958.     if (n == 0) {
  959.         log->file = ngx_conf_open_file(cf->cycle, &value[1]);
  960.         if (log->file == NULL) {
  961.             return NGX_CONF_ERROR;
  962.         }

  963.     } else {
  964.         if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
  965.             return NGX_CONF_ERROR;
  966.         }

  967.         log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t));
  968.         if (log->script == NULL) {
  969.             return NGX_CONF_ERROR;
  970.         }

  971.         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

  972.         sc.cf = cf;
  973.         sc.source = &value[1];
  974.         sc.lengths = &log->script->lengths;
  975.         sc.values = &log->script->values;
  976.         sc.variables = n;
  977.         sc.complete_lengths = 1;
  978.         sc.complete_values = 1;

  979.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  980.             return NGX_CONF_ERROR;
  981.         }
  982.     }

  983. process_formats:

  984.     if (cf->args->nelts >= 3) {
  985.         name = value[2];

  986.         if (ngx_strcmp(name.data, "combined") == 0) {
  987.             lmcf->combined_used = 1;
  988.         }

  989.     } else {
  990.         ngx_str_set(&name, "combined");
  991.         lmcf->combined_used = 1;
  992.     }

  993.     fmt = lmcf->formats.elts;
  994.     for (i = 0; i < lmcf->formats.nelts; i++) {
  995.         if (fmt[i].name.len == name.len
  996.             && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
  997.         {
  998.             log->format = &fmt[i];
  999.             break;
  1000.         }
  1001.     }

  1002.     if (log->format == NULL) {
  1003.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1004.                            "unknown log format \"%V\"", &name);
  1005.         return NGX_CONF_ERROR;
  1006.     }

  1007.     size = 0;
  1008.     flush = 0;
  1009.     gzip = 0;

  1010.     for (i = 3; i < cf->args->nelts; i++) {

  1011.         if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
  1012.             s.len = value[i].len - 7;
  1013.             s.data = value[i].data + 7;

  1014.             size = ngx_parse_size(&s);

  1015.             if (size == NGX_ERROR || size == 0) {
  1016.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1017.                                    "invalid buffer size \"%V\"", &s);
  1018.                 return NGX_CONF_ERROR;
  1019.             }

  1020.             continue;
  1021.         }

  1022.         if (ngx_strncmp(value[i].data, "flush=", 6) == 0) {
  1023.             s.len = value[i].len - 6;
  1024.             s.data = value[i].data + 6;

  1025.             flush = ngx_parse_time(&s, 0);

  1026.             if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) {
  1027.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1028.                                    "invalid flush time \"%V\"", &s);
  1029.                 return NGX_CONF_ERROR;
  1030.             }

  1031.             continue;
  1032.         }

  1033.         if (ngx_strncmp(value[i].data, "gzip", 4) == 0
  1034.             && (value[i].len == 4 || value[i].data[4] == '='))
  1035.         {
  1036. #if (NGX_ZLIB)
  1037.             if (size == 0) {
  1038.                 size = 64 * 1024;
  1039.             }

  1040.             if (value[i].len == 4) {
  1041.                 gzip = Z_BEST_SPEED;
  1042.                 continue;
  1043.             }

  1044.             s.len = value[i].len - 5;
  1045.             s.data = value[i].data + 5;

  1046.             gzip = ngx_atoi(s.data, s.len);

  1047.             if (gzip < 1 || gzip > 9) {
  1048.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1049.                                    "invalid compression level \"%V\"", &s);
  1050.                 return NGX_CONF_ERROR;
  1051.             }

  1052.             continue;

  1053. #else
  1054.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1055.                                "nginx was built without zlib support");
  1056.             return NGX_CONF_ERROR;
  1057. #endif
  1058.         }

  1059.         if (ngx_strncmp(value[i].data, "if=", 3) == 0) {
  1060.             s.len = value[i].len - 3;
  1061.             s.data = value[i].data + 3;

  1062.             ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

  1063.             ccv.cf = cf;
  1064.             ccv.value = &s;
  1065.             ccv.complex_value = ngx_palloc(cf->pool,
  1066.                                            sizeof(ngx_http_complex_value_t));
  1067.             if (ccv.complex_value == NULL) {
  1068.                 return NGX_CONF_ERROR;
  1069.             }

  1070.             if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  1071.                 return NGX_CONF_ERROR;
  1072.             }

  1073.             log->filter = ccv.complex_value;

  1074.             continue;
  1075.         }

  1076.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1077.                            "invalid parameter \"%V\"", &value[i]);
  1078.         return NGX_CONF_ERROR;
  1079.     }

  1080.     if (flush && size == 0) {
  1081.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1082.                            "no buffer is defined for access_log \"%V\"",
  1083.                            &value[1]);
  1084.         return NGX_CONF_ERROR;
  1085.     }

  1086.     if (size) {

  1087.         if (log->script) {
  1088.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1089.                                "buffered logs cannot have variables in name");
  1090.             return NGX_CONF_ERROR;
  1091.         }

  1092.         if (log->syslog_peer) {
  1093.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1094.                                "logs to syslog cannot be buffered");
  1095.             return NGX_CONF_ERROR;
  1096.         }

  1097.         if (log->file->data) {
  1098.             buffer = log->file->data;

  1099.             if (buffer->last - buffer->start != size
  1100.                 || buffer->flush != flush
  1101.                 || buffer->gzip != gzip)
  1102.             {
  1103.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1104.                                    "access_log \"%V\" already defined "
  1105.                                    "with conflicting parameters",
  1106.                                    &value[1]);
  1107.                 return NGX_CONF_ERROR;
  1108.             }

  1109.             return NGX_CONF_OK;
  1110.         }

  1111.         buffer = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_buf_t));
  1112.         if (buffer == NULL) {
  1113.             return NGX_CONF_ERROR;
  1114.         }

  1115.         buffer->start = ngx_pnalloc(cf->pool, size);
  1116.         if (buffer->start == NULL) {
  1117.             return NGX_CONF_ERROR;
  1118.         }

  1119.         buffer->pos = buffer->start;
  1120.         buffer->last = buffer->start + size;

  1121.         if (flush) {
  1122.             buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
  1123.             if (buffer->event == NULL) {
  1124.                 return NGX_CONF_ERROR;
  1125.             }

  1126.             buffer->event->data = log->file;
  1127.             buffer->event->handler = ngx_http_log_flush_handler;
  1128.             buffer->event->log = &cf->cycle->new_log;
  1129.             buffer->event->cancelable = 1;

  1130.             buffer->flush = flush;
  1131.         }

  1132.         buffer->gzip = gzip;

  1133.         log->file->flush = ngx_http_log_flush;
  1134.         log->file->data = buffer;
  1135.     }

  1136.     return NGX_CONF_OK;
  1137. }


  1138. static char *
  1139. ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1140. {
  1141.     ngx_http_log_main_conf_t *lmcf = conf;

  1142.     ngx_str_t           *value;
  1143.     ngx_uint_t           i;
  1144.     ngx_http_log_fmt_t  *fmt;

  1145.     value = cf->args->elts;

  1146.     fmt = lmcf->formats.elts;
  1147.     for (i = 0; i < lmcf->formats.nelts; i++) {
  1148.         if (fmt[i].name.len == value[1].len
  1149.             && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
  1150.         {
  1151.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1152.                                "duplicate \"log_format\" name \"%V\"",
  1153.                                &value[1]);
  1154.             return NGX_CONF_ERROR;
  1155.         }
  1156.     }

  1157.     fmt = ngx_array_push(&lmcf->formats);
  1158.     if (fmt == NULL) {
  1159.         return NGX_CONF_ERROR;
  1160.     }

  1161.     fmt->name = value[1];

  1162.     fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
  1163.     if (fmt->flushes == NULL) {
  1164.         return NGX_CONF_ERROR;
  1165.     }

  1166.     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
  1167.     if (fmt->ops == NULL) {
  1168.         return NGX_CONF_ERROR;
  1169.     }

  1170.     return ngx_http_log_compile_format(cf, fmt->flushes, fmt->ops, cf->args, 2);
  1171. }


  1172. static char *
  1173. ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
  1174.     ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
  1175. {
  1176.     u_char              *data, *p, ch;
  1177.     size_t               i, len;
  1178.     ngx_str_t           *value, var;
  1179.     ngx_int_t           *flush;
  1180.     ngx_uint_t           bracket, escape;
  1181.     ngx_http_log_op_t   *op;
  1182.     ngx_http_log_var_t  *v;

  1183.     escape = NGX_HTTP_LOG_ESCAPE_DEFAULT;
  1184.     value = args->elts;

  1185.     if (s < args->nelts && ngx_strncmp(value[s].data, "escape=", 7) == 0) {
  1186.         data = value[s].data + 7;

  1187.         if (ngx_strcmp(data, "json") == 0) {
  1188.             escape = NGX_HTTP_LOG_ESCAPE_JSON;

  1189.         } else if (ngx_strcmp(data, "none") == 0) {
  1190.             escape = NGX_HTTP_LOG_ESCAPE_NONE;

  1191.         } else if (ngx_strcmp(data, "default") != 0) {
  1192.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1193.                                "unknown log format escaping \"%s\"", data);
  1194.             return NGX_CONF_ERROR;
  1195.         }

  1196.         s++;
  1197.     }

  1198.     for ( /* void */ ; s < args->nelts; s++) {

  1199.         i = 0;

  1200.         while (i < value[s].len) {

  1201.             op = ngx_array_push(ops);
  1202.             if (op == NULL) {
  1203.                 return NGX_CONF_ERROR;
  1204.             }

  1205.             data = &value[s].data[i];

  1206.             if (value[s].data[i] == '$') {

  1207.                 if (++i == value[s].len) {
  1208.                     goto invalid;
  1209.                 }

  1210.                 if (value[s].data[i] == '{') {
  1211.                     bracket = 1;

  1212.                     if (++i == value[s].len) {
  1213.                         goto invalid;
  1214.                     }

  1215.                     var.data = &value[s].data[i];

  1216.                 } else {
  1217.                     bracket = 0;
  1218.                     var.data = &value[s].data[i];
  1219.                 }

  1220.                 for (var.len = 0; i < value[s].len; i++, var.len++) {
  1221.                     ch = value[s].data[i];

  1222.                     if (ch == '}' && bracket) {
  1223.                         i++;
  1224.                         bracket = 0;
  1225.                         break;
  1226.                     }

  1227.                     if ((ch >= 'A' && ch <= 'Z')
  1228.                         || (ch >= 'a' && ch <= 'z')
  1229.                         || (ch >= '0' && ch <= '9')
  1230.                         || ch == '_')
  1231.                     {
  1232.                         continue;
  1233.                     }

  1234.                     break;
  1235.                 }

  1236.                 if (bracket) {
  1237.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1238.                                        "the closing bracket in \"%V\" "
  1239.                                        "variable is missing", &var);
  1240.                     return NGX_CONF_ERROR;
  1241.                 }

  1242.                 if (var.len == 0) {
  1243.                     goto invalid;
  1244.                 }

  1245.                 for (v = ngx_http_log_vars; v->name.len; v++) {

  1246.                     if (v->name.len == var.len
  1247.                         && ngx_strncmp(v->name.data, var.data, var.len) == 0)
  1248.                     {
  1249.                         op->len = v->len;
  1250.                         op->getlen = NULL;
  1251.                         op->run = v->run;
  1252.                         op->data = 0;

  1253.                         goto found;
  1254.                     }
  1255.                 }

  1256.                 if (ngx_http_log_variable_compile(cf, op, &var, escape)
  1257.                     != NGX_OK)
  1258.                 {
  1259.                     return NGX_CONF_ERROR;
  1260.                 }

  1261.                 if (flushes) {

  1262.                     flush = ngx_array_push(flushes);
  1263.                     if (flush == NULL) {
  1264.                         return NGX_CONF_ERROR;
  1265.                     }

  1266.                     *flush = op->data; /* variable index */
  1267.                 }

  1268.             found:

  1269.                 continue;
  1270.             }

  1271.             i++;

  1272.             while (i < value[s].len && value[s].data[i] != '$') {
  1273.                 i++;
  1274.             }

  1275.             len = &value[s].data[i] - data;

  1276.             if (len) {

  1277.                 op->len = len;
  1278.                 op->getlen = NULL;

  1279.                 if (len <= sizeof(uintptr_t)) {
  1280.                     op->run = ngx_http_log_copy_short;
  1281.                     op->data = 0;

  1282.                     while (len--) {
  1283.                         op->data <<= 8;
  1284.                         op->data |= data[len];
  1285.                     }

  1286.                 } else {
  1287.                     op->run = ngx_http_log_copy_long;

  1288.                     p = ngx_pnalloc(cf->pool, len);
  1289.                     if (p == NULL) {
  1290.                         return NGX_CONF_ERROR;
  1291.                     }

  1292.                     ngx_memcpy(p, data, len);
  1293.                     op->data = (uintptr_t) p;
  1294.                 }
  1295.             }
  1296.         }
  1297.     }

  1298.     return NGX_CONF_OK;

  1299. invalid:

  1300.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);

  1301.     return NGX_CONF_ERROR;
  1302. }


  1303. static char *
  1304. ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1305. {
  1306.     ngx_http_log_loc_conf_t *llcf = conf;

  1307.     time_t       inactive, valid;
  1308.     ngx_str_t   *value, s;
  1309.     ngx_int_t    max, min_uses;
  1310.     ngx_uint_t   i;

  1311.     if (llcf->open_file_cache != NGX_CONF_UNSET_PTR) {
  1312.         return "is duplicate";
  1313.     }

  1314.     value = cf->args->elts;

  1315.     max = 0;
  1316.     inactive = 10;
  1317.     valid = 60;
  1318.     min_uses = 1;

  1319.     for (i = 1; i < cf->args->nelts; i++) {

  1320.         if (ngx_strncmp(value[i].data, "max=", 4) == 0) {

  1321.             max = ngx_atoi(value[i].data + 4, value[i].len - 4);
  1322.             if (max == NGX_ERROR) {
  1323.                 goto failed;
  1324.             }

  1325.             continue;
  1326.         }

  1327.         if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {

  1328.             s.len = value[i].len - 9;
  1329.             s.data = value[i].data + 9;

  1330.             inactive = ngx_parse_time(&s, 1);
  1331.             if (inactive == (time_t) NGX_ERROR) {
  1332.                 goto failed;
  1333.             }

  1334.             continue;
  1335.         }

  1336.         if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) {

  1337.             min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
  1338.             if (min_uses == NGX_ERROR) {
  1339.                 goto failed;
  1340.             }

  1341.             continue;
  1342.         }

  1343.         if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {

  1344.             s.len = value[i].len - 6;
  1345.             s.data = value[i].data + 6;

  1346.             valid = ngx_parse_time(&s, 1);
  1347.             if (valid == (time_t) NGX_ERROR) {
  1348.                 goto failed;
  1349.             }

  1350.             continue;
  1351.         }

  1352.         if (ngx_strcmp(value[i].data, "off") == 0) {

  1353.             llcf->open_file_cache = NULL;

  1354.             continue;
  1355.         }

  1356.     failed:

  1357.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1358.                            "invalid \"open_log_file_cache\" parameter \"%V\"",
  1359.                            &value[i]);
  1360.         return NGX_CONF_ERROR;
  1361.     }

  1362.     if (llcf->open_file_cache == NULL) {
  1363.         return NGX_CONF_OK;
  1364.     }

  1365.     if (max == 0) {
  1366.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1367.                         "\"open_log_file_cache\" must have \"max\" parameter");
  1368.         return NGX_CONF_ERROR;
  1369.     }

  1370.     llcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);

  1371.     if (llcf->open_file_cache) {

  1372.         llcf->open_file_cache_valid = valid;
  1373.         llcf->open_file_cache_min_uses = min_uses;

  1374.         return NGX_CONF_OK;
  1375.     }

  1376.     return NGX_CONF_ERROR;
  1377. }


  1378. static ngx_int_t
  1379. ngx_http_log_init(ngx_conf_t *cf)
  1380. {
  1381.     ngx_str_t                  *value;
  1382.     ngx_array_t                 a;
  1383.     ngx_http_handler_pt        *h;
  1384.     ngx_http_log_fmt_t         *fmt;
  1385.     ngx_http_log_main_conf_t   *lmcf;
  1386.     ngx_http_core_main_conf_t  *cmcf;

  1387.     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);

  1388.     if (lmcf->combined_used) {
  1389.         if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) {
  1390.             return NGX_ERROR;
  1391.         }

  1392.         value = ngx_array_push(&a);
  1393.         if (value == NULL) {
  1394.             return NGX_ERROR;
  1395.         }

  1396.         *value = ngx_http_combined_fmt;
  1397.         fmt = lmcf->formats.elts;

  1398.         if (ngx_http_log_compile_format(cf, NULL, fmt->ops, &a, 0)
  1399.             != NGX_CONF_OK)
  1400.         {
  1401.             return NGX_ERROR;
  1402.         }
  1403.     }

  1404.     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

  1405.     h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
  1406.     if (h == NULL) {
  1407.         return NGX_ERROR;
  1408.     }

  1409.     *h = ngx_http_log_handler;

  1410.     return NGX_OK;
  1411. }