xref: /unit/src/nxt_router_access_log.c (revision 2625:a6b688c5757c)
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Valentin V. Bartenev
5  * Copyright (C) NGINX, Inc.
6  */
7 
8 #include <nxt_router.h>
9 #include <nxt_conf.h>
10 #include <nxt_http.h>
11 
12 
13 typedef struct {
14     nxt_str_t                 path;
15     nxt_str_t                 format;
16     nxt_conf_value_t          *expr;
17 } nxt_router_access_log_conf_t;
18 
19 
20 typedef struct {
21     nxt_str_t                 text;
22     nxt_router_access_log_t   *access_log;
23 } nxt_router_access_log_ctx_t;
24 
25 
26 static void nxt_router_access_log_writer(nxt_task_t *task,
27     nxt_http_request_t *r, nxt_router_access_log_t *access_log,
28     nxt_tstr_t *format);
29 static void nxt_router_access_log_write_ready(nxt_task_t *task, void *obj,
30     void *data);
31 static void nxt_router_access_log_write_error(nxt_task_t *task, void *obj,
32     void *data);
33 static void nxt_router_access_log_ready(nxt_task_t *task,
34     nxt_port_recv_msg_t *msg, void *data);
35 static void nxt_router_access_log_error(nxt_task_t *task,
36     nxt_port_recv_msg_t *msg, void *data);
37 static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj,
38     void *data);
39 static void nxt_router_access_log_reopen_ready(nxt_task_t *task,
40     nxt_port_recv_msg_t *msg, void *data);
41 static void nxt_router_access_log_reopen_error(nxt_task_t *task,
42     nxt_port_recv_msg_t *msg, void *data);
43 
44 
45 static nxt_conf_map_t  nxt_router_access_log_conf[] = {
46     {
47         nxt_string("path"),
48         NXT_CONF_MAP_STR,
49         offsetof(nxt_router_access_log_conf_t, path),
50     },
51 
52     {
53         nxt_string("format"),
54         NXT_CONF_MAP_STR,
55         offsetof(nxt_router_access_log_conf_t, format),
56     },
57 
58     {
59         nxt_string("if"),
60         NXT_CONF_MAP_PTR,
61         offsetof(nxt_router_access_log_conf_t, expr),
62     },
63 };
64 
65 
66 nxt_int_t
nxt_router_access_log_create(nxt_task_t * task,nxt_router_conf_t * rtcf,nxt_conf_value_t * value)67 nxt_router_access_log_create(nxt_task_t *task, nxt_router_conf_t *rtcf,
68     nxt_conf_value_t *value)
69 {
70     u_char                        *p;
71     nxt_int_t                     ret;
72     nxt_str_t                     str;
73     nxt_tstr_t                    *format;
74     nxt_router_t                  *router;
75     nxt_router_access_log_t       *access_log;
76     nxt_router_access_log_conf_t  alcf;
77 
78     static nxt_str_t  log_format_str = nxt_string("$remote_addr - - "
79         "[$time_local] \"$request_line\" $status $body_bytes_sent "
80         "\"$header_referer\" \"$header_user_agent\"");
81 
82     nxt_memzero(&alcf, sizeof(nxt_router_access_log_conf_t));
83 
84     alcf.format = log_format_str;
85 
86     if (nxt_conf_type(value) == NXT_CONF_STRING) {
87         nxt_conf_get_string(value, &alcf.path);
88 
89     } else {
90         ret = nxt_conf_map_object(rtcf->mem_pool, value,
91                                   nxt_router_access_log_conf,
92                                   nxt_nitems(nxt_router_access_log_conf),
93                                   &alcf);
94         if (ret != NXT_OK) {
95             nxt_alert(task, "access log map error");
96             return NXT_ERROR;
97         }
98     }
99 
100     router = nxt_router;
101 
102     access_log = router->access_log;
103 
104     if (access_log != NULL && nxt_strstr_eq(&alcf.path, &access_log->path)) {
105         nxt_router_access_log_use(&router->lock, access_log);
106 
107     } else {
108         access_log = nxt_malloc(sizeof(nxt_router_access_log_t)
109                                 + alcf.path.length);
110         if (access_log == NULL) {
111             nxt_alert(task, "failed to allocate access log structure");
112             return NXT_ERROR;
113         }
114 
115         access_log->fd = -1;
116         access_log->handler = &nxt_router_access_log_writer;
117         access_log->count = 1;
118 
119         access_log->path.length = alcf.path.length;
120         access_log->path.start = (u_char *) access_log
121                                  + sizeof(nxt_router_access_log_t);
122 
123         nxt_memcpy(access_log->path.start, alcf.path.start, alcf.path.length);
124     }
125 
126     str.length = alcf.format.length + 1;
127 
128     str.start = nxt_malloc(str.length);
129     if (str.start == NULL) {
130         nxt_alert(task, "failed to allocate log format structure");
131         return NXT_ERROR;
132     }
133 
134     p = nxt_cpymem(str.start, alcf.format.start, alcf.format.length);
135     *p = '\n';
136 
137     format = nxt_tstr_compile(rtcf->tstr_state, &str, NXT_TSTR_LOGGING);
138     if (nxt_slow_path(format == NULL)) {
139         return NXT_ERROR;
140     }
141 
142     rtcf->access_log = access_log;
143     rtcf->log_format = format;
144 
145     if (alcf.expr != NULL) {
146         nxt_conf_get_string(alcf.expr, &str);
147 
148         if (str.length > 0 && str.start[0] == '!') {
149             rtcf->log_negate = 1;
150 
151             str.start++;
152             str.length--;
153         }
154 
155         rtcf->log_expr = nxt_tstr_compile(rtcf->tstr_state, &str, 0);
156         if (nxt_slow_path(rtcf->log_expr == NULL)) {
157             return NXT_ERROR;
158         }
159     }
160 
161     return NXT_OK;
162 }
163 
164 
165 static void
nxt_router_access_log_writer(nxt_task_t * task,nxt_http_request_t * r,nxt_router_access_log_t * access_log,nxt_tstr_t * format)166 nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r,
167     nxt_router_access_log_t *access_log, nxt_tstr_t *format)
168 {
169     nxt_int_t                    ret;
170     nxt_router_conf_t            *rtcf;
171     nxt_router_access_log_ctx_t  *ctx;
172 
173     ctx = nxt_mp_get(r->mem_pool, sizeof(nxt_router_access_log_ctx_t));
174     if (nxt_slow_path(ctx == NULL)) {
175         return;
176     }
177 
178     ctx->access_log = access_log;
179 
180     if (nxt_tstr_is_const(format)) {
181         nxt_tstr_str(format, &ctx->text);
182 
183         nxt_router_access_log_write_ready(task, r, ctx);
184 
185     } else {
186         rtcf = r->conf->socket_conf->router_conf;
187 
188         ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state,
189                                   &r->tstr_cache, r, r->mem_pool);
190         if (nxt_slow_path(ret != NXT_OK)) {
191             return;
192         }
193 
194         nxt_tstr_query(task, r->tstr_query, format, &ctx->text);
195         nxt_tstr_query_resolve(task, r->tstr_query, ctx,
196                                nxt_router_access_log_write_ready,
197                                nxt_router_access_log_write_error);
198      }
199 }
200 
201 
202 static void
nxt_router_access_log_write_ready(nxt_task_t * task,void * obj,void * data)203 nxt_router_access_log_write_ready(nxt_task_t *task, void *obj, void *data)
204 {
205     nxt_http_request_t           *r;
206     nxt_router_access_log_ctx_t  *ctx;
207 
208     r = obj;
209     ctx = data;
210 
211     nxt_fd_write(ctx->access_log->fd, ctx->text.start, ctx->text.length);
212 
213     nxt_http_request_close_handler(task, r, r->proto.any);
214 }
215 
216 
217 static void
nxt_router_access_log_write_error(nxt_task_t * task,void * obj,void * data)218 nxt_router_access_log_write_error(nxt_task_t *task, void *obj, void *data)
219 {
220 
221 }
222 
223 
224 void
nxt_router_access_log_open(nxt_task_t * task,nxt_router_temp_conf_t * tmcf)225 nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
226 {
227     uint32_t                 stream;
228     nxt_int_t                ret;
229     nxt_buf_t                *b;
230     nxt_port_t               *main_port, *router_port;
231     nxt_runtime_t            *rt;
232     nxt_router_access_log_t  *access_log;
233 
234     access_log = tmcf->router_conf->access_log;
235 
236     b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0);
237     if (nxt_slow_path(b == NULL)) {
238         goto fail;
239     }
240 
241     b->completion_handler = nxt_buf_dummy_completion;
242 
243     nxt_buf_cpystr(b, &access_log->path);
244     *b->mem.free++ = '\0';
245 
246     rt = task->thread->runtime;
247     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
248     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
249 
250     stream = nxt_port_rpc_register_handler(task, router_port,
251                                            nxt_router_access_log_ready,
252                                            nxt_router_access_log_error,
253                                            -1, tmcf);
254     if (nxt_slow_path(stream == 0)) {
255         goto fail;
256     }
257 
258     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
259                                 stream, router_port->id, b);
260 
261     if (nxt_slow_path(ret != NXT_OK)) {
262         nxt_port_rpc_cancel(task, router_port, stream);
263         goto fail;
264     }
265 
266     return;
267 
268 fail:
269 
270     nxt_router_conf_error(task, tmcf);
271 }
272 
273 
274 static void
nxt_router_access_log_ready(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)275 nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
276     void *data)
277 {
278     nxt_router_temp_conf_t   *tmcf;
279     nxt_router_access_log_t  *access_log;
280 
281     tmcf = data;
282 
283     access_log = tmcf->router_conf->access_log;
284 
285     access_log->fd = msg->fd[0];
286 
287     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
288                        nxt_router_conf_apply, task, tmcf, NULL);
289 }
290 
291 
292 static void
nxt_router_access_log_error(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)293 nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
294     void *data)
295 {
296     nxt_router_temp_conf_t  *tmcf;
297 
298     tmcf = data;
299 
300     nxt_router_conf_error(task, tmcf);
301 }
302 
303 
304 void
nxt_router_access_log_use(nxt_thread_spinlock_t * lock,nxt_router_access_log_t * access_log)305 nxt_router_access_log_use(nxt_thread_spinlock_t *lock,
306     nxt_router_access_log_t *access_log)
307 {
308     if (access_log == NULL) {
309         return;
310     }
311 
312     nxt_thread_spin_lock(lock);
313 
314     access_log->count++;
315 
316     nxt_thread_spin_unlock(lock);
317 }
318 
319 
320 void
nxt_router_access_log_release(nxt_task_t * task,nxt_thread_spinlock_t * lock,nxt_router_access_log_t * access_log)321 nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock,
322     nxt_router_access_log_t *access_log)
323 {
324     if (access_log == NULL) {
325         return;
326     }
327 
328     nxt_thread_spin_lock(lock);
329 
330     if (--access_log->count != 0) {
331         access_log = NULL;
332     }
333 
334     nxt_thread_spin_unlock(lock);
335 
336     if (access_log != NULL) {
337 
338         if (access_log->fd != -1) {
339             nxt_fd_close(access_log->fd);
340         }
341 
342         nxt_free(access_log);
343     }
344 }
345 
346 
347 typedef struct {
348     nxt_mp_t                 *mem_pool;
349     nxt_router_access_log_t  *access_log;
350 } nxt_router_access_log_reopen_t;
351 
352 
353 void
nxt_router_access_log_reopen_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg)354 nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
355 {
356     nxt_mp_t                        *mp;
357     uint32_t                        stream;
358     nxt_int_t                       ret;
359     nxt_buf_t                       *b;
360     nxt_port_t                      *main_port, *router_port;
361     nxt_runtime_t                   *rt;
362     nxt_router_access_log_t         *access_log;
363     nxt_router_access_log_reopen_t  *reopen;
364 
365     access_log = nxt_router->access_log;
366 
367     if (access_log == NULL) {
368         return;
369     }
370 
371     mp = nxt_mp_create(1024, 128, 256, 32);
372     if (nxt_slow_path(mp == NULL)) {
373         return;
374     }
375 
376     reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t));
377     if (nxt_slow_path(reopen == NULL)) {
378         goto fail;
379     }
380 
381     reopen->mem_pool = mp;
382     reopen->access_log = access_log;
383 
384     b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0);
385     if (nxt_slow_path(b == NULL)) {
386         goto fail;
387     }
388 
389     b->completion_handler = nxt_router_access_log_reopen_completion;
390 
391     nxt_buf_cpystr(b, &access_log->path);
392     *b->mem.free++ = '\0';
393 
394     rt = task->thread->runtime;
395     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
396     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
397 
398     stream = nxt_port_rpc_register_handler(task, router_port,
399                                            nxt_router_access_log_reopen_ready,
400                                            nxt_router_access_log_reopen_error,
401                                            -1, reopen);
402     if (nxt_slow_path(stream == 0)) {
403         goto fail;
404     }
405 
406     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
407                                 stream, router_port->id, b);
408 
409     if (nxt_slow_path(ret != NXT_OK)) {
410         nxt_port_rpc_cancel(task, router_port, stream);
411         goto fail;
412     }
413 
414     nxt_mp_retain(mp);
415 
416     return;
417 
418 fail:
419 
420     nxt_mp_destroy(mp);
421 }
422 
423 
424 static void
nxt_router_access_log_reopen_completion(nxt_task_t * task,void * obj,void * data)425 nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data)
426 {
427     nxt_mp_t   *mp;
428     nxt_buf_t  *b;
429 
430     b = obj;
431     mp = b->data;
432 
433     nxt_mp_release(mp);
434 }
435 
436 
437 static void
nxt_router_access_log_reopen_ready(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)438 nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
439     void *data)
440 {
441     nxt_router_access_log_t         *access_log;
442     nxt_router_access_log_reopen_t  *reopen;
443 
444     reopen = data;
445 
446     access_log = reopen->access_log;
447 
448     if (access_log == nxt_router->access_log) {
449 
450         if (nxt_slow_path(dup2(msg->fd[0], access_log->fd) == -1)) {
451             nxt_alert(task, "dup2(%FD, %FD) failed %E",
452                       msg->fd[0], access_log->fd, nxt_errno);
453         }
454     }
455 
456     nxt_fd_close(msg->fd[0]);
457     nxt_mp_release(reopen->mem_pool);
458 }
459 
460 
461 static void
nxt_router_access_log_reopen_error(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)462 nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
463     void *data)
464 {
465     nxt_router_access_log_reopen_t  *reopen;
466 
467     reopen = data;
468 
469     nxt_mp_release(reopen->mem_pool);
470 }
471