src/http/modules/ngx_http_log_module.c - nginx-1.7.10

Global variables defined

Data types defined

Functions 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. static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
  65.     u_char *buf, size_t len);
  66. static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
  67.     ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len);

  68. #if (NGX_ZLIB)
  69. static ssize_t ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len,
  70.     ngx_int_t level, ngx_log_t *log);

  71. static void *ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size);
  72. static void ngx_http_log_gzip_free(void *opaque, void *address);
  73. #endif

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

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

  94. static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
  95.     ngx_http_log_op_t *op, ngx_str_t *value);
  96. static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
  97.     uintptr_t data);
  98. static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
  99.     ngx_http_log_op_t *op);
  100. static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size);


  101. static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
  102. static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf);
  103. static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
  104.     void *child);
  105. static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
  106.     void *conf);
  107. static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
  108.     void *conf);
  109. static char *ngx_http_log_compile_format(ngx_conf_t *cf,
  110.     ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
  111. static char *ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
  112.     void *conf);
  113. static ngx_int_t ngx_http_log_init(ngx_conf_t *cf);


  114. static ngx_command_t  ngx_http_log_commands[] = {

  115.     { ngx_string("log_format"),
  116.       NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
  117.       ngx_http_log_set_format,
  118.       NGX_HTTP_MAIN_CONF_OFFSET,
  119.       0,
  120.       NULL },

  121.     { ngx_string("access_log"),
  122.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
  123.                         |NGX_HTTP_LMT_CONF|NGX_CONF_1MORE,
  124.       ngx_http_log_set_log,
  125.       NGX_HTTP_LOC_CONF_OFFSET,
  126.       0,
  127.       NULL },

  128.     { ngx_string("open_log_file_cache"),
  129.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
  130.       ngx_http_log_open_file_cache,
  131.       NGX_HTTP_LOC_CONF_OFFSET,
  132.       0,
  133.       NULL },

  134.       ngx_null_command
  135. };


  136. static ngx_http_module_t  ngx_http_log_module_ctx = {
  137.     NULL,                                  /* preconfiguration */
  138.     ngx_http_log_init,                     /* postconfiguration */

  139.     ngx_http_log_create_main_conf,         /* create main configuration */
  140.     NULL,                                  /* init main configuration */

  141.     NULL,                                  /* create server configuration */
  142.     NULL,                                  /* merge server configuration */

  143.     ngx_http_log_create_loc_conf,          /* create location configuration */
  144.     ngx_http_log_merge_loc_conf            /* merge location configuration */
  145. };


  146. ngx_module_t  ngx_http_log_module = {
  147.     NGX_MODULE_V1,
  148.     &ngx_http_log_module_ctx,              /* module context */
  149.     ngx_http_log_commands,                 /* module directives */
  150.     NGX_HTTP_MODULE,                       /* module type */
  151.     NULL,                                  /* init master */
  152.     NULL,                                  /* init module */
  153.     NULL,                                  /* init process */
  154.     NULL,                                  /* init thread */
  155.     NULL,                                  /* exit thread */
  156.     NULL,                                  /* exit process */
  157.     NULL,                                  /* exit master */
  158.     NGX_MODULE_V1_PADDING
  159. };


  160. static ngx_str_t  ngx_http_access_log = ngx_string(NGX_HTTP_LOG_PATH);


  161. static ngx_str_t  ngx_http_combined_fmt =
  162.     ngx_string("$remote_addr - $remote_user [$time_local] "
  163.                "\"$request\" $status $body_bytes_sent "
  164.                "\"$http_referer\" \"$http_user_agent\"");


  165. static ngx_http_log_var_t  ngx_http_log_vars[] = {
  166.     { ngx_string("pipe"), 1, ngx_http_log_pipe },
  167.     { ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1,
  168.                           ngx_http_log_time },
  169.     { ngx_string("time_iso8601"), sizeof("1970-09-28T12:00:00+06:00") - 1,
  170.                           ngx_http_log_iso8601 },
  171.     { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec },
  172.     { ngx_string("request_time"), NGX_TIME_T_LEN + 4,
  173.                           ngx_http_log_request_time },
  174.     { ngx_string("status"), NGX_INT_T_LEN, ngx_http_log_status },
  175.     { ngx_string("bytes_sent"), NGX_OFF_T_LEN, ngx_http_log_bytes_sent },
  176.     { ngx_string("body_bytes_sent"), NGX_OFF_T_LEN,
  177.                           ngx_http_log_body_bytes_sent },
  178.     { ngx_string("request_length"), NGX_SIZE_T_LEN,
  179.                           ngx_http_log_request_length },

  180.     { ngx_null_string, 0, NULL }
  181. };


  182. static ngx_int_t
  183. ngx_http_log_handler(ngx_http_request_t *r)
  184. {
  185.     u_char                   *line, *p;
  186.     size_t                    len, size;
  187.     ssize_t                   n;
  188.     ngx_str_t                 val;
  189.     ngx_uint_t                i, l;
  190.     ngx_http_log_t           *log;
  191.     ngx_http_log_op_t        *op;
  192.     ngx_http_log_buf_t       *buffer;
  193.     ngx_http_log_loc_conf_t  *lcf;

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

  196.     lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);

  197.     if (lcf->off) {
  198.         return NGX_OK;
  199.     }

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

  202.         if (log[l].filter) {
  203.             if (ngx_http_complex_value(r, log[l].filter, &val) != NGX_OK) {
  204.                 return NGX_ERROR;
  205.             }

  206.             if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) {
  207.                 continue;
  208.             }
  209.         }

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

  211.             /*
  212.              * on FreeBSD writing to a full filesystem with enabled softupdates
  213.              * may block process for much longer time than writing to non-full
  214.              * filesystem, so we skip writing to a log for one second
  215.              */

  216.             continue;
  217.         }

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

  219.         len = 0;
  220.         op = log[l].format->ops->elts;
  221.         for (i = 0; i < log[l].format->ops->nelts; i++) {
  222.             if (op[i].len == 0) {
  223.                 len += op[i].getlen(r, op[i].data);

  224.             } else {
  225.                 len += op[i].len;
  226.             }
  227.         }

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

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

  233.             goto alloc_line;
  234.         }

  235.         len += NGX_LINEFEED_SIZE;

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

  237.         if (buffer) {

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

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

  241.                 buffer->pos = buffer->start;
  242.             }

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

  244.                 p = buffer->pos;

  245.                 if (buffer->event && p == buffer->start) {
  246.                     ngx_add_timer(buffer->event, buffer->flush);
  247.                 }

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

  251.                 ngx_linefeed(p);

  252.                 buffer->pos = p;

  253.                 continue;
  254.             }

  255.             if (buffer->event && buffer->event->timer_set) {
  256.                 ngx_del_timer(buffer->event);
  257.             }
  258.         }

  259.     alloc_line:

  260.         line = ngx_pnalloc(r->pool, len);
  261.         if (line == NULL) {
  262.             return NGX_ERROR;
  263.         }

  264.         p = line;

  265.         if (log[l].syslog_peer) {
  266.             p = ngx_syslog_add_header(log[l].syslog_peer, line);
  267.         }

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

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

  272.             size = p - line;

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

  274.             if (n < 0) {
  275.                 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  276.                               "send() to syslog failed");

  277.             } else if ((size_t) n != size) {
  278.                 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  279.                               "send() to syslog has written only %z of %uz",
  280.                               n, size);
  281.             }

  282.             continue;
  283.         }

  284.         ngx_linefeed(p);

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

  287.     return NGX_OK;
  288. }


  289. static void
  290. ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
  291.     size_t len)
  292. {
  293.     u_char              *name;
  294.     time_t               now;
  295.     ssize_t              n;
  296.     ngx_err_t            err;
  297. #if (NGX_ZLIB)
  298.     ngx_http_log_buf_t  *buffer;
  299. #endif

  300.     if (log->script == NULL) {
  301.         name = log->file->name.data;

  302. #if (NGX_ZLIB)
  303.         buffer = log->file->data;

  304.         if (buffer && buffer->gzip) {
  305.             n = ngx_http_log_gzip(log->file->fd, buf, len, buffer->gzip,
  306.                                   r->connection->log);
  307.         } else {
  308.             n = ngx_write_fd(log->file->fd, buf, len);
  309.         }
  310. #else
  311.         n = ngx_write_fd(log->file->fd, buf, len);
  312. #endif

  313.     } else {
  314.         name = NULL;
  315.         n = ngx_http_log_script_write(r, log->script, &name, buf, len);
  316.     }

  317.     if (n == (ssize_t) len) {
  318.         return;
  319.     }

  320.     now = ngx_time();

  321.     if (n == -1) {
  322.         err = ngx_errno;

  323.         if (err == NGX_ENOSPC) {
  324.             log->disk_full_time = now;
  325.         }

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

  329.             log->error_log_time = now;
  330.         }

  331.         return;
  332.     }

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

  337.         log->error_log_time = now;
  338.     }
  339. }


  340. static ssize_t
  341. ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
  342.     u_char **name, u_char *buf, size_t len)
  343. {
  344.     size_t                     root;
  345.     ssize_t                    n;
  346.     ngx_str_t                  log, path;
  347.     ngx_open_file_info_t       of;
  348.     ngx_http_log_loc_conf_t   *llcf;
  349.     ngx_http_core_loc_conf_t  *clcf;

  350.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  351.     if (!r->root_tested) {

  352.         /* test root directory existence */

  353.         if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
  354.             /* simulate successful logging */
  355.             return len;
  356.         }

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

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

  359.         of.valid = clcf->open_file_cache_valid;
  360.         of.min_uses = clcf->open_file_cache_min_uses;
  361.         of.test_dir = 1;
  362.         of.test_only = 1;
  363.         of.errors = clcf->open_file_cache_errors;
  364.         of.events = clcf->open_file_cache_events;

  365.         if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
  366.             /* simulate successful logging */
  367.             return len;
  368.         }

  369.         if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
  370.             != NGX_OK)
  371.         {
  372.             if (of.err == 0) {
  373.                 /* simulate successful logging */
  374.                 return len;
  375.             }

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

  378.             /* simulate successful logging */
  379.             return len;
  380.         }

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

  384.             /* simulate successful logging */
  385.             return len;
  386.         }
  387.     }

  388.     if (ngx_http_script_run(r, &log, script->lengths->elts, 1,
  389.                             script->values->elts)
  390.         == NULL)
  391.     {
  392.         /* simulate successful logging */
  393.         return len;
  394.     }

  395.     log.data[log.len - 1] = '\0';
  396.     *name = log.data;

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

  399.     llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);

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

  401.     of.log = 1;
  402.     of.valid = llcf->open_file_cache_valid;
  403.     of.min_uses = llcf->open_file_cache_min_uses;
  404.     of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;

  405.     if (ngx_http_set_disable_symlinks(r, clcf, &log, &of) != NGX_OK) {
  406.         /* simulate successful logging */
  407.         return len;
  408.     }

  409.     if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool)
  410.         != NGX_OK)
  411.     {
  412.         ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
  413.                       "%s \"%s\" failed", of.failed, log.data);
  414.         /* simulate successful logging */
  415.         return len;
  416.     }

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

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

  420.     return n;
  421. }


  422. #if (NGX_ZLIB)

  423. static ssize_t
  424. ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,
  425.     ngx_log_t *log)
  426. {
  427.     int          rc, wbits, memlevel;
  428.     u_char      *out;
  429.     size_t       size;
  430.     ssize_t      n;
  431.     z_stream     zstream;
  432.     ngx_err_t    err;
  433.     ngx_pool_t  *pool;

  434.     wbits = MAX_WBITS;
  435.     memlevel = MAX_MEM_LEVEL - 1;

  436.     while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) {
  437.         wbits--;
  438.         memlevel--;
  439.     }

  440.     /*
  441.      * This is a formula from deflateBound() for conservative upper bound of
  442.      * compressed data plus 18 bytes of gzip wrapper.
  443.      */

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

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

  446.     pool = ngx_create_pool(256, log);
  447.     if (pool == NULL) {
  448.         /* simulate successful logging */
  449.         return len;
  450.     }

  451.     pool->log = log;

  452.     zstream.zalloc = ngx_http_log_gzip_alloc;
  453.     zstream.zfree = ngx_http_log_gzip_free;
  454.     zstream.opaque = pool;

  455.     out = ngx_pnalloc(pool, size);
  456.     if (out == NULL) {
  457.         goto done;
  458.     }

  459.     zstream.next_in = buf;
  460.     zstream.avail_in = len;
  461.     zstream.next_out = out;
  462.     zstream.avail_out = size;

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

  465.     if (rc != Z_OK) {
  466.         ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateInit2() failed: %d", rc);
  467.         goto done;
  468.     }

  469.     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, log, 0,
  470.                    "deflate in: ni:%p no:%p ai:%ud ao:%ud",
  471.                    zstream.next_in, zstream.next_out,
  472.                    zstream.avail_in, zstream.avail_out);

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

  474.     if (rc != Z_STREAM_END) {
  475.         ngx_log_error(NGX_LOG_ALERT, log, 0,
  476.                       "deflate(Z_FINISH) failed: %d", rc);
  477.         goto done;
  478.     }

  479.     ngx_log_debug5(NGX_LOG_DEBUG_HTTP, log, 0,
  480.                    "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
  481.                    zstream.next_in, zstream.next_out,
  482.                    zstream.avail_in, zstream.avail_out,
  483.                    rc);

  484.     size -= zstream.avail_out;

  485.     rc = deflateEnd(&zstream);

  486.     if (rc != Z_OK) {
  487.         ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc);
  488.         goto done;
  489.     }

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

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

  493.         ngx_destroy_pool(pool);

  494.         ngx_set_errno(err);
  495.         return -1;
  496.     }

  497. done:

  498.     ngx_destroy_pool(pool);

  499.     /* simulate successful logging */
  500.     return len;
  501. }


  502. static void *
  503. ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size)
  504. {
  505.     ngx_pool_t *pool = opaque;

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

  508.     return ngx_palloc(pool, items * size);
  509. }


  510. static void
  511. ngx_http_log_gzip_free(void *opaque, void *address)
  512. {
  513. #if 0
  514.     ngx_pool_t *pool = opaque;

  515.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0, "gzip free: %p", address);
  516. #endif
  517. }

  518. #endif


  519. static void
  520. ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log)
  521. {
  522.     size_t               len;
  523.     ssize_t              n;
  524.     ngx_http_log_buf_t  *buffer;

  525.     buffer = file->data;

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

  527.     if (len == 0) {
  528.         return;
  529.     }

  530. #if (NGX_ZLIB)
  531.     if (buffer->gzip) {
  532.         n = ngx_http_log_gzip(file->fd, buffer->start, len, buffer->gzip, log);
  533.     } else {
  534.         n = ngx_write_fd(file->fd, buffer->start, len);
  535.     }
  536. #else
  537.     n = ngx_write_fd(file->fd, buffer->start, len);
  538. #endif

  539.     if (n == -1) {
  540.         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
  541.                       ngx_write_fd_n " to \"%s\" failed",
  542.                       file->name.data);

  543.     } else if ((size_t) n != len) {
  544.         ngx_log_error(NGX_LOG_ALERT, log, 0,
  545.                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
  546.                       file->name.data, n, len);
  547.     }

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

  549.     if (buffer->event && buffer->event->timer_set) {
  550.         ngx_del_timer(buffer->event);
  551.     }
  552. }


  553. static void
  554. ngx_http_log_flush_handler(ngx_event_t *ev)
  555. {
  556.     ngx_open_file_t     *file;
  557.     ngx_http_log_buf_t  *buffer;

  558.     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  559.                    "http log buffer flush handler");

  560.     if (ev->timedout) {
  561.         ngx_http_log_flush(ev->data, ev->log);
  562.         return;
  563.     }

  564.     /* cancel the flush timer for graceful shutdown */

  565.     file = ev->data;
  566.     buffer = file->data;

  567.     buffer->event = NULL;
  568. }


  569. static u_char *
  570. ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
  571.     ngx_http_log_op_t *op)
  572. {
  573.     size_t     len;
  574.     uintptr_t  data;

  575.     len = op->len;
  576.     data = op->data;

  577.     while (len--) {
  578.         *buf++ = (u_char) (data & 0xff);
  579.         data >>= 8;
  580.     }

  581.     return buf;
  582. }


  583. static u_char *
  584. ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf,
  585.     ngx_http_log_op_t *op)
  586. {
  587.     return ngx_cpymem(buf, (u_char *) op->data, op->len);
  588. }


  589. static u_char *
  590. ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
  591. {
  592.     if (r->pipeline) {
  593.         *buf = 'p';
  594.     } else {
  595.         *buf = '.';
  596.     }

  597.     return buf + 1;
  598. }


  599. static u_char *
  600. ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
  601. {
  602.     return ngx_cpymem(buf, ngx_cached_http_log_time.data,
  603.                       ngx_cached_http_log_time.len);
  604. }

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

  611. static u_char *
  612. ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
  613. {
  614.     ngx_time_t  *tp;

  615.     tp = ngx_timeofday();

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


  618. static u_char *
  619. ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
  620.     ngx_http_log_op_t *op)
  621. {
  622.     ngx_time_t      *tp;
  623.     ngx_msec_int_t   ms;

  624.     tp = ngx_timeofday();

  625.     ms = (ngx_msec_int_t)
  626.              ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
  627.     ms = ngx_max(ms, 0);

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


  630. static u_char *
  631. ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
  632. {
  633.     ngx_uint_t  status;

  634.     if (r->err_status) {
  635.         status = r->err_status;

  636.     } else if (r->headers_out.status) {
  637.         status = r->headers_out.status;

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

  640.     } else {
  641.         status = 0;
  642.     }

  643.     return ngx_sprintf(buf, "%03ui", status);
  644. }


  645. static u_char *
  646. ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
  647.     ngx_http_log_op_t *op)
  648. {
  649.     return ngx_sprintf(buf, "%O", r->connection->sent);
  650. }


  651. /*
  652. * although there is a real $body_bytes_sent variable,
  653. * this log operation code function is more optimized for logging
  654. */

  655. static u_char *
  656. ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
  657.     ngx_http_log_op_t *op)
  658. {
  659.     off_t  length;

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

  661.     if (length > 0) {
  662.         return ngx_sprintf(buf, "%O", length);
  663.     }

  664.     *buf = '0';

  665.     return buf + 1;
  666. }


  667. static u_char *
  668. ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
  669.     ngx_http_log_op_t *op)
  670. {
  671.     return ngx_sprintf(buf, "%O", r->request_length);
  672. }


  673. static ngx_int_t
  674. ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
  675.     ngx_str_t *value)
  676. {
  677.     ngx_int_t  index;

  678.     index = ngx_http_get_variable_index(cf, value);
  679.     if (index == NGX_ERROR) {
  680.         return NGX_ERROR;
  681.     }

  682.     op->len = 0;
  683.     op->getlen = ngx_http_log_variable_getlen;
  684.     op->run = ngx_http_log_variable;
  685.     op->data = index;

  686.     return NGX_OK;
  687. }


  688. static size_t
  689. ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data)
  690. {
  691.     uintptr_t                   len;
  692.     ngx_http_variable_value_t  *value;

  693.     value = ngx_http_get_indexed_variable(r, data);

  694.     if (value == NULL || value->not_found) {
  695.         return 1;
  696.     }

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

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

  699.     return value->len + len * 3;
  700. }


  701. static u_char *
  702. ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
  703. {
  704.     ngx_http_variable_value_t  *value;

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

  706.     if (value == NULL || value->not_found) {
  707.         *buf = '-';
  708.         return buf + 1;
  709.     }

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

  712.     } else {
  713.         return (u_char *) ngx_http_log_escape(buf, value->data, value->len);
  714.     }
  715. }


  716. static uintptr_t
  717. ngx_http_log_escape(u_char *dst, u_char *src, size_t size)
  718. {
  719.     ngx_uint_t      n;
  720.     static u_char   hex[] = "0123456789ABCDEF";

  721.     static uint32_t   escape[] = {
  722.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */

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

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

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

  729.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  730.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  731.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  732.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  733.     };


  734.     if (dst == NULL) {

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

  736.         n = 0;

  737.         while (size) {
  738.             if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
  739.                 n++;
  740.             }
  741.             src++;
  742.             size--;
  743.         }

  744.         return (uintptr_t) n;
  745.     }

  746.     while (size) {
  747.         if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
  748.             *dst++ = '\\';
  749.             *dst++ = 'x';
  750.             *dst++ = hex[*src >> 4];
  751.             *dst++ = hex[*src & 0xf];
  752.             src++;

  753.         } else {
  754.             *dst++ = *src++;
  755.         }
  756.         size--;
  757.     }

  758.     return (uintptr_t) dst;
  759. }


  760. static void *
  761. ngx_http_log_create_main_conf(ngx_conf_t *cf)
  762. {
  763.     ngx_http_log_main_conf_t  *conf;

  764.     ngx_http_log_fmt_t  *fmt;

  765.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
  766.     if (conf == NULL) {
  767.         return NULL;
  768.     }

  769.     if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t))
  770.         != NGX_OK)
  771.     {
  772.         return NULL;
  773.     }

  774.     fmt = ngx_array_push(&conf->formats);
  775.     if (fmt == NULL) {
  776.         return NULL;
  777.     }

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

  779.     fmt->flushes = NULL;

  780.     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
  781.     if (fmt->ops == NULL) {
  782.         return NULL;
  783.     }

  784.     return conf;
  785. }


  786. static void *
  787. ngx_http_log_create_loc_conf(ngx_conf_t *cf)
  788. {
  789.     ngx_http_log_loc_conf_t  *conf;

  790.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t));
  791.     if (conf == NULL) {
  792.         return NULL;
  793.     }

  794.     conf->open_file_cache = NGX_CONF_UNSET_PTR;

  795.     return conf;
  796. }


  797. static char *
  798. ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  799. {
  800.     ngx_http_log_loc_conf_t *prev = parent;
  801.     ngx_http_log_loc_conf_t *conf = child;

  802.     ngx_http_log_t            *log;
  803.     ngx_http_log_fmt_t        *fmt;
  804.     ngx_http_log_main_conf_t  *lmcf;

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

  806.         conf->open_file_cache = prev->open_file_cache;
  807.         conf->open_file_cache_valid = prev->open_file_cache_valid;
  808.         conf->open_file_cache_min_uses = prev->open_file_cache_min_uses;

  809.         if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
  810.             conf->open_file_cache = NULL;
  811.         }
  812.     }

  813.     if (conf->logs || conf->off) {
  814.         return NGX_CONF_OK;
  815.     }

  816.     conf->logs = prev->logs;
  817.     conf->off = prev->off;

  818.     if (conf->logs || conf->off) {
  819.         return NGX_CONF_OK;
  820.     }

  821.     conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
  822.     if (conf->logs == NULL) {
  823.         return NGX_CONF_ERROR;
  824.     }

  825.     log = ngx_array_push(conf->logs);
  826.     if (log == NULL) {
  827.         return NGX_CONF_ERROR;
  828.     }

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

  830.     log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log);
  831.     if (log->file == NULL) {
  832.         return NGX_CONF_ERROR;
  833.     }

  834.     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
  835.     fmt = lmcf->formats.elts;

  836.     /* the default "combined" format */
  837.     log->format = &fmt[0];
  838.     lmcf->combined_used = 1;

  839.     return NGX_CONF_OK;
  840. }


  841. static char *
  842. ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  843. {
  844.     ngx_http_log_loc_conf_t *llcf = conf;

  845.     ssize_t                            size;
  846.     ngx_int_t                          gzip;
  847.     ngx_uint_t                         i, n;
  848.     ngx_msec_t                         flush;
  849.     ngx_str_t                         *value, name, s;
  850.     ngx_http_log_t                    *log;
  851.     ngx_syslog_peer_t                 *peer;
  852.     ngx_http_log_buf_t                *buffer;
  853.     ngx_http_log_fmt_t                *fmt;
  854.     ngx_http_log_main_conf_t          *lmcf;
  855.     ngx_http_script_compile_t          sc;
  856.     ngx_http_compile_complex_value_t   ccv;

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

  858.     if (ngx_strcmp(value[1].data, "off") == 0) {
  859.         llcf->off = 1;
  860.         if (cf->args->nelts == 2) {
  861.             return NGX_CONF_OK;
  862.         }

  863.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  864.                            "invalid parameter \"%V\"", &value[2]);
  865.         return NGX_CONF_ERROR;
  866.     }

  867.     if (llcf->logs == NULL) {
  868.         llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
  869.         if (llcf->logs == NULL) {
  870.             return NGX_CONF_ERROR;
  871.         }
  872.     }

  873.     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);

  874.     log = ngx_array_push(llcf->logs);
  875.     if (log == NULL) {
  876.         return NGX_CONF_ERROR;
  877.     }

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


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

  880.         peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
  881.         if (peer == NULL) {
  882.             return NGX_CONF_ERROR;
  883.         }

  884.         if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
  885.             return NGX_CONF_ERROR;
  886.         }

  887.         log->syslog_peer = peer;

  888.         goto process_formats;
  889.     }

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

  891.     if (n == 0) {
  892.         log->file = ngx_conf_open_file(cf->cycle, &value[1]);
  893.         if (log->file == NULL) {
  894.             return NGX_CONF_ERROR;
  895.         }

  896.     } else {
  897.         if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
  898.             return NGX_CONF_ERROR;
  899.         }

  900.         log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t));
  901.         if (log->script == NULL) {
  902.             return NGX_CONF_ERROR;
  903.         }

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

  905.         sc.cf = cf;
  906.         sc.source = &value[1];
  907.         sc.lengths = &log->script->lengths;
  908.         sc.values = &log->script->values;
  909.         sc.variables = n;
  910.         sc.complete_lengths = 1;
  911.         sc.complete_values = 1;

  912.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  913.             return NGX_CONF_ERROR;
  914.         }
  915.     }

  916. process_formats:

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

  919.         if (ngx_strcmp(name.data, "combined") == 0) {
  920.             lmcf->combined_used = 1;
  921.         }

  922.     } else {
  923.         ngx_str_set(&name, "combined");
  924.         lmcf->combined_used = 1;
  925.     }

  926.     fmt = lmcf->formats.elts;
  927.     for (i = 0; i < lmcf->formats.nelts; i++) {
  928.         if (fmt[i].name.len == name.len
  929.             && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
  930.         {
  931.             log->format = &fmt[i];
  932.             break;
  933.         }
  934.     }

  935.     if (log->format == NULL) {
  936.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  937.                            "unknown log format \"%V\"", &name);
  938.         return NGX_CONF_ERROR;
  939.     }

  940.     size = 0;
  941.     flush = 0;
  942.     gzip = 0;

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

  944.         if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
  945.             s.len = value[i].len - 7;
  946.             s.data = value[i].data + 7;

  947.             size = ngx_parse_size(&s);

  948.             if (size == NGX_ERROR || size == 0) {
  949.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  950.                                    "invalid buffer size \"%V\"", &s);
  951.                 return NGX_CONF_ERROR;
  952.             }

  953.             continue;
  954.         }

  955.         if (ngx_strncmp(value[i].data, "flush=", 6) == 0) {
  956.             s.len = value[i].len - 6;
  957.             s.data = value[i].data + 6;

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

  959.             if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) {
  960.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  961.                                    "invalid flush time \"%V\"", &s);
  962.                 return NGX_CONF_ERROR;
  963.             }

  964.             continue;
  965.         }

  966.         if (ngx_strncmp(value[i].data, "gzip", 4) == 0
  967.             && (value[i].len == 4 || value[i].data[4] == '='))
  968.         {
  969. #if (NGX_ZLIB)
  970.             if (size == 0) {
  971.                 size = 64 * 1024;
  972.             }

  973.             if (value[i].len == 4) {
  974.                 gzip = Z_BEST_SPEED;
  975.                 continue;
  976.             }

  977.             s.len = value[i].len - 5;
  978.             s.data = value[i].data + 5;

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

  980.             if (gzip < 1 || gzip > 9) {
  981.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  982.                                    "invalid compression level \"%V\"", &s);
  983.                 return NGX_CONF_ERROR;
  984.             }

  985.             continue;

  986. #else
  987.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  988.                                "nginx was built without zlib support");
  989.             return NGX_CONF_ERROR;
  990. #endif
  991.         }

  992.         if (ngx_strncmp(value[i].data, "if=", 3) == 0) {
  993.             s.len = value[i].len - 3;
  994.             s.data = value[i].data + 3;

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

  996.             ccv.cf = cf;
  997.             ccv.value = &s;
  998.             ccv.complex_value = ngx_palloc(cf->pool,
  999.                                            sizeof(ngx_http_complex_value_t));
  1000.             if (ccv.complex_value == NULL) {
  1001.                 return NGX_CONF_ERROR;
  1002.             }

  1003.             if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  1004.                 return NGX_CONF_ERROR;
  1005.             }

  1006.             log->filter = ccv.complex_value;

  1007.             continue;
  1008.         }

  1009.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1010.                            "invalid parameter \"%V\"", &value[i]);
  1011.         return NGX_CONF_ERROR;
  1012.     }

  1013.     if (flush && size == 0) {
  1014.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1015.                            "no buffer is defined for access_log \"%V\"",
  1016.                            &value[1]);
  1017.         return NGX_CONF_ERROR;
  1018.     }

  1019.     if (size) {

  1020.         if (log->script) {
  1021.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1022.                                "buffered logs cannot have variables in name");
  1023.             return NGX_CONF_ERROR;
  1024.         }

  1025.         if (log->syslog_peer) {
  1026.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1027.                                "logs to syslog cannot be buffered");
  1028.             return NGX_CONF_ERROR;
  1029.         }

  1030.         if (log->file->data) {
  1031.             buffer = log->file->data;

  1032.             if (buffer->last - buffer->start != size
  1033.                 || buffer->flush != flush
  1034.                 || buffer->gzip != gzip)
  1035.             {
  1036.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1037.                                    "access_log \"%V\" already defined "
  1038.                                    "with conflicting parameters",
  1039.                                    &value[1]);
  1040.                 return NGX_CONF_ERROR;
  1041.             }

  1042.             return NGX_CONF_OK;
  1043.         }

  1044.         buffer = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_buf_t));
  1045.         if (buffer == NULL) {
  1046.             return NGX_CONF_ERROR;
  1047.         }

  1048.         buffer->start = ngx_pnalloc(cf->pool, size);
  1049.         if (buffer->start == NULL) {
  1050.             return NGX_CONF_ERROR;
  1051.         }

  1052.         buffer->pos = buffer->start;
  1053.         buffer->last = buffer->start + size;

  1054.         if (flush) {
  1055.             buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
  1056.             if (buffer->event == NULL) {
  1057.                 return NGX_CONF_ERROR;
  1058.             }

  1059.             buffer->event->data = log->file;
  1060.             buffer->event->handler = ngx_http_log_flush_handler;
  1061.             buffer->event->log = &cf->cycle->new_log;
  1062.             buffer->event->cancelable = 1;

  1063.             buffer->flush = flush;
  1064.         }

  1065.         buffer->gzip = gzip;

  1066.         log->file->flush = ngx_http_log_flush;
  1067.         log->file->data = buffer;
  1068.     }

  1069.     return NGX_CONF_OK;
  1070. }


  1071. static char *
  1072. ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1073. {
  1074.     ngx_http_log_main_conf_t *lmcf = conf;

  1075.     ngx_str_t           *value;
  1076.     ngx_uint_t           i;
  1077.     ngx_http_log_fmt_t  *fmt;

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

  1079.     fmt = lmcf->formats.elts;
  1080.     for (i = 0; i < lmcf->formats.nelts; i++) {
  1081.         if (fmt[i].name.len == value[1].len
  1082.             && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
  1083.         {
  1084.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1085.                                "duplicate \"log_format\" name \"%V\"",
  1086.                                &value[1]);
  1087.             return NGX_CONF_ERROR;
  1088.         }
  1089.     }

  1090.     fmt = ngx_array_push(&lmcf->formats);
  1091.     if (fmt == NULL) {
  1092.         return NGX_CONF_ERROR;
  1093.     }

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

  1095.     fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
  1096.     if (fmt->flushes == NULL) {
  1097.         return NGX_CONF_ERROR;
  1098.     }

  1099.     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
  1100.     if (fmt->ops == NULL) {
  1101.         return NGX_CONF_ERROR;
  1102.     }

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


  1105. static char *
  1106. ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
  1107.     ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
  1108. {
  1109.     u_char              *data, *p, ch;
  1110.     size_t               i, len;
  1111.     ngx_str_t           *value, var;
  1112.     ngx_int_t           *flush;
  1113.     ngx_uint_t           bracket;
  1114.     ngx_http_log_op_t   *op;
  1115.     ngx_http_log_var_t  *v;

  1116.     value = args->elts;

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

  1118.         i = 0;

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

  1120.             op = ngx_array_push(ops);
  1121.             if (op == NULL) {
  1122.                 return NGX_CONF_ERROR;
  1123.             }

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

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

  1126.                 if (++i == value[s].len) {
  1127.                     goto invalid;
  1128.                 }

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

  1131.                     if (++i == value[s].len) {
  1132.                         goto invalid;
  1133.                     }

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

  1135.                 } else {
  1136.                     bracket = 0;
  1137.                     var.data = &value[s].data[i];
  1138.                 }

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

  1141.                     if (ch == '}' && bracket) {
  1142.                         i++;
  1143.                         bracket = 0;
  1144.                         break;
  1145.                     }

  1146.                     if ((ch >= 'A' && ch <= 'Z')
  1147.                         || (ch >= 'a' && ch <= 'z')
  1148.                         || (ch >= '0' && ch <= '9')
  1149.                         || ch == '_')
  1150.                     {
  1151.                         continue;
  1152.                     }

  1153.                     break;
  1154.                 }

  1155.                 if (bracket) {
  1156.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1157.                                        "the closing bracket in \"%V\" "
  1158.                                        "variable is missing", &var);
  1159.                     return NGX_CONF_ERROR;
  1160.                 }

  1161.                 if (var.len == 0) {
  1162.                     goto invalid;
  1163.                 }

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

  1165.                     if (v->name.len == var.len
  1166.                         && ngx_strncmp(v->name.data, var.data, var.len) == 0)
  1167.                     {
  1168.                         op->len = v->len;
  1169.                         op->getlen = NULL;
  1170.                         op->run = v->run;
  1171.                         op->data = 0;

  1172.                         goto found;
  1173.                     }
  1174.                 }

  1175.                 if (ngx_http_log_variable_compile(cf, op, &var) != NGX_OK) {
  1176.                     return NGX_CONF_ERROR;
  1177.                 }

  1178.                 if (flushes) {

  1179.                     flush = ngx_array_push(flushes);
  1180.                     if (flush == NULL) {
  1181.                         return NGX_CONF_ERROR;
  1182.                     }

  1183.                     *flush = op->data; /* variable index */
  1184.                 }

  1185.             found:

  1186.                 continue;
  1187.             }

  1188.             i++;

  1189.             while (i < value[s].len && value[s].data[i] != '$') {
  1190.                 i++;
  1191.             }

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

  1193.             if (len) {

  1194.                 op->len = len;
  1195.                 op->getlen = NULL;

  1196.                 if (len <= sizeof(uintptr_t)) {
  1197.                     op->run = ngx_http_log_copy_short;
  1198.                     op->data = 0;

  1199.                     while (len--) {
  1200.                         op->data <<= 8;
  1201.                         op->data |= data[len];
  1202.                     }

  1203.                 } else {
  1204.                     op->run = ngx_http_log_copy_long;

  1205.                     p = ngx_pnalloc(cf->pool, len);
  1206.                     if (p == NULL) {
  1207.                         return NGX_CONF_ERROR;
  1208.                     }

  1209.                     ngx_memcpy(p, data, len);
  1210.                     op->data = (uintptr_t) p;
  1211.                 }
  1212.             }
  1213.         }
  1214.     }

  1215.     return NGX_CONF_OK;

  1216. invalid:

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

  1218.     return NGX_CONF_ERROR;
  1219. }


  1220. static char *
  1221. ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1222. {
  1223.     ngx_http_log_loc_conf_t *llcf = conf;

  1224.     time_t       inactive, valid;
  1225.     ngx_str_t   *value, s;
  1226.     ngx_int_t    max, min_uses;
  1227.     ngx_uint_t   i;

  1228.     if (llcf->open_file_cache != NGX_CONF_UNSET_PTR) {
  1229.         return "is duplicate";
  1230.     }

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

  1232.     max = 0;
  1233.     inactive = 10;
  1234.     valid = 60;
  1235.     min_uses = 1;

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

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

  1238.             max = ngx_atoi(value[i].data + 4, value[i].len - 4);
  1239.             if (max == NGX_ERROR) {
  1240.                 goto failed;
  1241.             }

  1242.             continue;
  1243.         }

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

  1245.             s.len = value[i].len - 9;
  1246.             s.data = value[i].data + 9;

  1247.             inactive = ngx_parse_time(&s, 1);
  1248.             if (inactive == (time_t) NGX_ERROR) {
  1249.                 goto failed;
  1250.             }

  1251.             continue;
  1252.         }

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

  1254.             min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
  1255.             if (min_uses == NGX_ERROR) {
  1256.                 goto failed;
  1257.             }

  1258.             continue;
  1259.         }

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

  1261.             s.len = value[i].len - 6;
  1262.             s.data = value[i].data + 6;

  1263.             valid = ngx_parse_time(&s, 1);
  1264.             if (valid == (time_t) NGX_ERROR) {
  1265.                 goto failed;
  1266.             }

  1267.             continue;
  1268.         }

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

  1270.             llcf->open_file_cache = NULL;

  1271.             continue;
  1272.         }

  1273.     failed:

  1274.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1275.                            "invalid \"open_log_file_cache\" parameter \"%V\"",
  1276.                            &value[i]);
  1277.         return NGX_CONF_ERROR;
  1278.     }

  1279.     if (llcf->open_file_cache == NULL) {
  1280.         return NGX_CONF_OK;
  1281.     }

  1282.     if (max == 0) {
  1283.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1284.                         "\"open_log_file_cache\" must have \"max\" parameter");
  1285.         return NGX_CONF_ERROR;
  1286.     }

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

  1288.     if (llcf->open_file_cache) {

  1289.         llcf->open_file_cache_valid = valid;
  1290.         llcf->open_file_cache_min_uses = min_uses;

  1291.         return NGX_CONF_OK;
  1292.     }

  1293.     return NGX_CONF_ERROR;
  1294. }


  1295. static ngx_int_t
  1296. ngx_http_log_init(ngx_conf_t *cf)
  1297. {
  1298.     ngx_str_t                  *value;
  1299.     ngx_array_t                 a;
  1300.     ngx_http_handler_pt        *h;
  1301.     ngx_http_log_fmt_t         *fmt;
  1302.     ngx_http_log_main_conf_t   *lmcf;
  1303.     ngx_http_core_main_conf_t  *cmcf;

  1304.     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);

  1305.     if (lmcf->combined_used) {
  1306.         if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) {
  1307.             return NGX_ERROR;
  1308.         }

  1309.         value = ngx_array_push(&a);
  1310.         if (value == NULL) {
  1311.             return NGX_ERROR;
  1312.         }

  1313.         *value = ngx_http_combined_fmt;
  1314.         fmt = lmcf->formats.elts;

  1315.         if (ngx_http_log_compile_format(cf, NULL, fmt->ops, &a, 0)
  1316.             != NGX_CONF_OK)
  1317.         {
  1318.             return NGX_ERROR;
  1319.         }
  1320.     }

  1321.     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

  1322.     h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
  1323.     if (h == NULL) {
  1324.         return NGX_ERROR;
  1325.     }

  1326.     *h = ngx_http_log_handler;

  1327.     return NGX_OK;
  1328. }