src/http/modules/ngx_http_log_module.c - nginx-1.31.4 nginx/ @ 8d9666701

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.     u_char *end, 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.     u_char *end, ngx_http_log_op_t *op);
  81. static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
  82.     u_char *end, ngx_http_log_op_t *op);
  83. static u_char *ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf,
  84.     u_char *end, ngx_http_log_op_t *op);
  85. static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
  86.     u_char *end, ngx_http_log_op_t *op);
  87. static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
  88.     u_char *end, ngx_http_log_op_t *op);
  89. static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf,
  90.     u_char *end, ngx_http_log_op_t *op);
  91. static u_char *ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
  92.     u_char *end, ngx_http_log_op_t *op);
  93. static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
  94.     u_char *end, ngx_http_log_op_t *op);
  95. static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
  96.     u_char *end, 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.     u_char *end, 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.     u_char *end, 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, u_char *end, ngx_http_log_op_t *op);

  112. static ngx_int_t ngx_http_log_check_length(ngx_http_request_t *r,
  113.     u_char *buf, u_char *end, size_t len);


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


  127. static ngx_command_t  ngx_http_log_commands[] = {

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

  134.     { ngx_string("access_log"),
  135.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
  136.                         |NGX_HTTP_LMT_CONF|NGX_CONF_1MORE,
  137.       ngx_http_log_set_log,
  138.       NGX_HTTP_LOC_CONF_OFFSET,
  139.       0,
  140.       NULL },

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

  147.       ngx_null_command
  148. };


  149. static ngx_http_module_t  ngx_http_log_module_ctx = {
  150.     NULL,                                  /* preconfiguration */
  151.     ngx_http_log_init,                     /* postconfiguration */

  152.     ngx_http_log_create_main_conf,         /* create main configuration */
  153.     NULL,                                  /* init main configuration */

  154.     NULL,                                  /* create server configuration */
  155.     NULL,                                  /* merge server configuration */

  156.     ngx_http_log_create_loc_conf,          /* create location configuration */
  157.     ngx_http_log_merge_loc_conf            /* merge location configuration */
  158. };


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


  173. static ngx_str_t  ngx_http_access_log = ngx_string(NGX_HTTP_LOG_PATH);


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


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

  193.     { ngx_null_string, 0, NULL }
  194. };


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

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

  209.     lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);

  210.     if (lcf->off) {
  211.         return NGX_OK;
  212.     }

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

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

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

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

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

  229.             continue;
  230.         }

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

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

  237.             } else {
  238.                 len += op[i].len;
  239.             }
  240.         }

  241.         len += NGX_LINEFEED_SIZE;

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

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

  247.             goto alloc_line;
  248.         }

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

  250.         if (buffer) {

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

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

  254.                 buffer->pos = buffer->start;
  255.             }

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

  257.                 p = buffer->pos;
  258.                 end = p + len - NGX_LINEFEED_SIZE;

  259.                 if (buffer->event && p == buffer->start) {
  260.                     ngx_add_timer(buffer->event, buffer->flush);
  261.                 }

  262.                 for (i = 0; i < log[l].format->ops->nelts && p; i++) {
  263.                     p = op[i].run(r, p, end, &op[i]);
  264.                 }

  265.                 if (p == NULL) {
  266.                     return NGX_ERROR;
  267.                 }

  268.                 ngx_linefeed(p);

  269.                 buffer->pos = p;

  270.                 continue;
  271.             }

  272.             if (buffer->event && buffer->event->timer_set) {
  273.                 ngx_del_timer(buffer->event);
  274.             }
  275.         }

  276.     alloc_line:

  277.         line = ngx_pnalloc(r->pool, len);
  278.         if (line == NULL) {
  279.             return NGX_ERROR;
  280.         }

  281.         p = line;
  282.         end = line + len - NGX_LINEFEED_SIZE;

  283.         if (log[l].syslog_peer) {
  284.             p = ngx_syslog_add_header(log[l].syslog_peer, line);
  285.         }

  286.         for (i = 0; i < log[l].format->ops->nelts && p; i++) {
  287.             p = op[i].run(r, p, end, &op[i]);
  288.         }

  289.         if (p == NULL) {
  290.             return NGX_ERROR;
  291.         }

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

  293.             size = p - line;

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

  295.             if (n < 0) {
  296.                 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  297.                               "send() to syslog failed");

  298.             } else if ((size_t) n != size) {
  299.                 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  300.                               "send() to syslog has written only %z of %uz",
  301.                               n, size);
  302.             }

  303.             continue;
  304.         }

  305.         ngx_linefeed(p);

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

  308.     return NGX_OK;
  309. }


  310. static void
  311. ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
  312.     size_t len)
  313. {
  314.     u_char              *name;
  315.     time_t               now;
  316.     ssize_t              n;
  317.     ngx_err_t            err;
  318. #if (NGX_ZLIB)
  319.     ngx_http_log_buf_t  *buffer;
  320. #endif

  321.     if (log->script == NULL) {
  322.         name = log->file->name.data;

  323. #if (NGX_ZLIB)
  324.         buffer = log->file->data;

  325.         if (buffer && buffer->gzip) {
  326.             n = ngx_http_log_gzip(log->file->fd, buf, len, buffer->gzip,
  327.                                   r->connection->log);
  328.         } else {
  329.             n = ngx_write_fd(log->file->fd, buf, len);
  330.         }
  331. #else
  332.         n = ngx_write_fd(log->file->fd, buf, len);
  333. #endif

  334.     } else {
  335.         name = NULL;
  336.         n = ngx_http_log_script_write(r, log->script, &name, buf, len);
  337.     }

  338.     if (n == (ssize_t) len) {
  339.         return;
  340.     }

  341.     now = ngx_time();

  342.     if (n == -1) {
  343.         err = ngx_errno;

  344.         if (err == NGX_ENOSPC) {
  345.             log->disk_full_time = now;
  346.         }

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

  350.             log->error_log_time = now;
  351.         }

  352.         return;
  353.     }

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

  358.         log->error_log_time = now;
  359.     }
  360. }


  361. static ssize_t
  362. ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
  363.     u_char **name, u_char *buf, size_t len)
  364. {
  365.     size_t                     root;
  366.     ssize_t                    n;
  367.     ngx_str_t                  log, path;
  368.     ngx_open_file_info_t       of;
  369.     ngx_http_log_loc_conf_t   *llcf;
  370.     ngx_http_core_loc_conf_t  *clcf;

  371.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  372.     if (!r->root_tested) {

  373.         /* test root directory existence */

  374.         if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
  375.             /* simulate successful logging */
  376.             return len;
  377.         }

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

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

  380.         of.valid = clcf->open_file_cache_valid;
  381.         of.min_uses = clcf->open_file_cache_min_uses;
  382.         of.test_dir = 1;
  383.         of.test_only = 1;
  384.         of.errors = clcf->open_file_cache_errors;
  385.         of.events = clcf->open_file_cache_events;

  386.         if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
  387.             /* simulate successful logging */
  388.             return len;
  389.         }

  390.         if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
  391.             != NGX_OK)
  392.         {
  393.             if (of.err == 0) {
  394.                 /* simulate successful logging */
  395.                 return len;
  396.             }

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

  399.             /* simulate successful logging */
  400.             return len;
  401.         }

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

  405.             /* simulate successful logging */
  406.             return len;
  407.         }
  408.     }

  409.     if (ngx_http_script_run(r, &log, script->lengths->elts, 1,
  410.                             script->values->elts)
  411.         == NULL)
  412.     {
  413.         /* simulate successful logging */
  414.         return len;
  415.     }

  416.     log.data[log.len - 1] = '\0';
  417.     *name = log.data;

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

  420.     llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);

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

  422.     of.log = 1;
  423.     of.valid = llcf->open_file_cache_valid;
  424.     of.min_uses = llcf->open_file_cache_min_uses;
  425.     of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;

  426.     if (ngx_http_set_disable_symlinks(r, clcf, &log, &of) != NGX_OK) {
  427.         /* simulate successful logging */
  428.         return len;
  429.     }

  430.     if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool)
  431.         != NGX_OK)
  432.     {
  433.         if (of.err == 0) {
  434.             /* simulate successful logging */
  435.             return len;
  436.         }

  437.         ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
  438.                       "%s \"%s\" failed", of.failed, log.data);
  439.         /* simulate successful logging */
  440.         return len;
  441.     }

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

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

  445.     return n;
  446. }


  447. #if (NGX_ZLIB)

  448. static ssize_t
  449. ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,
  450.     ngx_log_t *log)
  451. {
  452.     int          rc, wbits, memlevel;
  453.     u_char      *out;
  454.     size_t       size;
  455.     ssize_t      n;
  456.     z_stream     zstream;
  457.     ngx_err_t    err;
  458.     ngx_pool_t  *pool;

  459.     wbits = MAX_WBITS;
  460.     memlevel = MAX_MEM_LEVEL - 1;

  461.     while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) {
  462.         wbits--;
  463.         memlevel--;
  464.     }

  465.     /*
  466.      * This is a formula from deflateBound() for conservative upper bound of
  467.      * compressed data plus 18 bytes of gzip wrapper.
  468.      */

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

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

  471.     pool = ngx_create_pool(256, log);
  472.     if (pool == NULL) {
  473.         /* simulate successful logging */
  474.         return len;
  475.     }

  476.     pool->log = log;

  477.     zstream.zalloc = ngx_http_log_gzip_alloc;
  478.     zstream.zfree = ngx_http_log_gzip_free;
  479.     zstream.opaque = pool;

  480.     out = ngx_pnalloc(pool, size);
  481.     if (out == NULL) {
  482.         goto done;
  483.     }

  484.     zstream.next_in = buf;
  485.     zstream.avail_in = len;
  486.     zstream.next_out = out;
  487.     zstream.avail_out = size;

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

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

  494.     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, log, 0,
  495.                    "deflate in: ni:%p no:%p ai:%ud ao:%ud",
  496.                    zstream.next_in, zstream.next_out,
  497.                    zstream.avail_in, zstream.avail_out);

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

  499.     if (rc != Z_STREAM_END) {
  500.         ngx_log_error(NGX_LOG_ALERT, log, 0,
  501.                       "deflate(Z_FINISH) failed: %d", rc);
  502.         goto done;
  503.     }

  504.     ngx_log_debug5(NGX_LOG_DEBUG_HTTP, log, 0,
  505.                    "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
  506.                    zstream.next_in, zstream.next_out,
  507.                    zstream.avail_in, zstream.avail_out,
  508.                    rc);

  509.     size -= zstream.avail_out;

  510.     rc = deflateEnd(&zstream);

  511.     if (rc != Z_OK) {
  512.         ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc);
  513.         goto done;
  514.     }

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

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

  518.         ngx_destroy_pool(pool);

  519.         ngx_set_errno(err);
  520.         return -1;
  521.     }

  522. done:

  523.     ngx_destroy_pool(pool);

  524.     /* simulate successful logging */
  525.     return len;
  526. }


  527. static void *
  528. ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size)
  529. {
  530.     ngx_pool_t *pool = opaque;

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

  533.     return ngx_palloc(pool, items * size);
  534. }


  535. static void
  536. ngx_http_log_gzip_free(void *opaque, void *address)
  537. {
  538. #if 0
  539.     ngx_pool_t *pool = opaque;

  540.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0, "gzip free: %p", address);
  541. #endif
  542. }

  543. #endif


  544. static void
  545. ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log)
  546. {
  547.     size_t               len;
  548.     ssize_t              n;
  549.     ngx_http_log_buf_t  *buffer;

  550.     buffer = file->data;

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

  552.     if (len == 0) {
  553.         return;
  554.     }

  555. #if (NGX_ZLIB)
  556.     if (buffer->gzip) {
  557.         n = ngx_http_log_gzip(file->fd, buffer->start, len, buffer->gzip, log);
  558.     } else {
  559.         n = ngx_write_fd(file->fd, buffer->start, len);
  560.     }
  561. #else
  562.     n = ngx_write_fd(file->fd, buffer->start, len);
  563. #endif

  564.     if (n == -1) {
  565.         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
  566.                       ngx_write_fd_n " to \"%s\" failed",
  567.                       file->name.data);

  568.     } else if ((size_t) n != len) {
  569.         ngx_log_error(NGX_LOG_ALERT, log, 0,
  570.                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
  571.                       file->name.data, n, len);
  572.     }

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

  574.     if (buffer->event && buffer->event->timer_set) {
  575.         ngx_del_timer(buffer->event);
  576.     }
  577. }


  578. static void
  579. ngx_http_log_flush_handler(ngx_event_t *ev)
  580. {
  581.     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  582.                    "http log buffer flush handler");

  583.     ngx_http_log_flush(ev->data, ev->log);
  584. }


  585. static u_char *
  586. ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf, u_char *end,
  587.     ngx_http_log_op_t *op)
  588. {
  589.     size_t     len;
  590.     uintptr_t  data;

  591.     len = op->len;
  592.     data = op->data;

  593.     if (ngx_http_log_check_length(r, buf, end, len) != NGX_OK) {
  594.         return NULL;
  595.     }

  596.     while (len--) {
  597.         *buf++ = (u_char) (data & 0xff);
  598.         data >>= 8;
  599.     }

  600.     return buf;
  601. }


  602. static u_char *
  603. ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf, u_char *end,
  604.     ngx_http_log_op_t *op)
  605. {
  606.     if (ngx_http_log_check_length(r, buf, end, op->len) != NGX_OK) {
  607.         return NULL;
  608.     }

  609.     return ngx_cpymem(buf, (u_char *) op->data, op->len);
  610. }


  611. static u_char *
  612. ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, u_char *end,
  613.     ngx_http_log_op_t *op)
  614. {
  615.     if (ngx_http_log_check_length(r, buf, end, 1) != NGX_OK) {
  616.         return NULL;
  617.     }

  618.     if (r->pipeline) {
  619.         *buf = 'p';
  620.     } else {
  621.         *buf = '.';
  622.     }

  623.     return buf + 1;
  624. }


  625. static u_char *
  626. ngx_http_log_time(ngx_http_request_t *r, u_char *buf, u_char *end,
  627.     ngx_http_log_op_t *op)
  628. {
  629.     if (ngx_http_log_check_length(r, buf, end, ngx_cached_http_log_time.len)
  630.         != NGX_OK)
  631.     {
  632.         return NULL;
  633.     }

  634.     return ngx_cpymem(buf, ngx_cached_http_log_time.data,
  635.                       ngx_cached_http_log_time.len);
  636. }

  637. static u_char *
  638. ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, u_char *end,
  639.     ngx_http_log_op_t *op)
  640. {
  641.     if (ngx_http_log_check_length(r, buf, end, ngx_cached_http_log_iso8601.len)
  642.         != NGX_OK)
  643.     {
  644.         return NULL;
  645.     }

  646.     return ngx_cpymem(buf, ngx_cached_http_log_iso8601.data,
  647.                       ngx_cached_http_log_iso8601.len);
  648. }

  649. static u_char *
  650. ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, u_char *end,
  651.     ngx_http_log_op_t *op)
  652. {
  653.     ngx_time_t  *tp;

  654.     if (ngx_http_log_check_length(r, buf, end, NGX_TIME_T_LEN + 4) != NGX_OK) {
  655.         return NULL;
  656.     }

  657.     tp = ngx_timeofday();

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


  660. static u_char *
  661. ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf, u_char *end,
  662.     ngx_http_log_op_t *op)
  663. {
  664.     ngx_time_t      *tp;
  665.     ngx_msec_int_t   ms;

  666.     if (ngx_http_log_check_length(r, buf, end, NGX_TIME_T_LEN + 4) != NGX_OK) {
  667.         return NULL;
  668.     }

  669.     tp = ngx_timeofday();

  670.     ms = (ngx_msec_int_t)
  671.              ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
  672.     ms = ngx_max(ms, 0);

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


  675. static u_char *
  676. ngx_http_log_status(ngx_http_request_t *r, u_char *buf, u_char *end,
  677.     ngx_http_log_op_t *op)
  678. {
  679.     ngx_uint_t  status;

  680.     if (ngx_http_log_check_length(r, buf, end, NGX_INT_T_LEN) != NGX_OK) {
  681.         return NULL;
  682.     }

  683.     if (r->err_status) {
  684.         status = r->err_status;

  685.     } else if (r->headers_out.status) {
  686.         status = r->headers_out.status;

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

  689.     } else {
  690.         status = 0;
  691.     }

  692.     return ngx_sprintf(buf, "%03ui", status);
  693. }


  694. static u_char *
  695. ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf, u_char *end,
  696.     ngx_http_log_op_t *op)
  697. {
  698.     if (ngx_http_log_check_length(r, buf, end, NGX_OFF_T_LEN) != NGX_OK) {
  699.         return NULL;
  700.     }

  701.     return ngx_sprintf(buf, "%O", r->connection->sent);
  702. }


  703. /*
  704. * although there is a real $body_bytes_sent variable,
  705. * this log operation code function is more optimized for logging
  706. */

  707. static u_char *
  708. ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf, u_char *end,
  709.     ngx_http_log_op_t *op)
  710. {
  711.     off_t  length;

  712.     if (ngx_http_log_check_length(r, buf, end, NGX_OFF_T_LEN) != NGX_OK) {
  713.         return NULL;
  714.     }

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

  716.     if (length > 0) {
  717.         return ngx_sprintf(buf, "%O", length);
  718.     }

  719.     *buf = '0';

  720.     return buf + 1;
  721. }


  722. static u_char *
  723. ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, u_char *end,
  724.     ngx_http_log_op_t *op)
  725. {
  726.     if (ngx_http_log_check_length(r, buf, end, NGX_OFF_T_LEN) != NGX_OK) {
  727.         return NULL;
  728.     }

  729.     return ngx_sprintf(buf, "%O", r->request_length);
  730. }


  731. static ngx_int_t
  732. ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
  733.     ngx_str_t *value, ngx_uint_t escape)
  734. {
  735.     ngx_int_t  index;

  736.     index = ngx_http_get_variable_index(cf, value);
  737.     if (index == NGX_ERROR) {
  738.         return NGX_ERROR;
  739.     }

  740.     op->len = 0;

  741.     switch (escape) {
  742.     case NGX_HTTP_LOG_ESCAPE_JSON:
  743.         op->getlen = ngx_http_log_json_variable_getlen;
  744.         op->run = ngx_http_log_json_variable;
  745.         break;

  746.     case NGX_HTTP_LOG_ESCAPE_NONE:
  747.         op->getlen = ngx_http_log_unescaped_variable_getlen;
  748.         op->run = ngx_http_log_unescaped_variable;
  749.         break;

  750.     default: /* NGX_HTTP_LOG_ESCAPE_DEFAULT */
  751.         op->getlen = ngx_http_log_variable_getlen;
  752.         op->run = ngx_http_log_variable;
  753.     }

  754.     op->data = index;

  755.     return NGX_OK;
  756. }


  757. static size_t
  758. ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data)
  759. {
  760.     uintptr_t                   len;
  761.     ngx_http_variable_value_t  *value;

  762.     value = ngx_http_get_indexed_variable(r, data);

  763.     if (value == NULL || value->not_found) {
  764.         return 1;
  765.     }

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

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

  768.     return value->len + len * 3;
  769. }


  770. static u_char *
  771. ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, u_char *end,
  772.     ngx_http_log_op_t *op)
  773. {
  774.     uintptr_t                   len;
  775.     ngx_http_variable_value_t  *value;

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

  777.     if (value == NULL || value->not_found) {
  778.         if (ngx_http_log_check_length(r, buf, end, 1) != NGX_OK) {
  779.             return NULL;
  780.         }

  781.         *buf = '-';
  782.         return buf + 1;
  783.     }

  784.     if (value->escape == 0) {
  785.         if (ngx_http_log_check_length(r, buf, end, value->len) != NGX_OK) {
  786.             return NULL;
  787.         }

  788.         return ngx_cpymem(buf, value->data, value->len);

  789.     } else {
  790.         len = ngx_http_log_escape(NULL, value->data, value->len);

  791.         if (ngx_http_log_check_length(r, buf, end, value->len + len * 3)
  792.             != NGX_OK)
  793.         {
  794.             return NULL;
  795.         }

  796.         return (u_char *) ngx_http_log_escape(buf, value->data, value->len);
  797.     }
  798. }


  799. static uintptr_t
  800. ngx_http_log_escape(u_char *dst, u_char *src, size_t size)
  801. {
  802.     ngx_uint_t      n;
  803.     static u_char   hex[] = "0123456789ABCDEF";

  804.     static uint32_t   escape[] = {
  805.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */

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

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

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

  812.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  813.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  814.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  815.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  816.     };


  817.     if (dst == NULL) {

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

  819.         n = 0;

  820.         while (size) {
  821.             if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
  822.                 n++;
  823.             }
  824.             src++;
  825.             size--;
  826.         }

  827.         return (uintptr_t) n;
  828.     }

  829.     while (size) {
  830.         if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
  831.             *dst++ = '\\';
  832.             *dst++ = 'x';
  833.             *dst++ = hex[*src >> 4];
  834.             *dst++ = hex[*src & 0xf];
  835.             src++;

  836.         } else {
  837.             *dst++ = *src++;
  838.         }
  839.         size--;
  840.     }

  841.     return (uintptr_t) dst;
  842. }


  843. static size_t
  844. ngx_http_log_json_variable_getlen(ngx_http_request_t *r, uintptr_t data)
  845. {
  846.     uintptr_t                   len;
  847.     ngx_http_variable_value_t  *value;

  848.     value = ngx_http_get_indexed_variable(r, data);

  849.     if (value == NULL || value->not_found) {
  850.         return 0;
  851.     }

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

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

  854.     return value->len + len;
  855. }


  856. static u_char *
  857. ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf, u_char *end,
  858.     ngx_http_log_op_t *op)
  859. {
  860.     uintptr_t                   len;
  861.     ngx_http_variable_value_t  *value;

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

  863.     if (value == NULL || value->not_found) {
  864.         return buf;
  865.     }

  866.     if (value->escape == 0) {
  867.         if (ngx_http_log_check_length(r, buf, end, value->len) != NGX_OK) {
  868.             return NULL;
  869.         }

  870.         return ngx_cpymem(buf, value->data, value->len);

  871.     } else {
  872.         len = ngx_escape_json(NULL, value->data, value->len);

  873.         if (ngx_http_log_check_length(r, buf, end, value->len + len)
  874.             != NGX_OK)
  875.         {
  876.             return NULL;
  877.         }

  878.         return (u_char *) ngx_escape_json(buf, value->data, value->len);
  879.     }
  880. }


  881. static size_t
  882. ngx_http_log_unescaped_variable_getlen(ngx_http_request_t *r, uintptr_t data)
  883. {
  884.     ngx_http_variable_value_t  *value;

  885.     value = ngx_http_get_indexed_variable(r, data);

  886.     if (value == NULL || value->not_found) {
  887.         return 0;
  888.     }

  889.     value->escape = 0;

  890.     return value->len;
  891. }


  892. static u_char *
  893. ngx_http_log_unescaped_variable(ngx_http_request_t *r, u_char *buf,
  894.     u_char *end, ngx_http_log_op_t *op)
  895. {
  896.     ngx_http_variable_value_t  *value;

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

  898.     if (value == NULL || value->not_found) {
  899.         return buf;
  900.     }

  901.     if (ngx_http_log_check_length(r, buf, end, value->len) != NGX_OK) {
  902.         return NULL;
  903.     }

  904.     return ngx_cpymem(buf, value->data, value->len);
  905. }


  906. static ngx_int_t
  907. ngx_http_log_check_length(ngx_http_request_t *r, u_char *buf, u_char *end,
  908.     size_t len)
  909. {
  910.     if (end - buf < (ssize_t) len) {
  911.         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  912.                       "no buffer space in log script copy");
  913.         return NGX_ERROR;
  914.     }

  915.     return NGX_OK;
  916. }


  917. static void *
  918. ngx_http_log_create_main_conf(ngx_conf_t *cf)
  919. {
  920.     ngx_http_log_main_conf_t  *conf;

  921.     ngx_http_log_fmt_t  *fmt;

  922.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
  923.     if (conf == NULL) {
  924.         return NULL;
  925.     }

  926.     if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t))
  927.         != NGX_OK)
  928.     {
  929.         return NULL;
  930.     }

  931.     fmt = ngx_array_push(&conf->formats);
  932.     if (fmt == NULL) {
  933.         return NULL;
  934.     }

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

  936.     fmt->flushes = NULL;

  937.     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
  938.     if (fmt->ops == NULL) {
  939.         return NULL;
  940.     }

  941.     return conf;
  942. }


  943. static void *
  944. ngx_http_log_create_loc_conf(ngx_conf_t *cf)
  945. {
  946.     ngx_http_log_loc_conf_t  *conf;

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

  951.     conf->open_file_cache = NGX_CONF_UNSET_PTR;

  952.     return conf;
  953. }


  954. static char *
  955. ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  956. {
  957.     ngx_http_log_loc_conf_t *prev = parent;
  958.     ngx_http_log_loc_conf_t *conf = child;

  959.     ngx_http_log_t            *log;
  960.     ngx_http_log_fmt_t        *fmt;
  961.     ngx_http_log_main_conf_t  *lmcf;

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

  963.         conf->open_file_cache = prev->open_file_cache;
  964.         conf->open_file_cache_valid = prev->open_file_cache_valid;
  965.         conf->open_file_cache_min_uses = prev->open_file_cache_min_uses;

  966.         if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
  967.             conf->open_file_cache = NULL;
  968.         }
  969.     }

  970.     if (conf->logs || conf->off) {
  971.         return NGX_CONF_OK;
  972.     }

  973.     conf->logs = prev->logs;
  974.     conf->off = prev->off;

  975.     if (conf->logs || conf->off) {
  976.         return NGX_CONF_OK;
  977.     }

  978.     conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
  979.     if (conf->logs == NULL) {
  980.         return NGX_CONF_ERROR;
  981.     }

  982.     log = ngx_array_push(conf->logs);
  983.     if (log == NULL) {
  984.         return NGX_CONF_ERROR;
  985.     }

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

  987.     log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log);
  988.     if (log->file == NULL) {
  989.         return NGX_CONF_ERROR;
  990.     }

  991.     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
  992.     fmt = lmcf->formats.elts;

  993.     /* the default "combined" format */
  994.     log->format = &fmt[0];
  995.     lmcf->combined_used = 1;

  996.     return NGX_CONF_OK;
  997. }


  998. static char *
  999. ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1000. {
  1001.     ngx_http_log_loc_conf_t *llcf = conf;

  1002.     ssize_t                            size;
  1003.     ngx_int_t                          gzip;
  1004.     ngx_uint_t                         i, n;
  1005.     ngx_msec_t                         flush;
  1006.     ngx_str_t                         *value, name, s;
  1007.     ngx_http_log_t                    *log;
  1008.     ngx_syslog_peer_t                 *peer;
  1009.     ngx_http_log_buf_t                *buffer;
  1010.     ngx_http_log_fmt_t                *fmt;
  1011.     ngx_http_log_main_conf_t          *lmcf;
  1012.     ngx_http_script_compile_t          sc;
  1013.     ngx_http_compile_complex_value_t   ccv;

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

  1015.     if (ngx_strcmp(value[1].data, "off") == 0) {
  1016.         llcf->off = 1;
  1017.         if (cf->args->nelts == 2) {
  1018.             return NGX_CONF_OK;
  1019.         }

  1020.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1021.                            "invalid parameter \"%V\"", &value[2]);
  1022.         return NGX_CONF_ERROR;
  1023.     }

  1024.     if (llcf->logs == NULL) {
  1025.         llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
  1026.         if (llcf->logs == NULL) {
  1027.             return NGX_CONF_ERROR;
  1028.         }
  1029.     }

  1030.     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);

  1031.     log = ngx_array_push(llcf->logs);
  1032.     if (log == NULL) {
  1033.         return NGX_CONF_ERROR;
  1034.     }

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


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

  1037.         peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
  1038.         if (peer == NULL) {
  1039.             return NGX_CONF_ERROR;
  1040.         }

  1041.         if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
  1042.             return NGX_CONF_ERROR;
  1043.         }

  1044.         log->syslog_peer = peer;

  1045.         goto process_formats;
  1046.     }

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

  1048.     if (n == 0) {
  1049.         log->file = ngx_conf_open_file(cf->cycle, &value[1]);
  1050.         if (log->file == NULL) {
  1051.             return NGX_CONF_ERROR;
  1052.         }

  1053.     } else {
  1054.         if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
  1055.             return NGX_CONF_ERROR;
  1056.         }

  1057.         log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t));
  1058.         if (log->script == NULL) {
  1059.             return NGX_CONF_ERROR;
  1060.         }

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

  1062.         sc.cf = cf;
  1063.         sc.source = &value[1];
  1064.         sc.lengths = &log->script->lengths;
  1065.         sc.values = &log->script->values;
  1066.         sc.variables = n;
  1067.         sc.complete_lengths = 1;
  1068.         sc.complete_values = 1;

  1069.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  1070.             return NGX_CONF_ERROR;
  1071.         }
  1072.     }

  1073. process_formats:

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

  1076.         if (ngx_strcmp(name.data, "combined") == 0) {
  1077.             lmcf->combined_used = 1;
  1078.         }

  1079.     } else {
  1080.         ngx_str_set(&name, "combined");
  1081.         lmcf->combined_used = 1;
  1082.     }

  1083.     fmt = lmcf->formats.elts;
  1084.     for (i = 0; i < lmcf->formats.nelts; i++) {
  1085.         if (fmt[i].name.len == name.len
  1086.             && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
  1087.         {
  1088.             log->format = &fmt[i];
  1089.             break;
  1090.         }
  1091.     }

  1092.     if (log->format == NULL) {
  1093.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1094.                            "unknown log format \"%V\"", &name);
  1095.         return NGX_CONF_ERROR;
  1096.     }

  1097.     size = 0;
  1098.     flush = 0;
  1099.     gzip = 0;

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

  1101.         if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
  1102.             s.len = value[i].len - 7;
  1103.             s.data = value[i].data + 7;

  1104.             size = ngx_parse_size(&s);

  1105.             if (size == NGX_ERROR || size == 0) {
  1106.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1107.                                    "invalid buffer size \"%V\"", &s);
  1108.                 return NGX_CONF_ERROR;
  1109.             }

  1110.             continue;
  1111.         }

  1112.         if (ngx_strncmp(value[i].data, "flush=", 6) == 0) {
  1113.             s.len = value[i].len - 6;
  1114.             s.data = value[i].data + 6;

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

  1116.             if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) {
  1117.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1118.                                    "invalid flush time \"%V\"", &s);
  1119.                 return NGX_CONF_ERROR;
  1120.             }

  1121.             continue;
  1122.         }

  1123.         if (ngx_strncmp(value[i].data, "gzip", 4) == 0
  1124.             && (value[i].len == 4 || value[i].data[4] == '='))
  1125.         {
  1126. #if (NGX_ZLIB)
  1127.             if (size == 0) {
  1128.                 size = 64 * 1024;
  1129.             }

  1130.             if (value[i].len == 4) {
  1131.                 gzip = Z_BEST_SPEED;
  1132.                 continue;
  1133.             }

  1134.             s.len = value[i].len - 5;
  1135.             s.data = value[i].data + 5;

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

  1137.             if (gzip < 1 || gzip > 9) {
  1138.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1139.                                    "invalid compression level \"%V\"", &s);
  1140.                 return NGX_CONF_ERROR;
  1141.             }

  1142.             continue;

  1143. #else
  1144.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1145.                                "nginx was built without zlib support");
  1146.             return NGX_CONF_ERROR;
  1147. #endif
  1148.         }

  1149.         if (ngx_strncmp(value[i].data, "if=", 3) == 0) {
  1150.             s.len = value[i].len - 3;
  1151.             s.data = value[i].data + 3;

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

  1153.             ccv.cf = cf;
  1154.             ccv.value = &s;
  1155.             ccv.complex_value = ngx_palloc(cf->pool,
  1156.                                            sizeof(ngx_http_complex_value_t));
  1157.             if (ccv.complex_value == NULL) {
  1158.                 return NGX_CONF_ERROR;
  1159.             }

  1160.             if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  1161.                 return NGX_CONF_ERROR;
  1162.             }

  1163.             log->filter = ccv.complex_value;

  1164.             continue;
  1165.         }

  1166.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1167.                            "invalid parameter \"%V\"", &value[i]);
  1168.         return NGX_CONF_ERROR;
  1169.     }

  1170.     if (flush && size == 0) {
  1171.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1172.                            "no buffer is defined for access_log \"%V\"",
  1173.                            &value[1]);
  1174.         return NGX_CONF_ERROR;
  1175.     }

  1176.     if (size) {

  1177.         if (log->script) {
  1178.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1179.                                "buffered logs cannot have variables in name");
  1180.             return NGX_CONF_ERROR;
  1181.         }

  1182.         if (log->syslog_peer) {
  1183.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1184.                                "logs to syslog cannot be buffered");
  1185.             return NGX_CONF_ERROR;
  1186.         }

  1187.         if (log->file->data) {
  1188.             buffer = log->file->data;

  1189.             if (buffer->last - buffer->start != size
  1190.                 || buffer->flush != flush
  1191.                 || buffer->gzip != gzip)
  1192.             {
  1193.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1194.                                    "access_log \"%V\" already defined "
  1195.                                    "with conflicting parameters",
  1196.                                    &value[1]);
  1197.                 return NGX_CONF_ERROR;
  1198.             }

  1199.             return NGX_CONF_OK;
  1200.         }

  1201.         buffer = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_buf_t));
  1202.         if (buffer == NULL) {
  1203.             return NGX_CONF_ERROR;
  1204.         }

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

  1209.         buffer->pos = buffer->start;
  1210.         buffer->last = buffer->start + size;

  1211.         if (flush) {
  1212.             buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
  1213.             if (buffer->event == NULL) {
  1214.                 return NGX_CONF_ERROR;
  1215.             }

  1216.             buffer->event->data = log->file;
  1217.             buffer->event->handler = ngx_http_log_flush_handler;
  1218.             buffer->event->log = &cf->cycle->new_log;
  1219.             buffer->event->cancelable = 1;

  1220.             buffer->flush = flush;
  1221.         }

  1222.         buffer->gzip = gzip;

  1223.         log->file->flush = ngx_http_log_flush;
  1224.         log->file->data = buffer;
  1225.     }

  1226.     return NGX_CONF_OK;
  1227. }


  1228. static char *
  1229. ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1230. {
  1231.     ngx_http_log_main_conf_t *lmcf = conf;

  1232.     ngx_str_t           *value;
  1233.     ngx_uint_t           i;
  1234.     ngx_http_log_fmt_t  *fmt;

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

  1236.     fmt = lmcf->formats.elts;
  1237.     for (i = 0; i < lmcf->formats.nelts; i++) {
  1238.         if (fmt[i].name.len == value[1].len
  1239.             && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
  1240.         {
  1241.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1242.                                "duplicate \"log_format\" name \"%V\"",
  1243.                                &value[1]);
  1244.             return NGX_CONF_ERROR;
  1245.         }
  1246.     }

  1247.     fmt = ngx_array_push(&lmcf->formats);
  1248.     if (fmt == NULL) {
  1249.         return NGX_CONF_ERROR;
  1250.     }

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

  1252.     fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
  1253.     if (fmt->flushes == NULL) {
  1254.         return NGX_CONF_ERROR;
  1255.     }

  1256.     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
  1257.     if (fmt->ops == NULL) {
  1258.         return NGX_CONF_ERROR;
  1259.     }

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


  1262. static char *
  1263. ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
  1264.     ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
  1265. {
  1266.     u_char              *data, *p, ch;
  1267.     size_t               i, len;
  1268.     ngx_str_t           *value, var;
  1269.     ngx_int_t           *flush;
  1270.     ngx_uint_t           bracket, escape;
  1271.     ngx_http_log_op_t   *op;
  1272.     ngx_http_log_var_t  *v;

  1273.     escape = NGX_HTTP_LOG_ESCAPE_DEFAULT;
  1274.     value = args->elts;

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

  1277.         if (ngx_strcmp(data, "json") == 0) {
  1278.             escape = NGX_HTTP_LOG_ESCAPE_JSON;

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

  1281.         } else if (ngx_strcmp(data, "default") != 0) {
  1282.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1283.                                "unknown log format escaping \"%s\"", data);
  1284.             return NGX_CONF_ERROR;
  1285.         }

  1286.         s++;
  1287.     }

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

  1289.         i = 0;

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

  1291.             op = ngx_array_push(ops);
  1292.             if (op == NULL) {
  1293.                 return NGX_CONF_ERROR;
  1294.             }

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

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

  1297.                 if (++i == value[s].len) {
  1298.                     goto invalid;
  1299.                 }

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

  1302.                     if (++i == value[s].len) {
  1303.                         goto invalid;
  1304.                     }

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

  1306.                 } else {
  1307.                     bracket = 0;
  1308.                     var.data = &value[s].data[i];
  1309.                 }

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

  1312.                     if (ch == '}' && bracket) {
  1313.                         i++;
  1314.                         bracket = 0;
  1315.                         break;
  1316.                     }

  1317.                     if ((ch >= 'A' && ch <= 'Z')
  1318.                         || (ch >= 'a' && ch <= 'z')
  1319.                         || (ch >= '0' && ch <= '9')
  1320.                         || ch == '_')
  1321.                     {
  1322.                         continue;
  1323.                     }

  1324.                     break;
  1325.                 }

  1326.                 if (bracket) {
  1327.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1328.                                        "the closing bracket in \"%V\" "
  1329.                                        "variable is missing", &var);
  1330.                     return NGX_CONF_ERROR;
  1331.                 }

  1332.                 if (var.len == 0) {
  1333.                     goto invalid;
  1334.                 }

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

  1336.                     if (v->name.len == var.len
  1337.                         && ngx_strncmp(v->name.data, var.data, var.len) == 0)
  1338.                     {
  1339.                         op->len = v->len;
  1340.                         op->getlen = NULL;
  1341.                         op->run = v->run;
  1342.                         op->data = 0;

  1343.                         goto found;
  1344.                     }
  1345.                 }

  1346.                 if (ngx_http_log_variable_compile(cf, op, &var, escape)
  1347.                     != NGX_OK)
  1348.                 {
  1349.                     return NGX_CONF_ERROR;
  1350.                 }

  1351.                 if (flushes) {

  1352.                     flush = ngx_array_push(flushes);
  1353.                     if (flush == NULL) {
  1354.                         return NGX_CONF_ERROR;
  1355.                     }

  1356.                     *flush = op->data; /* variable index */
  1357.                 }

  1358.             found:

  1359.                 continue;
  1360.             }

  1361.             i++;

  1362.             while (i < value[s].len && value[s].data[i] != '$') {
  1363.                 i++;
  1364.             }

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

  1366.             if (len) {

  1367.                 op->len = len;
  1368.                 op->getlen = NULL;

  1369.                 if (len <= sizeof(uintptr_t)) {
  1370.                     op->run = ngx_http_log_copy_short;
  1371.                     op->data = 0;

  1372.                     while (len--) {
  1373.                         op->data <<= 8;
  1374.                         op->data |= data[len];
  1375.                     }

  1376.                 } else {
  1377.                     op->run = ngx_http_log_copy_long;

  1378.                     p = ngx_pnalloc(cf->pool, len);
  1379.                     if (p == NULL) {
  1380.                         return NGX_CONF_ERROR;
  1381.                     }

  1382.                     ngx_memcpy(p, data, len);
  1383.                     op->data = (uintptr_t) p;
  1384.                 }
  1385.             }
  1386.         }
  1387.     }

  1388.     return NGX_CONF_OK;

  1389. invalid:

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

  1391.     return NGX_CONF_ERROR;
  1392. }


  1393. static char *
  1394. ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1395. {
  1396.     ngx_http_log_loc_conf_t *llcf = conf;

  1397.     time_t       inactive, valid;
  1398.     ngx_str_t   *value, s;
  1399.     ngx_int_t    max, min_uses;
  1400.     ngx_uint_t   i;

  1401.     if (llcf->open_file_cache != NGX_CONF_UNSET_PTR) {
  1402.         return "is duplicate";
  1403.     }

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

  1405.     max = 0;
  1406.     inactive = 10;
  1407.     valid = 60;
  1408.     min_uses = 1;

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

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

  1411.             max = ngx_atoi(value[i].data + 4, value[i].len - 4);
  1412.             if (max == NGX_ERROR) {
  1413.                 goto failed;
  1414.             }

  1415.             continue;
  1416.         }

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

  1418.             s.len = value[i].len - 9;
  1419.             s.data = value[i].data + 9;

  1420.             inactive = ngx_parse_time(&s, 1);
  1421.             if (inactive == (time_t) NGX_ERROR) {
  1422.                 goto failed;
  1423.             }

  1424.             continue;
  1425.         }

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

  1427.             min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
  1428.             if (min_uses == NGX_ERROR) {
  1429.                 goto failed;
  1430.             }

  1431.             continue;
  1432.         }

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

  1434.             s.len = value[i].len - 6;
  1435.             s.data = value[i].data + 6;

  1436.             valid = ngx_parse_time(&s, 1);
  1437.             if (valid == (time_t) NGX_ERROR) {
  1438.                 goto failed;
  1439.             }

  1440.             continue;
  1441.         }

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

  1443.             llcf->open_file_cache = NULL;

  1444.             continue;
  1445.         }

  1446.     failed:

  1447.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1448.                            "invalid \"open_log_file_cache\" parameter \"%V\"",
  1449.                            &value[i]);
  1450.         return NGX_CONF_ERROR;
  1451.     }

  1452.     if (llcf->open_file_cache == NULL) {
  1453.         return NGX_CONF_OK;
  1454.     }

  1455.     if (max == 0) {
  1456.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1457.                         "\"open_log_file_cache\" must have \"max\" parameter");
  1458.         return NGX_CONF_ERROR;
  1459.     }

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

  1461.     if (llcf->open_file_cache) {

  1462.         llcf->open_file_cache_valid = valid;
  1463.         llcf->open_file_cache_min_uses = min_uses;

  1464.         return NGX_CONF_OK;
  1465.     }

  1466.     return NGX_CONF_ERROR;
  1467. }


  1468. static ngx_int_t
  1469. ngx_http_log_init(ngx_conf_t *cf)
  1470. {
  1471.     ngx_str_t                  *value;
  1472.     ngx_array_t                 a;
  1473.     ngx_http_handler_pt        *h;
  1474.     ngx_http_log_fmt_t         *fmt;
  1475.     ngx_http_log_main_conf_t   *lmcf;
  1476.     ngx_http_core_main_conf_t  *cmcf;

  1477.     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);

  1478.     if (lmcf->combined_used) {
  1479.         if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) {
  1480.             return NGX_ERROR;
  1481.         }

  1482.         value = ngx_array_push(&a);
  1483.         if (value == NULL) {
  1484.             return NGX_ERROR;
  1485.         }

  1486.         *value = ngx_http_combined_fmt;
  1487.         fmt = lmcf->formats.elts;

  1488.         if (ngx_http_log_compile_format(cf, NULL, fmt->ops, &a, 0)
  1489.             != NGX_CONF_OK)
  1490.         {
  1491.             return NGX_ERROR;
  1492.         }
  1493.     }

  1494.     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

  1495.     h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
  1496.     if (h == NULL) {
  1497.         return NGX_ERROR;
  1498.     }

  1499.     *h = ngx_http_log_handler;

  1500.     return NGX_OK;
  1501. }