summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_router_access_log.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nxt_router_access_log.c')
-rw-r--r--src/nxt_router_access_log.c442
1 files changed, 442 insertions, 0 deletions
diff --git a/src/nxt_router_access_log.c b/src/nxt_router_access_log.c
new file mode 100644
index 00000000..dc2a6687
--- /dev/null
+++ b/src/nxt_router_access_log.c
@@ -0,0 +1,442 @@
+
+/*
+ * 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_var_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_var_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_var_compile(&str, rtcf->mem_pool, rtcf->var_fields,
+ NXT_VAR_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_var_t *format)
+{
+ nxt_int_t ret;
+ 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_var_is_const(format)) {
+ nxt_var_raw(format, &ctx->text);
+
+ nxt_router_access_log_write_ready(task, r, ctx);
+
+ } else {
+ ret = nxt_var_query_init(&r->var_query, r, r->mem_pool);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return;
+ }
+
+ nxt_var_query(task, r->var_query, format, &ctx->text);
+ nxt_var_query_resolve(task, r->var_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);
+}