2

I've tried this tutorial to rotate log file without external software, but it seems it doesn't work, my configuration on the server { block:

if ($time_iso8601 ~ "^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})") {}
access_log /var/log/access-$year-$month-$day.log;
error_log /var/log/error-$year-$month-$day.log;

and the file created, named:

-rw-r--r-- 1 root root    0 May 28 17:46 error-$year-$month-$day.log

my NginX version:

nginx version: nginx/1.8.0

built with OpenSSL 1.0.2a 19 Mar 2015

TLS SNI support enabled

configure arguments: --prefix=/etc/nginx --conf-path=/etc/nginx/nginx.conf --sbin-path=/usr/bin/nginx --pid-path=/run/nginx.pid --lock-path=/run/lock/nginx.lock --user=http --group=http --http-log-path=/var/log/nginx/access.log --error-log-path=stderr --http-client-body-temp-path=/var/lib/nginx/client-body --http-proxy-temp-path=/var/lib/nginx/proxy --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-imap --with-imap_ssl_module --with-ipv6 --with-pcre-jit --with-file-aio --with-http_dav_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_realip_module --with-http_spdy_module --with-http_ssl_module --with-http_stub_status_module --with-http_addition_module --with-http_degradation_module --with-http_flv_module --with-http_mp4_module --with-http_secure_link_module --with-http_sub_module

8
  • Why do you want to do that instead of using log rotate?
    – AD7six
    May 28, 2015 at 11:52
  • 1
    I don't want to install another program..
    – Kokizzu
    May 28, 2015 at 12:11
  • @Kokizzu do you use containers for nginx?(docker/lxd)
    – Navern
    May 28, 2015 at 13:32
  • 1
    logrotate comes pre-installed on many of the most common Linux distributions, and is pretty much a standard item which you usually want to be present. If you want to avoid it, it's usually because you are operating in a minimal environment (e.g. embedded system or docker container), in which case you are probably better shipping the logs to something external to your system to manage.
    – mc0e
    May 28, 2015 at 13:36
  • 1
    logrotate is preinstalled. Moreover almost every service-daemon with custom logs have default logrotate configuration installed along binary package.
    – Navern
    May 28, 2015 at 21:33

4 Answers 4

3

See my comment above, and cpburnz's reasoning, but if you really want to proceed:

You could write a script which writes just the log commands to an include file, with the current date hard-coded. You'd have that included into your nginx config file, and your script would restart or reload nginx after writing the log commands to the include file.

Something like:

#!/bin/bash

date=`date -Id`

cat > /etc/nginx/includes/log_by_date.inc <<EOF
access_log /var/log/access-${date}.log;
error_log /var/log/error-${date}.log;
EOF

/etc/init.d/nginx restart

You'd run that from cron, most likely close to midnight.

plus of course you need to include /etc/nginx/includes/log_by_date.inc where you have your current logging commands.

3

According to that blog post,

Please note, that it’s not possible to embed variables in error_log directives, as any potential error would not be able to be logged if the file cannot be written.

With that in mind, it is not possible to have the error log automatically rotated with the naming format error-$year-$month-$day.log using that Nginx method.


However, setting up log rotation for the error log is not very difficult. Create a simple shell (bash) script at /usr/local/bin/rotate_nginx_error_log.sh:

#!/bin/sh
# /usr/local/bin/rotate_nginx_error_log.sh

# Get yesterday's date as YYYY-MM-DD
YESTERDAY=$(date -d 'yesterday' '+%Y-%m-%d') 

PID_FILE=/run/nginx.pid
LOG_FILE=/var/log/error.log
OLD_FILE=/var/log/error-$YESTERDAY.log

# Rotate yesterday's log.
mv $LOG_FILE $OLD_FILE

# Tell nginx to reopen the log file.
kill -USR1 $(cat $PID_FILE)

Make sure it has executable permissions:

chmod +x /usr/local/bin/rotate_nginx_error_log.sh

Then add a cronjob to your crontab that rotates the log nightly at midnight:

0 0 * * * /usr/local/bin/rotate_nginx_error_log.sh
2

Here is what I have on my server:

if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})") {
    set $year $1;
    set $month $2;
    set $day $3;
}

access_log /path/to/logs/nginx-access-$year-$month.log;

Now, sometimes $time_iso8601 has not the expected format, and the logs are then written in a file called nginx-access--.log (indeed, $year and $month are not set).

So I will think about changing the lines to something like this:

if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})") {
    set $year $1;
    set $month $2;
    set $day $3;

    access_log /path/to/logs/nginx-access-$year-$month.log;
}
else {
    access_log /path/to/logs/nginx-access-notime.log;
}

However, as told by @cpburnz, you won't be able to do this for error logs.

2
  • 1
    This works great in windows but not in Linux (CentOS) - no access log file is written for some unknown reason.
    – Marc
    Feb 25, 2020 at 10:12
  • Doesn't work in Debian as well.
    – TCB13
    Apr 1, 2022 at 21:36
1

The following works for the access log with nginx 1.13.x

We wanted our access log config in the 'http' block, 'if' isn't allowed there so used 'map' instead:

http {
    ...

    # Variable for access log filename date
    map $time_iso8601 $logdate {
        '~^(?<ymd>\d{4}-\d{2}-\d{2})'   $ymd;
        default                         'nodate';
    }

    log_format    acfmt    '$remote_addr "$request" "$query_string" "$http_referer" $request_time $status';
    access_log    'logs/access_${logdate}.log'    acfmt;

    ...
}

Log rotation occurs on the first request each day. Contrary to documentation elsewhere, a SIGUSR1 does not seem to be required.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .