1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Igor Sysoev
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_stream.h>
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyev#if (NGX_ZLIB)
13e18a033bSKonstantin Ananyev#include <zlib.h>
14e18a033bSKonstantin Ananyev#endif
15e18a033bSKonstantin Ananyev
16e18a033bSKonstantin Ananyev
17e18a033bSKonstantin Ananyevtypedef struct ngx_stream_log_op_s  ngx_stream_log_op_t;
18e18a033bSKonstantin Ananyev
19e18a033bSKonstantin Ananyevtypedef u_char *(*ngx_stream_log_op_run_pt) (ngx_stream_session_t *s,
20e18a033bSKonstantin Ananyev    u_char *buf, ngx_stream_log_op_t *op);
21e18a033bSKonstantin Ananyev
22e18a033bSKonstantin Ananyevtypedef size_t (*ngx_stream_log_op_getlen_pt) (ngx_stream_session_t *s,
23e18a033bSKonstantin Ananyev    uintptr_t data);
24e18a033bSKonstantin Ananyev
25e18a033bSKonstantin Ananyev
26e18a033bSKonstantin Ananyevstruct ngx_stream_log_op_s {
27e18a033bSKonstantin Ananyev    size_t                       len;
28e18a033bSKonstantin Ananyev    ngx_stream_log_op_getlen_pt  getlen;
29e18a033bSKonstantin Ananyev    ngx_stream_log_op_run_pt     run;
30e18a033bSKonstantin Ananyev    uintptr_t                    data;
31e18a033bSKonstantin Ananyev};
32e18a033bSKonstantin Ananyev
33e18a033bSKonstantin Ananyev
34e18a033bSKonstantin Ananyevtypedef struct {
35e18a033bSKonstantin Ananyev    ngx_str_t                    name;
36e18a033bSKonstantin Ananyev    ngx_array_t                 *flushes;
37e18a033bSKonstantin Ananyev    ngx_array_t                 *ops;        /* array of ngx_stream_log_op_t */
38e18a033bSKonstantin Ananyev} ngx_stream_log_fmt_t;
39e18a033bSKonstantin Ananyev
40e18a033bSKonstantin Ananyev
41e18a033bSKonstantin Ananyevtypedef struct {
42e18a033bSKonstantin Ananyev    ngx_array_t                  formats;    /* array of ngx_stream_log_fmt_t */
43e18a033bSKonstantin Ananyev} ngx_stream_log_main_conf_t;
44e18a033bSKonstantin Ananyev
45e18a033bSKonstantin Ananyev
46e18a033bSKonstantin Ananyevtypedef struct {
47e18a033bSKonstantin Ananyev    u_char                      *start;
48e18a033bSKonstantin Ananyev    u_char                      *pos;
49e18a033bSKonstantin Ananyev    u_char                      *last;
50e18a033bSKonstantin Ananyev
51e18a033bSKonstantin Ananyev    ngx_event_t                 *event;
52e18a033bSKonstantin Ananyev    ngx_msec_t                   flush;
53e18a033bSKonstantin Ananyev    ngx_int_t                    gzip;
54e18a033bSKonstantin Ananyev} ngx_stream_log_buf_t;
55e18a033bSKonstantin Ananyev
56e18a033bSKonstantin Ananyev
57e18a033bSKonstantin Ananyevtypedef struct {
58e18a033bSKonstantin Ananyev    ngx_array_t                 *lengths;
59e18a033bSKonstantin Ananyev    ngx_array_t                 *values;
60e18a033bSKonstantin Ananyev} ngx_stream_log_script_t;
61e18a033bSKonstantin Ananyev
62e18a033bSKonstantin Ananyev
63e18a033bSKonstantin Ananyevtypedef struct {
64e18a033bSKonstantin Ananyev    ngx_open_file_t             *file;
65e18a033bSKonstantin Ananyev    ngx_stream_log_script_t     *script;
66e18a033bSKonstantin Ananyev    time_t                       disk_full_time;
67e18a033bSKonstantin Ananyev    time_t                       error_log_time;
68e18a033bSKonstantin Ananyev    ngx_syslog_peer_t           *syslog_peer;
69e18a033bSKonstantin Ananyev    ngx_stream_log_fmt_t        *format;
70e18a033bSKonstantin Ananyev    ngx_stream_complex_value_t  *filter;
71e18a033bSKonstantin Ananyev} ngx_stream_log_t;
72e18a033bSKonstantin Ananyev
73e18a033bSKonstantin Ananyev
74e18a033bSKonstantin Ananyevtypedef struct {
75e18a033bSKonstantin Ananyev    ngx_array_t                 *logs;       /* array of ngx_stream_log_t */
76e18a033bSKonstantin Ananyev
77e18a033bSKonstantin Ananyev    ngx_open_file_cache_t       *open_file_cache;
78e18a033bSKonstantin Ananyev    time_t                       open_file_cache_valid;
79e18a033bSKonstantin Ananyev    ngx_uint_t                   open_file_cache_min_uses;
80e18a033bSKonstantin Ananyev
81e18a033bSKonstantin Ananyev    ngx_uint_t                   off;        /* unsigned  off:1 */
82e18a033bSKonstantin Ananyev} ngx_stream_log_srv_conf_t;
83e18a033bSKonstantin Ananyev
84e18a033bSKonstantin Ananyev
85e18a033bSKonstantin Ananyevtypedef struct {
86e18a033bSKonstantin Ananyev    ngx_str_t                    name;
87e18a033bSKonstantin Ananyev    size_t                       len;
88e18a033bSKonstantin Ananyev    ngx_stream_log_op_run_pt     run;
89e18a033bSKonstantin Ananyev} ngx_stream_log_var_t;
90e18a033bSKonstantin Ananyev
91e18a033bSKonstantin Ananyev
92e18a033bSKonstantin Ananyevstatic void ngx_stream_log_write(ngx_stream_session_t *s, ngx_stream_log_t *log,
93e18a033bSKonstantin Ananyev    u_char *buf, size_t len);
94e18a033bSKonstantin Ananyevstatic ssize_t ngx_stream_log_script_write(ngx_stream_session_t *s,
95e18a033bSKonstantin Ananyev    ngx_stream_log_script_t *script, u_char **name, u_char *buf, size_t len);
96e18a033bSKonstantin Ananyev
97e18a033bSKonstantin Ananyev#if (NGX_ZLIB)
98e18a033bSKonstantin Ananyevstatic ssize_t ngx_stream_log_gzip(ngx_fd_t fd, u_char *buf, size_t len,
99e18a033bSKonstantin Ananyev    ngx_int_t level, ngx_log_t *log);
100e18a033bSKonstantin Ananyev
101e18a033bSKonstantin Ananyevstatic void *ngx_stream_log_gzip_alloc(void *opaque, u_int items, u_int size);
102e18a033bSKonstantin Ananyevstatic void ngx_stream_log_gzip_free(void *opaque, void *address);
103e18a033bSKonstantin Ananyev#endif
104e18a033bSKonstantin Ananyev
105e18a033bSKonstantin Ananyevstatic void ngx_stream_log_flush(ngx_open_file_t *file, ngx_log_t *log);
106e18a033bSKonstantin Ananyevstatic void ngx_stream_log_flush_handler(ngx_event_t *ev);
107e18a033bSKonstantin Ananyev
108e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_log_variable_compile(ngx_conf_t *cf,
109e18a033bSKonstantin Ananyev    ngx_stream_log_op_t *op, ngx_str_t *value, ngx_uint_t json);
110e18a033bSKonstantin Ananyevstatic size_t ngx_stream_log_variable_getlen(ngx_stream_session_t *s,
111e18a033bSKonstantin Ananyev    uintptr_t data);
112e18a033bSKonstantin Ananyevstatic u_char *ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf,
113e18a033bSKonstantin Ananyev    ngx_stream_log_op_t *op);
114e18a033bSKonstantin Ananyevstatic uintptr_t ngx_stream_log_escape(u_char *dst, u_char *src, size_t size);
115e18a033bSKonstantin Ananyevstatic size_t ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s,
116e18a033bSKonstantin Ananyev    uintptr_t data);
117e18a033bSKonstantin Ananyevstatic u_char *ngx_stream_log_json_variable(ngx_stream_session_t *s,
118e18a033bSKonstantin Ananyev    u_char *buf, ngx_stream_log_op_t *op);
119e18a033bSKonstantin Ananyev
120e18a033bSKonstantin Ananyev
121e18a033bSKonstantin Ananyevstatic void *ngx_stream_log_create_main_conf(ngx_conf_t *cf);
122e18a033bSKonstantin Ananyevstatic void *ngx_stream_log_create_srv_conf(ngx_conf_t *cf);
123e18a033bSKonstantin Ananyevstatic char *ngx_stream_log_merge_srv_conf(ngx_conf_t *cf, void *parent,
124e18a033bSKonstantin Ananyev    void *child);
125e18a033bSKonstantin Ananyevstatic char *ngx_stream_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
126e18a033bSKonstantin Ananyev    void *conf);
127e18a033bSKonstantin Ananyevstatic char *ngx_stream_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
128e18a033bSKonstantin Ananyev    void *conf);
129e18a033bSKonstantin Ananyevstatic char *ngx_stream_log_compile_format(ngx_conf_t *cf,
130e18a033bSKonstantin Ananyev    ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
131e18a033bSKonstantin Ananyevstatic char *ngx_stream_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
132e18a033bSKonstantin Ananyev    void *conf);
133e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_log_init(ngx_conf_t *cf);
134e18a033bSKonstantin Ananyev
135e18a033bSKonstantin Ananyev
136e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_stream_log_commands[] = {
137e18a033bSKonstantin Ananyev
138e18a033bSKonstantin Ananyev    { ngx_string("log_format"),
139e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF|NGX_CONF_2MORE,
140e18a033bSKonstantin Ananyev      ngx_stream_log_set_format,
141e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF_OFFSET,
142e18a033bSKonstantin Ananyev      0,
143e18a033bSKonstantin Ananyev      NULL },
144e18a033bSKonstantin Ananyev
145e18a033bSKonstantin Ananyev    { ngx_string("access_log"),
146e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
147e18a033bSKonstantin Ananyev      ngx_stream_log_set_log,
148e18a033bSKonstantin Ananyev      NGX_STREAM_SRV_CONF_OFFSET,
149e18a033bSKonstantin Ananyev      0,
150e18a033bSKonstantin Ananyev      NULL },
151e18a033bSKonstantin Ananyev
152e18a033bSKonstantin Ananyev    { ngx_string("open_log_file_cache"),
153e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1234,
154e18a033bSKonstantin Ananyev      ngx_stream_log_open_file_cache,
155e18a033bSKonstantin Ananyev      NGX_STREAM_SRV_CONF_OFFSET,
156e18a033bSKonstantin Ananyev      0,
157e18a033bSKonstantin Ananyev      NULL },
158e18a033bSKonstantin Ananyev
159e18a033bSKonstantin Ananyev      ngx_null_command
160e18a033bSKonstantin Ananyev};
161e18a033bSKonstantin Ananyev
162e18a033bSKonstantin Ananyev
163e18a033bSKonstantin Ananyevstatic ngx_stream_module_t  ngx_stream_log_module_ctx = {
164e18a033bSKonstantin Ananyev    NULL,                                  /* preconfiguration */
165e18a033bSKonstantin Ananyev    ngx_stream_log_init,                   /* postconfiguration */
166e18a033bSKonstantin Ananyev
167e18a033bSKonstantin Ananyev    ngx_stream_log_create_main_conf,       /* create main configuration */
168e18a033bSKonstantin Ananyev    NULL,                                  /* init main configuration */
169e18a033bSKonstantin Ananyev
170e18a033bSKonstantin Ananyev    ngx_stream_log_create_srv_conf,        /* create server configuration */
171e18a033bSKonstantin Ananyev    ngx_stream_log_merge_srv_conf          /* merge server configuration */
172e18a033bSKonstantin Ananyev};
173e18a033bSKonstantin Ananyev
174e18a033bSKonstantin Ananyev
175e18a033bSKonstantin Ananyevngx_module_t  ngx_stream_log_module = {
176e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
177e18a033bSKonstantin Ananyev    &ngx_stream_log_module_ctx,            /* module context */
178e18a033bSKonstantin Ananyev    ngx_stream_log_commands,               /* module directives */
179e18a033bSKonstantin Ananyev    NGX_STREAM_MODULE,                     /* module type */
180e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
181e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
182e18a033bSKonstantin Ananyev    NULL,                                  /* init process */
183e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
184e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
185e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
186e18a033bSKonstantin Ananyev    NULL,                                  /* exit master */
187e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
188e18a033bSKonstantin Ananyev};
189e18a033bSKonstantin Ananyev
190e18a033bSKonstantin Ananyev
191e18a033bSKonstantin Ananyevstatic ngx_int_t
192e18a033bSKonstantin Ananyevngx_stream_log_handler(ngx_stream_session_t *s)
193e18a033bSKonstantin Ananyev{
194e18a033bSKonstantin Ananyev    u_char                     *line, *p;
195e18a033bSKonstantin Ananyev    size_t                      len, size;
196e18a033bSKonstantin Ananyev    ssize_t                     n;
197e18a033bSKonstantin Ananyev    ngx_str_t                   val;
198e18a033bSKonstantin Ananyev    ngx_uint_t                  i, l;
199e18a033bSKonstantin Ananyev    ngx_stream_log_t           *log;
200e18a033bSKonstantin Ananyev    ngx_stream_log_op_t        *op;
201e18a033bSKonstantin Ananyev    ngx_stream_log_buf_t       *buffer;
202e18a033bSKonstantin Ananyev    ngx_stream_log_srv_conf_t  *lscf;
203e18a033bSKonstantin Ananyev
204e18a033bSKonstantin Ananyev    ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
205e18a033bSKonstantin Ananyev                   "stream log handler");
206e18a033bSKonstantin Ananyev
207e18a033bSKonstantin Ananyev    lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_log_module);
208e18a033bSKonstantin Ananyev
209e18a033bSKonstantin Ananyev    if (lscf->off || lscf->logs == NULL) {
210e18a033bSKonstantin Ananyev        return NGX_OK;
211e18a033bSKonstantin Ananyev    }
212e18a033bSKonstantin Ananyev
213e18a033bSKonstantin Ananyev    log = lscf->logs->elts;
214e18a033bSKonstantin Ananyev    for (l = 0; l < lscf->logs->nelts; l++) {
215e18a033bSKonstantin Ananyev
216e18a033bSKonstantin Ananyev        if (log[l].filter) {
217e18a033bSKonstantin Ananyev            if (ngx_stream_complex_value(s, log[l].filter, &val) != NGX_OK) {
218e18a033bSKonstantin Ananyev                return NGX_ERROR;
219e18a033bSKonstantin Ananyev            }
220e18a033bSKonstantin Ananyev
221e18a033bSKonstantin Ananyev            if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) {
222e18a033bSKonstantin Ananyev                continue;
223e18a033bSKonstantin Ananyev            }
224e18a033bSKonstantin Ananyev        }
225e18a033bSKonstantin Ananyev
226e18a033bSKonstantin Ananyev        if (ngx_time() == log[l].disk_full_time) {
227e18a033bSKonstantin Ananyev
228e18a033bSKonstantin Ananyev            /*
229e18a033bSKonstantin Ananyev             * on FreeBSD writing to a full filesystem with enabled softupdates
230e18a033bSKonstantin Ananyev             * may block process for much longer time than writing to non-full
231e18a033bSKonstantin Ananyev             * filesystem, so we skip writing to a log for one second
232e18a033bSKonstantin Ananyev             */
233e18a033bSKonstantin Ananyev
234e18a033bSKonstantin Ananyev            continue;
235e18a033bSKonstantin Ananyev        }
236e18a033bSKonstantin Ananyev
237e18a033bSKonstantin Ananyev        ngx_stream_script_flush_no_cacheable_variables(s,
238e18a033bSKonstantin Ananyev                                                       log[l].format->flushes);
239e18a033bSKonstantin Ananyev
240e18a033bSKonstantin Ananyev        len = 0;
241e18a033bSKonstantin Ananyev        op = log[l].format->ops->elts;
242e18a033bSKonstantin Ananyev        for (i = 0; i < log[l].format->ops->nelts; i++) {
243e18a033bSKonstantin Ananyev            if (op[i].len == 0) {
244e18a033bSKonstantin Ananyev                len += op[i].getlen(s, op[i].data);
245e18a033bSKonstantin Ananyev
246e18a033bSKonstantin Ananyev            } else {
247e18a033bSKonstantin Ananyev                len += op[i].len;
248e18a033bSKonstantin Ananyev            }
249e18a033bSKonstantin Ananyev        }
250e18a033bSKonstantin Ananyev
251e18a033bSKonstantin Ananyev        if (log[l].syslog_peer) {
252e18a033bSKonstantin Ananyev
253e18a033bSKonstantin Ananyev            /* length of syslog's PRI and HEADER message parts */
254e18a033bSKonstantin Ananyev            len += sizeof("<255>Jan 01 00:00:00 ") - 1
255e18a033bSKonstantin Ananyev                   + ngx_cycle->hostname.len + 1
256e18a033bSKonstantin Ananyev                   + log[l].syslog_peer->tag.len + 2;
257e18a033bSKonstantin Ananyev
258e18a033bSKonstantin Ananyev            goto alloc_line;
259e18a033bSKonstantin Ananyev        }
260e18a033bSKonstantin Ananyev
261e18a033bSKonstantin Ananyev        len += NGX_LINEFEED_SIZE;
262e18a033bSKonstantin Ananyev
263e18a033bSKonstantin Ananyev        buffer = log[l].file ? log[l].file->data : NULL;
264e18a033bSKonstantin Ananyev
265e18a033bSKonstantin Ananyev        if (buffer) {
266e18a033bSKonstantin Ananyev
267e18a033bSKonstantin Ananyev            if (len > (size_t) (buffer->last - buffer->pos)) {
268e18a033bSKonstantin Ananyev
269e18a033bSKonstantin Ananyev                ngx_stream_log_write(s, &log[l], buffer->start,
270e18a033bSKonstantin Ananyev                                     buffer->pos - buffer->start);
271e18a033bSKonstantin Ananyev
272e18a033bSKonstantin Ananyev                buffer->pos = buffer->start;
273e18a033bSKonstantin Ananyev            }
274e18a033bSKonstantin Ananyev
275e18a033bSKonstantin Ananyev            if (len <= (size_t) (buffer->last - buffer->pos)) {
276e18a033bSKonstantin Ananyev
277e18a033bSKonstantin Ananyev                p = buffer->pos;
278e18a033bSKonstantin Ananyev
279e18a033bSKonstantin Ananyev                if (buffer->event && p == buffer->start) {
280e18a033bSKonstantin Ananyev                    ngx_add_timer(buffer->event, buffer->flush);
281e18a033bSKonstantin Ananyev                }
282e18a033bSKonstantin Ananyev
283e18a033bSKonstantin Ananyev                for (i = 0; i < log[l].format->ops->nelts; i++) {
284e18a033bSKonstantin Ananyev                    p = op[i].run(s, p, &op[i]);
285e18a033bSKonstantin Ananyev                }
286e18a033bSKonstantin Ananyev
287e18a033bSKonstantin Ananyev                ngx_linefeed(p);
288e18a033bSKonstantin Ananyev
289e18a033bSKonstantin Ananyev                buffer->pos = p;
290e18a033bSKonstantin Ananyev
291e18a033bSKonstantin Ananyev                continue;
292e18a033bSKonstantin Ananyev            }
293e18a033bSKonstantin Ananyev
294e18a033bSKonstantin Ananyev            if (buffer->event && buffer->event->timer_set) {
295e18a033bSKonstantin Ananyev                ngx_del_timer(buffer->event);
296e18a033bSKonstantin Ananyev            }
297e18a033bSKonstantin Ananyev        }
298e18a033bSKonstantin Ananyev
299e18a033bSKonstantin Ananyev    alloc_line:
300e18a033bSKonstantin Ananyev
301e18a033bSKonstantin Ananyev        line = ngx_pnalloc(s->connection->pool, len);
302e18a033bSKonstantin Ananyev        if (line == NULL) {
303e18a033bSKonstantin Ananyev            return NGX_ERROR;
304e18a033bSKonstantin Ananyev        }
305e18a033bSKonstantin Ananyev
306e18a033bSKonstantin Ananyev        p = line;
307e18a033bSKonstantin Ananyev
308e18a033bSKonstantin Ananyev        if (log[l].syslog_peer) {
309e18a033bSKonstantin Ananyev            p = ngx_syslog_add_header(log[l].syslog_peer, line);
310e18a033bSKonstantin Ananyev        }
311e18a033bSKonstantin Ananyev
312e18a033bSKonstantin Ananyev        for (i = 0; i < log[l].format->ops->nelts; i++) {
313e18a033bSKonstantin Ananyev            p = op[i].run(s, p, &op[i]);
314e18a033bSKonstantin Ananyev        }
315e18a033bSKonstantin Ananyev
316e18a033bSKonstantin Ananyev        if (log[l].syslog_peer) {
317e18a033bSKonstantin Ananyev
318e18a033bSKonstantin Ananyev            size = p - line;
319e18a033bSKonstantin Ananyev
320e18a033bSKonstantin Ananyev            n = ngx_syslog_send(log[l].syslog_peer, line, size);
321e18a033bSKonstantin Ananyev
322e18a033bSKonstantin Ananyev            if (n < 0) {
323e18a033bSKonstantin Ananyev                ngx_log_error(NGX_LOG_WARN, s->connection->log, 0,
324e18a033bSKonstantin Ananyev                              "send() to syslog failed");
325e18a033bSKonstantin Ananyev
326e18a033bSKonstantin Ananyev            } else if ((size_t) n != size) {
327e18a033bSKonstantin Ananyev                ngx_log_error(NGX_LOG_WARN, s->connection->log, 0,
328e18a033bSKonstantin Ananyev                              "send() to syslog has written only %z of %uz",
329e18a033bSKonstantin Ananyev                              n, size);
330e18a033bSKonstantin Ananyev            }
331e18a033bSKonstantin Ananyev
332e18a033bSKonstantin Ananyev            continue;
333e18a033bSKonstantin Ananyev        }
334e18a033bSKonstantin Ananyev
335e18a033bSKonstantin Ananyev        ngx_linefeed(p);
336e18a033bSKonstantin Ananyev
337e18a033bSKonstantin Ananyev        ngx_stream_log_write(s, &log[l], line, p - line);
338e18a033bSKonstantin Ananyev    }
339e18a033bSKonstantin Ananyev
340e18a033bSKonstantin Ananyev    return NGX_OK;
341e18a033bSKonstantin Ananyev}
342e18a033bSKonstantin Ananyev
343e18a033bSKonstantin Ananyev
344e18a033bSKonstantin Ananyevstatic void
345e18a033bSKonstantin Ananyevngx_stream_log_write(ngx_stream_session_t *s, ngx_stream_log_t *log,
346e18a033bSKonstantin Ananyev    u_char *buf, size_t len)
347e18a033bSKonstantin Ananyev{
348e18a033bSKonstantin Ananyev    u_char                *name;
349e18a033bSKonstantin Ananyev    time_t                 now;
350e18a033bSKonstantin Ananyev    ssize_t                n;
351e18a033bSKonstantin Ananyev    ngx_err_t              err;
352e18a033bSKonstantin Ananyev#if (NGX_ZLIB)
353e18a033bSKonstantin Ananyev    ngx_stream_log_buf_t  *buffer;
354e18a033bSKonstantin Ananyev#endif
355e18a033bSKonstantin Ananyev
356e18a033bSKonstantin Ananyev    if (log->script == NULL) {
357e18a033bSKonstantin Ananyev        name = log->file->name.data;
358e18a033bSKonstantin Ananyev
359e18a033bSKonstantin Ananyev#if (NGX_ZLIB)
360e18a033bSKonstantin Ananyev        buffer = log->file->data;
361e18a033bSKonstantin Ananyev
362e18a033bSKonstantin Ananyev        if (buffer && buffer->gzip) {
363e18a033bSKonstantin Ananyev            n = ngx_stream_log_gzip(log->file->fd, buf, len, buffer->gzip,
364e18a033bSKonstantin Ananyev                                    s->connection->log);
365e18a033bSKonstantin Ananyev        } else {
366e18a033bSKonstantin Ananyev            n = ngx_write_fd(log->file->fd, buf, len);
367e18a033bSKonstantin Ananyev        }
368e18a033bSKonstantin Ananyev#else
369e18a033bSKonstantin Ananyev        n = ngx_write_fd(log->file->fd, buf, len);
370e18a033bSKonstantin Ananyev#endif
371e18a033bSKonstantin Ananyev
372e18a033bSKonstantin Ananyev    } else {
373e18a033bSKonstantin Ananyev        name = NULL;
374e18a033bSKonstantin Ananyev        n = ngx_stream_log_script_write(s, log->script, &name, buf, len);
375e18a033bSKonstantin Ananyev    }
376e18a033bSKonstantin Ananyev
377e18a033bSKonstantin Ananyev    if (n == (ssize_t) len) {
378e18a033bSKonstantin Ananyev        return;
379e18a033bSKonstantin Ananyev    }
380e18a033bSKonstantin Ananyev
381e18a033bSKonstantin Ananyev    now = ngx_time();
382e18a033bSKonstantin Ananyev
383e18a033bSKonstantin Ananyev    if (n == -1) {
384e18a033bSKonstantin Ananyev        err = ngx_errno;
385e18a033bSKonstantin Ananyev
386e18a033bSKonstantin Ananyev        if (err == NGX_ENOSPC) {
387e18a033bSKonstantin Ananyev            log->disk_full_time = now;
388e18a033bSKonstantin Ananyev        }
389e18a033bSKonstantin Ananyev
390e18a033bSKonstantin Ananyev        if (now - log->error_log_time > 59) {
391e18a033bSKonstantin Ananyev            ngx_log_error(NGX_LOG_ALERT, s->connection->log, err,
392e18a033bSKonstantin Ananyev                          ngx_write_fd_n " to \"%s\" failed", name);
393e18a033bSKonstantin Ananyev
394e18a033bSKonstantin Ananyev            log->error_log_time = now;
395e18a033bSKonstantin Ananyev        }
396e18a033bSKonstantin Ananyev
397e18a033bSKonstantin Ananyev        return;
398e18a033bSKonstantin Ananyev    }
399e18a033bSKonstantin Ananyev
400e18a033bSKonstantin Ananyev    if (now - log->error_log_time > 59) {
401e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
402e18a033bSKonstantin Ananyev                      ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
403e18a033bSKonstantin Ananyev                      name, n, len);
404e18a033bSKonstantin Ananyev
405e18a033bSKonstantin Ananyev        log->error_log_time = now;
406e18a033bSKonstantin Ananyev    }
407e18a033bSKonstantin Ananyev}
408e18a033bSKonstantin Ananyev
409e18a033bSKonstantin Ananyev
410e18a033bSKonstantin Ananyevstatic ssize_t
411e18a033bSKonstantin Ananyevngx_stream_log_script_write(ngx_stream_session_t *s,
412e18a033bSKonstantin Ananyev    ngx_stream_log_script_t *script, u_char **name, u_char *buf, size_t len)
413e18a033bSKonstantin Ananyev{
414e18a033bSKonstantin Ananyev    ssize_t                     n;
415e18a033bSKonstantin Ananyev    ngx_str_t                   log;
416