Logging API¶
NGINX provides a powerful logging system for diagnostics and debugging.
Log Levels¶
NGX_LOG_STDERR /* 0 - Errors to stderr before log is opened */
NGX_LOG_EMERG /* 1 - System unusable */
NGX_LOG_ALERT /* 2 - Immediate action required */
NGX_LOG_CRIT /* 3 - Critical conditions */
NGX_LOG_ERR /* 4 - Error conditions */
NGX_LOG_WARN /* 5 - Warning conditions */
NGX_LOG_NOTICE /* 6 - Normal but significant */
NGX_LOG_INFO /* 7 - Informational */
NGX_LOG_DEBUG /* 8 - Debug messages */
Debug Categories¶
When NGINX is built with --with-debug:
NGX_LOG_DEBUG_CORE
NGX_LOG_DEBUG_ALLOC
NGX_LOG_DEBUG_MUTEX
NGX_LOG_DEBUG_EVENT
NGX_LOG_DEBUG_HTTP
NGX_LOG_DEBUG_MAIL
NGX_LOG_DEBUG_STREAM
Basic Logging¶
Error Logging¶
/* Simple message */
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"something went wrong");
/* With system error code */
ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
"failed to open file \"%s\"", filename);
/* With formatted values */
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"request took %M ms, uri: %V",
elapsed_ms, &r->uri);
Format Specifiers¶
| Specifier | Type | Description |
|---|---|---|
%d, %i |
int |
Signed integer |
%ud, %ui |
unsigned int |
Unsigned integer |
%l |
long |
Long integer |
%ul |
unsigned long |
Unsigned long |
%O |
off_t |
File offset |
%z |
ssize_t |
Signed size |
%uz |
size_t |
Unsigned size |
%p |
void * |
Pointer (hex) |
%s |
char * |
C string |
%V |
ngx_str_t * |
NGINX string |
%M |
ngx_msec_t |
Milliseconds |
%T |
time_t |
Time value |
%xd, %xD |
int, uint32_t |
Hex |
Practical Examples¶
Request Handler Logging¶
static ngx_int_t
ngx_http_mymodule_handler(ngx_http_request_t *r)
{
ngx_log_t *log = r->connection->log;
/* Info about request */
ngx_log_error(NGX_LOG_INFO, log, 0,
"processing request: method=%V uri=%V args=%V",
&r->method_name, &r->uri, &r->args);
/* Log client info */
ngx_log_error(NGX_LOG_INFO, log, 0,
"client: %V, server: %V",
&r->connection->addr_text,
&r->headers_in.server);
/* Log content length */
if (r->headers_in.content_length_n > 0) {
ngx_log_error(NGX_LOG_INFO, log, 0,
"content-length: %O",
r->headers_in.content_length_n);
}
return NGX_OK;
}
Error Handling with Context¶
static ngx_int_t
ngx_http_open_cache_file(ngx_http_request_t *r, ngx_str_t *path)
{
ngx_fd_t fd;
fd = ngx_open_file(path->data, NGX_FILE_RDONLY,
NGX_FILE_OPEN, 0);
if (fd == NGX_INVALID_FILE) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
ngx_open_file_n " \"%V\" failed", path);
return NGX_ERROR;
}
ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
"cache file opened: %V, fd=%d", path, fd);
return NGX_OK;
}
Debug Logging¶
Debug logging is only compiled in when NGINX is built with --with-debug.
Using Debug Macros¶
/* Fixed argument count variants (more efficient) */
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "handler called");
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
"uri: %V", &r->uri);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0,
"method=%V uri=%V", &r->method_name, &r->uri);
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, log, 0,
"client=%V server=%V uri=%V",
&r->connection->addr_text,
&r->headers_in.server,
&r->uri);
/* Up to ngx_log_debug8 available */
Conditional Debug Logging¶
static ngx_int_t
ngx_http_mymodule_process(ngx_http_request_t *r)
{
ngx_msec_t start, elapsed;
#if (NGX_DEBUG)
start = ngx_current_msec;
#endif
/* Do processing... */
#if (NGX_DEBUG)
elapsed = ngx_current_msec - start;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"processing took %M ms", elapsed);
#endif
return NGX_OK;
}
Configuration-Time Logging¶
Use during config parsing:
static char *
ngx_http_mymodule_set_value(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_str_t *value = cf->args->elts;
if (value[1].len == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"empty value in \"%V\" directive",
&cmd->name);
return NGX_CONF_ERROR;
}
if (value[1].len > 1024) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"value too long in \"%V\" directive, "
"truncating to 1024 bytes",
&cmd->name);
}
return NGX_CONF_OK;
}
Logging Incoming Data¶
Log Request Headers¶
static void
ngx_http_log_request_headers(ngx_http_request_t *r)
{
ngx_list_part_t *part;
ngx_table_elt_t *h;
ngx_uint_t i;
ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
"=== Request Headers ===");
part = &r->headers_in.headers.part;
h = part->elts;
for (i = 0; /* void */; i++) {
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
h = part->elts;
i = 0;
}
ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
" %V: %V", &h[i].key, &h[i].value);
}
}
Log Binary Data (Hex Dump)¶
static void
ngx_http_log_body_hex(ngx_http_request_t *r, u_char *data, size_t len)
{
u_char buf[64];
u_char *p;
size_t i;
ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
"body hex dump (%uz bytes):", len);
for (i = 0; i < len; i += 16) {
p = buf;
for (size_t j = 0; j < 16 && i + j < len; j++) {
p = ngx_sprintf(p, "%02xd ", data[i + j]);
}
ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
" %04xd: %s", i, buf);
}
}
Custom Log Handler¶
For special logging needs:
typedef struct {
ngx_str_t prefix;
ngx_uint_t request_count;
} ngx_http_mymodule_log_ctx_t;
static u_char *
ngx_http_mymodule_log_handler(ngx_log_t *log, u_char *buf, size_t len)
{
ngx_http_mymodule_log_ctx_t *ctx = log->data;
u_char *p = buf;
if (ctx) {
p = ngx_snprintf(buf, len, "[%V #%ui] ",
&ctx->prefix, ctx->request_count);
}
return p;
}
/* Attach custom handler to log */
static void
ngx_http_mymodule_setup_log(ngx_http_request_t *r)
{
ngx_http_mymodule_log_ctx_t *ctx;
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_mymodule_log_ctx_t));
if (ctx == NULL) {
return;
}
ngx_str_set(&ctx->prefix, "mymodule");
ctx->request_count = 1;
r->connection->log->handler = ngx_http_mymodule_log_handler;
r->connection->log->data = ctx;
}
Best Practices¶
Logging Guidelines
- Use appropriate levels - Don't use
ERRfor non-errors - Include context - Add request URI, client IP when relevant
- Use
ngx_errno- Pass system error codes for I/O operations - Guard debug logging - Use
#if (NGX_DEBUG)for expensive debug code - Use fixed-argument macros -
ngx_log_debug1is faster than variadic