Resolving Duplicate Nginx Access Log Entries When Customizing Log Format


1 views

When working with Nginx's logging system on Ubuntu servers, many developers encounter duplicate entries in access logs after attempting to customize the log format. The standard configuration hierarchy often leads to multiple access_log directives being processed unintentionally.

The default Ubuntu Nginx setup uses this include pattern:

http {
    # Main config
    access_log /var/log/nginx/access.log;
    
    # Included files
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

When you add another access_log directive in conf.d/, both directives remain active because Nginx processes them sequentially rather than overwriting them.

To properly override the default logging without modifying nginx.conf:

# In /etc/nginx/conf.d/log_format.conf
log_format extended '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';

# This will replace previous access_log directives in this context
access_log /var/log/nginx/access.log extended if=$loggable;

For more control, consider these approaches:

# 1. Using conditional logging
map $http_x_forwarded_for $loggable {
    default 1;
    ""      0; # Don't log requests without X-Forwarded-For
}

# 2. Separate logs for different formats
access_log /var/log/nginx/extended.log extended;
access_log /var/log/nginx/basic.log;

After making changes:

sudo nginx -t
sudo service nginx reload
tail -f /var/log/nginx/access.log

When working with Nginx's logging system on Ubuntu 14.04, a common pitfall occurs when trying to customize the log format while maintaining the same log file path. The default configuration in /etc/nginx/nginx.conf typically includes:

access_log /var/log/nginx/access.log;

When you add a customized log format in included configuration files (like those in /etc/nginx/conf.d/), you might inadvertently create duplicate entries because:

  • The original access_log directive remains active
  • Your new directive adds another logging channel
  • Both configurations write to the same file

To properly modify the log format without creating duplicates, you need to understand Nginx's configuration inheritance. Here's the correct approach:

# First define your custom log format at http context level
log_format main_ext '$remote_addr - $remote_user [$time_local] "$request" '
                   '$status $body_bytes_sent "$http_referer" '
                   '"$http_user_agent" "$http_x_forwarded_for"';

# Then override the access_log in your server context
server {
    access_log /var/log/nginx/access.log main_ext;
    ...
}

Several key points to remember when implementing this solution:

  1. The log_format directive must appear before any access_log directives that reference it
  2. For maximum compatibility, place your format definition in /etc/nginx/nginx.conf within the http block
  3. You can completely disable access logging for specific contexts using access_log off;

After making changes, always test your configuration:

sudo nginx -t
sudo service nginx reload

Check your logs to confirm only single entries are being written:

sudo tail -f /var/log/nginx/access.log

For more advanced scenarios, you might consider conditional logging:

map $http_x_forwarded_for $loggable {
    default 1;
    ""      0;
}

access_log /var/log/nginx/access.log main_ext if=$loggable;