nginx正确的logrotate配置

nginx默认的logrotate配置如下

[ec2-user@rpc_ngx ~]$ cat /etc/logrotate.d/nginx
/var/log/nginx/*log {
    create 0664 nginx root
    daily
    rotate 10
    missingok
    notifempty
    compress
    sharedscripts
    postrotate
        /etc/init.d/nginx reopen_logs
    endscript
}

每天早上0点的时候会对所有的log文件切分,压缩,轮转,然后调用`nginx reopen_logs`.

如果你像我们需要对nginx logs进行分析的话

  1. 发现存在.gz文件就将这个文件copy到aws s3上
  2. 在aws上运行emr对s3上文件进行分析

那么你会发现这个gzip文件是不完整的。EMR日志会出现下面这些错误

19/04/23 08:35:02 INFO HadoopRDD: Input split: s3a://fm.castbox.data.nginx-logs/sync_server_access/201904/20190423-app1.gz:0+542490624
Traceback (most recent call last):
  File "/mnt/yarn/usercache/hadoop/appcache/application_1556007841411_0001/container_1556007841411_0001_02_000002/pyspark.zip/pyspark/daemon.py", line 170, in manager
  File "/mnt/yarn/usercache/hadoop/appcache/application_1556007841411_0001/container_1556007841411_0001_02_000002/pyspark.zip/pyspark/daemon.py", line 73, in worker
  File "/mnt/yarn/usercache/hadoop/appcache/application_1556007841411_0001/container_1556007841411_0001_02_000002/pyspark.zip/pyspark/worker.py", line 397, in main
    if read_int(infile) == SpecialLengths.END_OF_STREAM:
  File "/mnt/yarn/usercache/hadoop/appcache/application_1556007841411_0001/container_1556007841411_0001_02_000002/pyspark.zip/pyspark/serializers.py", line 714, in read_int
    raise EOFError
EOFError
Traceback (most recent call last):
  File "/mnt/yarn/usercache/hadoop/appcache/application_1556007841411_0001/container_1556007841411_0001_02_000002/pyspark.zip/pyspark/daemon.py", line 170, in manager
  File "/mnt/yarn/usercache/hadoop/appcache/application_1556007841411_0001/container_1556007841411_0001_02_000002/pyspark.zip/pyspark/daemon.py", line 73, in worker
  File "/mnt/yarn/usercache/hadoop/appcache/application_1556007841411_0001/container_1556007841411_0001_02_000002/pyspark.zip/pyspark/worker.py", line 397, in main
    if read_int(infile) == SpecialLengths.END_OF_STREAM:
  File "/mnt/yarn/usercache/hadoop/appcache/application_1556007841411_0001/container_1556007841411_0001_02_000002/pyspark.zip/pyspark/serializers.py", line 714, in read_int
    raise EOFError
EOFError
19/04/23 08:35:41 ERROR Executor: Exception in task 1.3 in stage 0.0 (TID 5)
java.io.EOFException: Unexpected end of input stream

出现不完整gz文件的原因在于gzip压缩成.gz文件并不是原子操作。 在压缩初始的时候就会生成.gz文件,所以依赖.gz这个文件的生成不可靠的。

如果在确保.gz完全压缩完成呢?一开始我觉得可以在 `postrotate` 这里增加DONE(标记)文件 然而实际这种方式并不work, 因为我理解错了logrotate的执行顺序。 通过我这几次实验+阅读文档,这个logrotate的顺序应该是

  1. 先对所有的log文件重新命名
  2. 对历史数据进行轮转
  3. 调用`nginx reopen_logs`
  4. 对这些新生成的文件压缩成.gz文件

所以 `postrotate` 是在压缩成.gz文件就执行了,并不能满足我的需求。

查阅了logrotate的文档之后,发现有个 `lastaction` block. 这个区域内部的代码是在 所有动作完成之后执行的,正好可以满足我的需求。所以一个nginx比较好的logrotate配置应该是这样的

[ec2-user@rpc_ngx nginx-logs]# cat /etc/logrotate.d/nginx
/var/log/nginx/*log {
    create 0664 nginx root
    daily
    rotate 10
    missingok
    compress
    notifempty
    sharedscripts
    postrotate
        /etc/init.d/nginx reopen_logs
    endscript
    lastaction
        echo /var/log/nginx/*log-$(date +%Y%m%d).gz | sed -e 's/.gz/.gz.done/g' | xargs touch
    endscript
}