Nginx log splitting is a very common operation and maintenance work, there are many articles about this area, usually no more than two methods: one is to use cron periodically execute shell scripts to archive log files; The second is to use dedicated log archiving work logrotate.

The first method of writing shell scripts is not used much because it is so primitive. Logrotate, by contrast, is a lot easier to use and easy to configure. How to configure Logrotate is not the subject of this article, you can search for it if you are interested.

While most Linux distributions ship with Logrotate, there are cases where Logrotate is not necessarily installed, such as nginx’s Docker image or older Linux distributions. Logrotate can be installed using package manager, but only if the server has access to the Internet, which is not always possible within an enterprise.

There is an easier way to do this. As of Nginx 0.7.6, the access_log path configuration can contain variables, which can be used to implement log splitting. For example, if we wanted to split the log by day, we could configure it like this:

access_log logs/access-$logdate.log main;
Copy the code

So the next question is how do we extract the $logDate variable? There are suggestions on the Internet to use the following methods:

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

access_log logs/access-$year-$month-$day.log main;
Copy the code

$year-$month-$day.log = access-year -$month-$day.log = access-year -$month-$day. Second, if can only occur in server and location blocks, whereas access_log is usually configured in the top-level HTTP block, so if is not applicable.

If you want to set access_log in an HTTP block, a better way is to use the map directive:

map $time_iso8601 $logdate { '~^(? <ymd>\d{4}-\d{2}-\d{2})' $ymd; default 'date-not-found'; } access_log logs/access-$logdate.log main;Copy the code

The map directive perfectly solves the problem of the if directive by setting the default value to ensure that $logDate is always available and can appear in HTTP blocks.

Finally, to improve log efficiency, it is recommended to configure open_log_file_cache. The complete log splitting configuration is as follows:

log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; map $time_iso8601 $logdate { '~^(? <ymd>\d{4}-\d{2}-\d{2})' $ymd; default 'date-not-found'; } access_log logs/access-$logdate.log main; open_log_file_cache max=10;Copy the code

In this paper, to the end.