yum upgrades for production use, this is the repository for you.
Active subscription is required.
The NGINX error_log_write module brings conditional error logging to NGINX. This powerful module lets administrators write custom log entries based on request attributes. Unlike NGINX’s native error_log directive, the NGINX error_log_write module creates targeted debugging entries from your configuration file.
Why You Need Conditional Error Logging
NGINX’s native error_log directive is powerful but limited. It specifies where errors go and at what level. However, it cannot:
- Write custom messages for specific conditions
- Log only when certain variables match
- Create debugging entries without code changes
- Track specific request patterns across locations
The NGINX error_log_write module solves these limitations. It inserts custom log entries at any severity level. Entries are triggered by NGINX variables and conditions.
How the Module Works
This module operates during NGINX’s log phase. This phase runs after request processing completes. This timing is significant:
- All request variables are fully populated
- The response has already been sent
- Upstream processing is complete
- There’s no performance impact on response time
When NGINX processes a request, each directive is evaluated. If the condition is true, the message goes to the error log.
Configuration Inheritance
Log entries in http context propagate to all servers. Server entries propagate to all locations. This inheritance is unconditional. Child configurations receive parent entries plus local ones.
Installing the NGINX error_log_write Module
RHEL, CentOS, AlmaLinux, Rocky Linux
First, enable the GetPageSpeed repository:
sudo dnf install https://extras.getpagespeed.com/release-latest.rpm
Then install the module:
sudo dnf install nginx-module-error-log-write
After installation, load the module in /etc/nginx/nginx.conf:
load_module modules/ngx_http_error_log_write_module.so;
Verify the installation:
nginx -t
Note: This module is available for RHEL-based distributions only. Debian and Ubuntu packages are not yet available.
The error_log_write Directive
The module provides a single, flexible directive:
Syntax: error_log_write [level=log_level] message=text [if=condition] [if!=condition];
Default: No default (must be explicitly configured)
Context: http, server, location
Parameters
| Parameter | Description | Required |
|---|---|---|
level= |
Log level for the entry | No (default: error) |
message= |
The log message (supports variables) | Yes |
if= |
Condition that must be true | No |
if!= |
Condition that must be false | No |
Available Log Levels
The directive supports these log levels:
| Level | Description |
|---|---|
emerg |
System is unusable |
alert |
Immediate action required |
crit |
Critical conditions |
error or err |
Error conditions (default) |
warn |
Warning conditions |
info |
Informational messages |
debug |
Debug messages (requires debug build) |
stderr |
Direct stderr output |
Important: The
noticelevel is not functional in the current release.
Basic Configuration Examples
Simple Logging
Log a message for every request to a location:
location /api {
error_log_write "message=API endpoint accessed";
proxy_pass http://backend;
}
This writes to the error log at the default error level.
Logging with Custom Level
Specify a different log level:
location /health {
error_log_write level=info "message=Health check performed";
return 200 "OK";
}
Using Variables in Messages
Include request details in your log messages:
location / {
error_log_write level=info "message=Request: $request_method $request_uri from $remote_addr";
root /var/www/html;
}
This produces log entries like:
2026/02/12 14:30:45 [info] 1234#1234: *5 error_log_write: Request: GET /index.html from 192.168.1.100
Conditional Logging Examples
The true power of this directive lies in conditional capabilities.
Log When Condition is True (if=)
Log only when a specific condition is met:
location /debug {
# Only log when ?debug=1 is present
error_log_write level=warn "message=Debug mode enabled for $remote_addr" "if=$arg_debug";
return 200 "Debug endpoint";
}
Log When Condition is False (if!=)
Log when a condition is NOT met:
location /admin {
# Log when Authorization header is missing
error_log_write level=error "message=Unauthorized access from $remote_addr" "if!=$http_authorization";
auth_basic "Admin Area";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://admin_backend;
}
Combining Multiple Conditions
Define multiple log entries for different scenarios:
location /api/v2 {
# Log authenticated requests at info level
error_log_write level=info "message=Authenticated call: $request_uri" "if=$http_authorization";
# Log unauthenticated requests at warn level
error_log_write level=warn "message=Unauthenticated call from $remote_addr" "if!=$http_authorization";
proxy_pass http://api_backend;
}
Real-World Use Cases
Tracking Authentication Failures
Monitor failed authentication attempts:
server {
listen 443 ssl;
server_name secure.example.com;
# Log all requests missing auth token
error_log_write level=warn "message=Missing token: $request_uri from $remote_addr" "if!=$http_x_auth_token";
location /api {
proxy_pass http://secure_backend;
}
}
For advanced authentication, see the NGINX JWT authentication module. Also check the NGINX TOTP two-factor authentication module.
Debugging Specific User Agents
Track requests from specific clients:
location / {
# Log requests from debugging client
error_log_write level=info "message=Debug client: $request_uri" "if=$http_x_debug_client";
root /var/www/html;
}
For sophisticated debugging, the NGINX echo module provides shell-style scripting.
Monitoring Slow Backend Indicators
Log when clients signal slow responses:
location /api {
# Log if client indicates timeout concern
error_log_write level=warn "message=Timeout warning: upstream=$upstream_addr" "if=$http_x_timeout_warning";
proxy_pass http://backend;
}
Request Rate Monitoring
Track high-volume request patterns:
location /search {
# Log every search request with query
error_log_write level=info "message=Search query: $arg_q from $remote_addr";
proxy_pass http://search_backend;
}
Geographic Access Logging
When combined with GeoIP modules, log geographic data:
location /checkout {
# Log checkout attempts with country info
error_log_write level=info "message=Checkout from $geoip2_country for $remote_addr";
proxy_pass http://payment_backend;
}
Configuration Inheritance in Detail
Understanding inheritance is crucial for effective use.
http {
# Logged for ALL requests
error_log_write level=info "message=Global: $request_uri";
server {
listen 80;
server_name example.com;
# Logged for all requests to this server
error_log_write level=info "message=Server: $host";
location / {
error_log_write level=warn "message=Root location accessed";
root /var/www/html;
}
location /api {
# Inherits http and server entries
error_log_write level=info "message=API: $request_method";
proxy_pass http://api_backend;
}
}
}
A request to /api/users produces three log entries:
1. “Global: /api/users” (from http context)
2. “Server: example.com” (from server context)
3. “API: GET” (from location context)
Performance Considerations
The module is designed for minimal performance impact:
Log Phase Execution: Runs during NGINX’s log phase. This occurs after the response is sent. Logging does not delay responses.
Variable Evaluation: Complex expressions are evaluated at log time. Keep messages simple to minimize overhead.
Condition Evaluation: Uses NGINX’s optimized complex value mechanism.
Disk I/O: Log entries go to the error_log file. Consider I/O for high-traffic servers:
error_log /var/log/nginx/error.log warn;
For alternative logging, see the NGINX pipelog module.
Troubleshooting
Log Entries Not Appearing
- Check log level: Your
error_logdirective must include the target level:
error_log /var/log/nginx/error.log info;
- Verify module loading:
nginx -T 2>&1 | grep error_log_write
- Check condition evaluation: Empty or “0” values prevent logging.
Quoting Syntax
Parameters with spaces must be quoted:
# CORRECT
error_log_write "message=Request from $remote_addr";
# INCORRECT
error_log_write message=Request from $remote_addr;
notice Level Not Working
Use level=info or level=warn as alternatives.
Comparison with Other Logging Methods
error_log_write vs access_log
The access_log directive logs successful requests in a structured format. It’s ideal for traffic analysis. The error_log_write directive targets specific conditions with custom messages. Use access_log for general traffic. Use error_log_write for targeted debugging.
error_log_write vs Application Logging
Application-level logging requires code changes. The NGINX error_log_write module works at the proxy layer. You can add logging without modifying backends. This is useful when you cannot change application code.
Native NGINX Logging vs error_log_write
| Feature | Native error_log | error_log_write |
|---|---|---|
| Global error logging | Yes | No |
| Custom messages | No | Yes |
| Variable interpolation | No | Yes |
| Conditional logging | No | Yes |
| Per-location control | No | Yes |
| Log level per entry | No | Yes |
Use native error_log for system errors. Use error_log_write for custom application-level logging.
Security Considerations
Follow these security practices:
Avoid Logging Sensitive Data: Never log passwords or tokens:
# BAD
error_log_write "message=Auth: $http_authorization";
# GOOD
error_log_write "message=Auth header present" "if=$http_authorization";
Protect Log Files:
chmod 640 /var/log/nginx/error.log
chown nginx:adm /var/log/nginx/error.log
Rate Awareness: High-frequency logging fills disk quickly. Use conditions to limit volume.
Integration with Log Analysis Tools
The error_log_write entries follow NGINX’s standard format. They work with existing log analysis tools:
- Logrotate: Standard rotation works without changes
- Fail2ban: Create filters matching the
error_log_write:prefix - ELK Stack: Parse using grok patterns for NGINX error logs
- Prometheus: Use mtail or similar exporters to create metrics
Example fail2ban filter:
[Definition]
failregex = error_log_write: Unauthorized access from <HOST>
Best Practices Summary
- Use appropriate log levels: Reserve
errorfor issues. Useinfofor routine tracking. -
Keep messages concise: Include only relevant information.
-
Use conditions wisely: Avoid logging every request. Target specific scenarios.
-
Test configurations: Verify with
nginx -tbefore deployment. -
Monitor log growth: Conditional logging can generate significant volume.
Conclusion
The NGINX error_log_write module provides flexible conditional logging for your configuration. You gain visibility into request patterns without modifying application code.
Key benefits:
- Debugging flexibility: Add targeted logging without code changes
- Conditional control: Log only when conditions match
- Variable support: Include any NGINX variable in messages
- Zero response delay: Runs after response is sent
Install the module from the GetPageSpeed repository today.
Source code is on GitHub.
