446 lines
11 KiB
C
446 lines
11 KiB
C
|
|
/*
|
|
* Copyright (C) Igor Sysoev
|
|
* Copyright (C) Valentin V. Bartenev
|
|
* Copyright (C) NGINX, Inc.
|
|
*/
|
|
|
|
#include <nxt_router.h>
|
|
#include <nxt_conf.h>
|
|
#include <nxt_http.h>
|
|
|
|
|
|
typedef struct {
|
|
nxt_str_t path;
|
|
nxt_str_t format;
|
|
} nxt_router_access_log_conf_t;
|
|
|
|
|
|
typedef struct {
|
|
nxt_str_t text;
|
|
nxt_router_access_log_t *access_log;
|
|
} nxt_router_access_log_ctx_t;
|
|
|
|
|
|
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);
|
|
static void nxt_router_access_log_write_ready(nxt_task_t *task, void *obj,
|
|
void *data);
|
|
static void nxt_router_access_log_write_error(nxt_task_t *task, void *obj,
|
|
void *data);
|
|
static void nxt_router_access_log_ready(nxt_task_t *task,
|
|
nxt_port_recv_msg_t *msg, void *data);
|
|
static void nxt_router_access_log_error(nxt_task_t *task,
|
|
nxt_port_recv_msg_t *msg, void *data);
|
|
static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj,
|
|
void *data);
|
|
static void nxt_router_access_log_reopen_ready(nxt_task_t *task,
|
|
nxt_port_recv_msg_t *msg, void *data);
|
|
static void nxt_router_access_log_reopen_error(nxt_task_t *task,
|
|
nxt_port_recv_msg_t *msg, void *data);
|
|
|
|
|
|
static nxt_conf_map_t nxt_router_access_log_conf[] = {
|
|
{
|
|
nxt_string("path"),
|
|
NXT_CONF_MAP_STR,
|
|
offsetof(nxt_router_access_log_conf_t, path),
|
|
},
|
|
|
|
{
|
|
nxt_string("format"),
|
|
NXT_CONF_MAP_STR,
|
|
offsetof(nxt_router_access_log_conf_t, format),
|
|
},
|
|
};
|
|
|
|
|
|
nxt_int_t
|
|
nxt_router_access_log_create(nxt_task_t *task, nxt_router_conf_t *rtcf,
|
|
nxt_conf_value_t *value)
|
|
{
|
|
u_char *p;
|
|
nxt_int_t ret;
|
|
nxt_str_t str;
|
|
nxt_tstr_t *format;
|
|
nxt_router_t *router;
|
|
nxt_router_access_log_t *access_log;
|
|
nxt_router_access_log_conf_t alcf;
|
|
|
|
static nxt_str_t log_format_str = nxt_string("$remote_addr - - "
|
|
"[$time_local] \"$request_line\" $status $body_bytes_sent "
|
|
"\"$header_referer\" \"$header_user_agent\"");
|
|
|
|
alcf.format = log_format_str;
|
|
|
|
if (nxt_conf_type(value) == NXT_CONF_STRING) {
|
|
nxt_conf_get_string(value, &alcf.path);
|
|
|
|
} else {
|
|
ret = nxt_conf_map_object(rtcf->mem_pool, value,
|
|
nxt_router_access_log_conf,
|
|
nxt_nitems(nxt_router_access_log_conf),
|
|
&alcf);
|
|
if (ret != NXT_OK) {
|
|
nxt_alert(task, "access log map error");
|
|
return NXT_ERROR;
|
|
}
|
|
}
|
|
|
|
router = nxt_router;
|
|
|
|
access_log = router->access_log;
|
|
|
|
if (access_log != NULL && nxt_strstr_eq(&alcf.path, &access_log->path)) {
|
|
nxt_router_access_log_use(&router->lock, access_log);
|
|
|
|
} else {
|
|
access_log = nxt_malloc(sizeof(nxt_router_access_log_t)
|
|
+ alcf.path.length);
|
|
if (access_log == NULL) {
|
|
nxt_alert(task, "failed to allocate access log structure");
|
|
return NXT_ERROR;
|
|
}
|
|
|
|
access_log->fd = -1;
|
|
access_log->handler = &nxt_router_access_log_writer;
|
|
access_log->count = 1;
|
|
|
|
access_log->path.length = alcf.path.length;
|
|
access_log->path.start = (u_char *) access_log
|
|
+ sizeof(nxt_router_access_log_t);
|
|
|
|
nxt_memcpy(access_log->path.start, alcf.path.start, alcf.path.length);
|
|
}
|
|
|
|
str.length = alcf.format.length + 1;
|
|
|
|
str.start = nxt_malloc(str.length);
|
|
if (str.start == NULL) {
|
|
nxt_alert(task, "failed to allocate log format structure");
|
|
return NXT_ERROR;
|
|
}
|
|
|
|
p = nxt_cpymem(str.start, alcf.format.start, alcf.format.length);
|
|
*p = '\n';
|
|
|
|
format = nxt_tstr_compile(rtcf->tstr_state, &str, NXT_TSTR_LOGGING);
|
|
if (nxt_slow_path(format == NULL)) {
|
|
return NXT_ERROR;
|
|
}
|
|
|
|
rtcf->access_log = access_log;
|
|
rtcf->log_format = format;
|
|
|
|
return NXT_OK;
|
|
}
|
|
|
|
|
|
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)
|
|
{
|
|
nxt_int_t ret;
|
|
nxt_router_conf_t *rtcf;
|
|
nxt_router_access_log_ctx_t *ctx;
|
|
|
|
ctx = nxt_mp_get(r->mem_pool, sizeof(nxt_router_access_log_ctx_t));
|
|
if (nxt_slow_path(ctx == NULL)) {
|
|
return;
|
|
}
|
|
|
|
ctx->access_log = access_log;
|
|
|
|
if (nxt_tstr_is_const(format)) {
|
|
nxt_tstr_str(format, &ctx->text);
|
|
|
|
nxt_router_access_log_write_ready(task, r, ctx);
|
|
|
|
} else {
|
|
rtcf = r->conf->socket_conf->router_conf;
|
|
|
|
ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state,
|
|
&r->tstr_cache, r, r->mem_pool);
|
|
if (nxt_slow_path(ret != NXT_OK)) {
|
|
return;
|
|
}
|
|
|
|
nxt_tstr_query(task, r->tstr_query, format, &ctx->text);
|
|
nxt_tstr_query_resolve(task, r->tstr_query, ctx,
|
|
nxt_router_access_log_write_ready,
|
|
nxt_router_access_log_write_error);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
nxt_router_access_log_write_ready(nxt_task_t *task, void *obj, void *data)
|
|
{
|
|
nxt_http_request_t *r;
|
|
nxt_router_access_log_ctx_t *ctx;
|
|
|
|
r = obj;
|
|
ctx = data;
|
|
|
|
nxt_fd_write(ctx->access_log->fd, ctx->text.start, ctx->text.length);
|
|
|
|
nxt_http_request_close_handler(task, r, r->proto.any);
|
|
}
|
|
|
|
|
|
static void
|
|
nxt_router_access_log_write_error(nxt_task_t *task, void *obj, void *data)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
void
|
|
nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
|
|
{
|
|
uint32_t stream;
|
|
nxt_int_t ret;
|
|
nxt_buf_t *b;
|
|
nxt_port_t *main_port, *router_port;
|
|
nxt_runtime_t *rt;
|
|
nxt_router_access_log_t *access_log;
|
|
|
|
access_log = tmcf->router_conf->access_log;
|
|
|
|
b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0);
|
|
if (nxt_slow_path(b == NULL)) {
|
|
goto fail;
|
|
}
|
|
|
|
b->completion_handler = nxt_buf_dummy_completion;
|
|
|
|
nxt_buf_cpystr(b, &access_log->path);
|
|
*b->mem.free++ = '\0';
|
|
|
|
rt = task->thread->runtime;
|
|
main_port = rt->port_by_type[NXT_PROCESS_MAIN];
|
|
router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
|
|
|
|
stream = nxt_port_rpc_register_handler(task, router_port,
|
|
nxt_router_access_log_ready,
|
|
nxt_router_access_log_error,
|
|
-1, tmcf);
|
|
if (nxt_slow_path(stream == 0)) {
|
|
goto fail;
|
|
}
|
|
|
|
ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
|
|
stream, router_port->id, b);
|
|
|
|
if (nxt_slow_path(ret != NXT_OK)) {
|
|
nxt_port_rpc_cancel(task, router_port, stream);
|
|
goto fail;
|
|
}
|
|
|
|
return;
|
|
|
|
fail:
|
|
|
|
nxt_router_conf_error(task, tmcf);
|
|
}
|
|
|
|
|
|
static void
|
|
nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
|
|
void *data)
|
|
{
|
|
nxt_router_temp_conf_t *tmcf;
|
|
nxt_router_access_log_t *access_log;
|
|
|
|
tmcf = data;
|
|
|
|
access_log = tmcf->router_conf->access_log;
|
|
|
|
access_log->fd = msg->fd[0];
|
|
|
|
nxt_work_queue_add(&task->thread->engine->fast_work_queue,
|
|
nxt_router_conf_apply, task, tmcf, NULL);
|
|
}
|
|
|
|
|
|
static void
|
|
nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
|
|
void *data)
|
|
{
|
|
nxt_router_temp_conf_t *tmcf;
|
|
|
|
tmcf = data;
|
|
|
|
nxt_router_conf_error(task, tmcf);
|
|
}
|
|
|
|
|
|
void
|
|
nxt_router_access_log_use(nxt_thread_spinlock_t *lock,
|
|
nxt_router_access_log_t *access_log)
|
|
{
|
|
if (access_log == NULL) {
|
|
return;
|
|
}
|
|
|
|
nxt_thread_spin_lock(lock);
|
|
|
|
access_log->count++;
|
|
|
|
nxt_thread_spin_unlock(lock);
|
|
}
|
|
|
|
|
|
void
|
|
nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock,
|
|
nxt_router_access_log_t *access_log)
|
|
{
|
|
if (access_log == NULL) {
|
|
return;
|
|
}
|
|
|
|
nxt_thread_spin_lock(lock);
|
|
|
|
if (--access_log->count != 0) {
|
|
access_log = NULL;
|
|
}
|
|
|
|
nxt_thread_spin_unlock(lock);
|
|
|
|
if (access_log != NULL) {
|
|
|
|
if (access_log->fd != -1) {
|
|
nxt_fd_close(access_log->fd);
|
|
}
|
|
|
|
nxt_free(access_log);
|
|
}
|
|
}
|
|
|
|
|
|
typedef struct {
|
|
nxt_mp_t *mem_pool;
|
|
nxt_router_access_log_t *access_log;
|
|
} nxt_router_access_log_reopen_t;
|
|
|
|
|
|
void
|
|
nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
|
|
{
|
|
nxt_mp_t *mp;
|
|
uint32_t stream;
|
|
nxt_int_t ret;
|
|
nxt_buf_t *b;
|
|
nxt_port_t *main_port, *router_port;
|
|
nxt_runtime_t *rt;
|
|
nxt_router_access_log_t *access_log;
|
|
nxt_router_access_log_reopen_t *reopen;
|
|
|
|
access_log = nxt_router->access_log;
|
|
|
|
if (access_log == NULL) {
|
|
return;
|
|
}
|
|
|
|
mp = nxt_mp_create(1024, 128, 256, 32);
|
|
if (nxt_slow_path(mp == NULL)) {
|
|
return;
|
|
}
|
|
|
|
reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t));
|
|
if (nxt_slow_path(reopen == NULL)) {
|
|
goto fail;
|
|
}
|
|
|
|
reopen->mem_pool = mp;
|
|
reopen->access_log = access_log;
|
|
|
|
b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0);
|
|
if (nxt_slow_path(b == NULL)) {
|
|
goto fail;
|
|
}
|
|
|
|
b->completion_handler = nxt_router_access_log_reopen_completion;
|
|
|
|
nxt_buf_cpystr(b, &access_log->path);
|
|
*b->mem.free++ = '\0';
|
|
|
|
rt = task->thread->runtime;
|
|
main_port = rt->port_by_type[NXT_PROCESS_MAIN];
|
|
router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
|
|
|
|
stream = nxt_port_rpc_register_handler(task, router_port,
|
|
nxt_router_access_log_reopen_ready,
|
|
nxt_router_access_log_reopen_error,
|
|
-1, reopen);
|
|
if (nxt_slow_path(stream == 0)) {
|
|
goto fail;
|
|
}
|
|
|
|
ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
|
|
stream, router_port->id, b);
|
|
|
|
if (nxt_slow_path(ret != NXT_OK)) {
|
|
nxt_port_rpc_cancel(task, router_port, stream);
|
|
goto fail;
|
|
}
|
|
|
|
nxt_mp_retain(mp);
|
|
|
|
return;
|
|
|
|
fail:
|
|
|
|
nxt_mp_destroy(mp);
|
|
}
|
|
|
|
|
|
static void
|
|
nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data)
|
|
{
|
|
nxt_mp_t *mp;
|
|
nxt_buf_t *b;
|
|
|
|
b = obj;
|
|
mp = b->data;
|
|
|
|
nxt_mp_release(mp);
|
|
}
|
|
|
|
|
|
static void
|
|
nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
|
|
void *data)
|
|
{
|
|
nxt_router_access_log_t *access_log;
|
|
nxt_router_access_log_reopen_t *reopen;
|
|
|
|
reopen = data;
|
|
|
|
access_log = reopen->access_log;
|
|
|
|
if (access_log == nxt_router->access_log) {
|
|
|
|
if (nxt_slow_path(dup2(msg->fd[0], access_log->fd) == -1)) {
|
|
nxt_alert(task, "dup2(%FD, %FD) failed %E",
|
|
msg->fd[0], access_log->fd, nxt_errno);
|
|
}
|
|
}
|
|
|
|
nxt_fd_close(msg->fd[0]);
|
|
nxt_mp_release(reopen->mem_pool);
|
|
}
|
|
|
|
|
|
static void
|
|
nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
|
|
void *data)
|
|
{
|
|
nxt_router_access_log_reopen_t *reopen;
|
|
|
|
reopen = data;
|
|
|
|
nxt_mp_release(reopen->mem_pool);
|
|
}
|