目标描述
Golang程序将日志写入到rsyslog的LOCAL0中。
所以这里要使用rsyslog记录来自LOCAL0的日志,几点需求:
- 日志存储在
/xxx/程序名/程序名.log
下。 - 要对日志进行切割,压缩。
这里主要需要研究的功能就是:
rsyslog
的日志动态路径。Logrotate
的定期日志切割。Logrotate
的日志压缩。
另外:
这里系统为Centos7,不涉及远程日志记录。
关于rsyslog和Logrotate的介绍网上有很多:
rsyslog的配置
rsyslog版本(centos7):8.24.0-41
基本配置
rsyslog的配置文件位于/etc/rsyslog.conf
,
1 | ... |
上面的配置中,所使用的*
就表示通配,例如mail.*
就表示来自mail
的所有级别日志都记录到
-/var/log/maillog
中。*.emerg
则表示所有emerg
级别以上的日志(其实emerg
已经是最高级别)都发送给所有正在登陆的用户。
rsyslog有三种配置格式basic
、advanced
和obsolete legacy
,它们可以在同一个配置文件中混用,但是官方建议尽量避免使用obsolete legacy
配置格式,
因为这个不健康,官方原话:Do not use obsolete legacy format. It will make your life miserable.
1 | basic |
这里如果要让自己的程序使用rsyslog来记录日志,那么就可以使用LOCAL0~6
这些facility来进行我们的自定义日志记录,
配置日志动态路径
例如一条在rsyslog接收到一条日志之后,希望它能将根据日志附带的tag信息, 将日志打印到 /logdir/tag/tag.log 文件,这就是动态日志路径。
要达到这个目的,使用rsyslog配置中的Templates语法结构即可。
这里可以使用Templates
来定义一段字符串,字符串中可以带有变量,这样就可以达到日志记录位置随日志的tag信息而变化的目的。
修改 /etc/rsyslog.conf :
1 | template(name="MyDynFile" type="string" string="/var/log/%programname%/%programname%.log") |
上面的配置中,首先定义了一个string类型的Template,然后将local0的所有日志输入到这个路径下的日志文件中,
这里的%programname%
即表示:
the “static” part of the tag, as defined by BSD syslogd. For example, when TAG is “named[12345]”, programname is “named”.
也就是说这里将日志保存到/var/log/%programname%/%programname%.log
路径之下,更多的字段可以参考rsyslog Properties。
测试配置:
首先使用命令看配置是否有语法错误:
1 | $ /usr/sbin/rsyslogd -f /etc/rsyslog.conf -N1 |
重启rsyslog服务:
1 | sudo systemctl restart rsyslog |
测试配置是否达到预期:
1 | logger -t test -p local0.info "hello world" |
可以看到这里动态日志路径配置成功。
Logrotate 配置
上面完成了使用rsyslog来进行日志记录,但是如果不对日志进行切割压缩,日志的大小就会无限增长,不仅将来不好查询,而且占存储空间, 这里可以使用Logrotate来进行日志的切割与压缩。
Logrotate并不是一个一直运行的linux程序,它的自动运行是linux的计划任务cron来实现的,位于/etc/cron.daily/logrotate
,
它每天执行一次。
而Logrotate的配置文件则位于/etc/logrotate.conf
,这个配置文件里面又包含了目录/etc/logrotate.d/
下的所有配置文件,
所有通常在/etc/logrotate.d/
目录下来添加自定义的配置文件。
切割日志:
- 方法一:将原日志文件重命名,重新创建新的日志文件,通知使用此日志的进程使用新的日志文件。对应Logrotate中的
create
。 - 方法二:先将原日志文件复制,然后截断原文件,这样不需要通知使用此日志的进程,但两个操作之间有短暂的时间间隙,可能会丢失日志。对应Logrotate中的
copytruncate
。 - 方法三:只复制原日志文件。对应Logrotate中的
copy
。
这里之所以有三种切割日志的方法,原因在于当一个程序获取到一个文件句柄并向里面写入数据时,即使此时文件名发生了变化, 也不会影响之前的文件句柄的使用,程序仍然可以通过这个文件句柄写入数据到此文件中,如果不对原程序发出通知,让其重新获取文件句柄, 那么这个日志文件的大小就会继续增长。
压缩日志:经过日志切割,原日志文件已经重命名,已经没有进程再继续使用它,这时便可以进行任意的操作,想要压缩就可以直接进行压缩。
rotate:保留日志文件的数量(轮转数量)。例如rotate为3,切割出来日志文件为log.1
、log.2
和log.3
,则下一次再进行切割时,
会将log.3
删除,log.2
重命名为log.3
,log.1
重命名为log.2
,新切割出来的日志文件命名为log.1
。
Logrotate的具体配置。
这里添加一个新的配置文件到/etc/logrotate.d/
目录下,内容如下:
1 | /var/log/*/*.log { |
这里首先配置的路径为/var/log/*/*.log
,因为上面rsyslog将LOCAL0的日志记录到了/var/log/%programname%/%programname%.log
,
这样便能够通配到所有LOCAL0的日志文件。
注意到这里的最后几句配置:
1 | postrotate // 脚本,用于通知rsyslog使用新的日志文件 |
其中夹在postrotate
和endscript
中间的就是脚本,postrotate
表示脚本在rotate之后运行,也就是此时已经将原日志文件重命名,
并且创建了新日志文件,但是还没有对原日志文件进行压缩。脚本中使用kill -HUP
来通知rsyslog使用新日志文件,脚本执行完毕后,
Logrotate将对原日志文件使用gzip进行压缩。
这里切割出来的日志文件将保存在与原日志文件同一目录下,如果想要将切割出来的日志文件保存到别的目录,可以添加下面的配置:
1 | olddir /var/log/old |
这样切割下来的日志文件就会存储在/var/log/old
目录之下(old目录需要手动创建)。
Logrotate 日志压缩
默认情况下,Logrotate使用gzip进行压缩,当然也可以配置其它的压缩工具。
如果要使用bzip2
来进行压缩,则可以使用下面的配置:
1 | compress |
那么在压缩日志时,就会使用/usr/bin/bzip2 -9
来进行压缩。
使用bzip2可以达到更大的压缩比,但是在压缩过程中也会消耗更多的CPU。
同理也可以配置成其它的压缩工具。
Logrotate 定期执行
Logrotate通过cron来定期运行,默认配置在/etc/cron.daily/logrotate
,也就是默认每天执行一次。
使用下面命令可以让Logrotate立即执行某一配置,而不用等待计划任务:
1 | // 立即执行syslog配置 |
如果想要更灵活的执行时间配置,就可以在cron中来添加,例如想要Logrotate每分钟执行一次,则可以在/etc/crontab
中进行配置:
1 | sudo vim /etc/crontab |
这样就可以使得Logrotate每分钟执行一次。
配置总结
rsyslog:
1 | umask 0000 |
这里的umask
配合dirCreateMode
和fileCreateMode
来使用,这样便可指定创建出来的文件夹与文件的默认权限。
Logrotate:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/data1/log/*/*.log {
create 0644 root root
daily
rotate 65535
size 1M
dateext
dateformat -%Y%m%d.%s
missingok
notifempty
compress
sharedscripts
postrotate
/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
endscript
}
1 | /data1/log/*/*.log { |
补充:docker内使用rsyslog + Logrotate
今天要在docker中配置rsyslog + Logrotate,发现centos7的docker中没有自带rsyslog和cron,并且没有systemd,所以不能通过systemctl来操作服务。
首先需要安装rsyslog和cron:
1 | yum install -y rsyslog cronie |
非常重要的一点在于:rsyslog 默认通过 journal 读取日志信息,但CentOS镜像默认并未安装systemd和journald。
首先kill掉正在运行的rsyslog进程,然后修改配置:
- 注释
$ModLoad imjournal
- 注释
$IMJournalStateFile imjournal.state
- 将
$OmitLocalLogging on
改为$OmitLocalLogging off
- 将journal的配置删除:
rm -rf /etc/rsyslog.d/listen.conf
启动rsyslog:
1 | # rsyslogd |
启动cron:
1
# crond
1 | # crond |
补充:修改rsyslog的日志记录格式
首先可以看到默认的rsyslog的格式:
1 | Sep 30 17:21:49 localhost test: Hello World!!! |
它所对应的配置格式是:
1 | template(name="FileFormat" type="string" |
可以看到其实有点儿丑,为了把它变得好看一点,需要新建一个template来定义它的格式。
官方文档中这部分定义的字段都可以使用:
这里定义的template
如下:
1 | template(name="MyOutFmt" type="list") { |
配置输出文件的template
为MyOutFmt
:
1 | local0.* action(type="omfile" dynaFile="MyDynFile" template="MyOutFmt" dirCreateMode="0755" fileCreateMode="0644" ioBufferSize="64K") |
测试效果:
1 | logger -t test -p local0.info 'Hello World!!!' |
ok,顺眼多了。