linux日志规则

本文总阅读量

前记

最近系统上出现部分日志丢失的情况,为了解决这个问题,开始了解Linux的日志结构和机制.
注:由于这些应用都是需要用配置去改良或者指导他们如何去做,所以除了简述Linux的结构和功能外,更多的是如何去配置他们,如果不想看配置说明,可以忽略2,3,4点,不过最重要的是了解整个日志记录的机制,以及通过配置去了解这套机制会如何去限制日志的记录以及优化传输,这样我们才能去灵活使用他们

1.发送以及保存数据

Linux中有一套稳定的日志管理系统,除了方便的过滤和分发外,为了多个服务器日志管理,还有一套稳定的日志发送结构,方便不漏日志的情况下,收集所有服务器的日志

1.1结构图

注:系统为debain7,以为本地发送,本地接受为例

一般程序通过调用Linux的日志接口把日志传给/dev/log,由journald发送到rsyslog service模块,再根据syslog协议把不同的日志转向不同的输出模块,输出不同的日志
img

1.2如何发送日志

程序根据syslog标准,封装日志,并发送到指定socket(/dev/log)

1.3 /dev/log

一个UNIX域套接字,接受在本地机器上运行的进程所产生的消息,如果要想让系统记录日志,就可以按照syslog规范把日志发送到/dev/log/这个socket
除此之外还有/dev/klog – 一个从UNIX内核接受消息的设备.
如果看到syslog记录了kern的日志,却没记录普通日志,那就是/dev/log这个socket缓冲区满了,可以尝试通过kern.ipc.maxsockbuf改变缓冲区大小,但并不能完全解决问题.

1.4 journald

systemd/journald 提供了 socket /run/systemd/journal/syslog,通过软连接,让发送到/dev/log/的数据实际上发送到/run/systemd/journal/syslog,通过读取标准socket来读取日志。不过systemd-journald 所记录的数据其实是在内存中,但是系统还是利用文件的型态将它记录到 /run/log/ 下面,重新开机后,在内存的数据就会被清除掉.
通过在 /etc/systemd/journald.conf 中设置 ForwardToSyslog=yes,journald就会把日志发送到rsyslog.
journald自己也提供了很多功能,比如有:过滤输出,大小限制等等
PS: 在还没有systemd时代,必须要开机完成并且执行了 rsyslogd 这个 daemon 之后,登录文件才会开始记录。所以,需要自己产生一个 klogd 的服务, 才能将系统在开机过程、启动服务的过程中的信息记录下来,然后等 rsyslogd 启动后才传送给它来处理.现在有了systemd主动调用 systemd-journald 来协助记载登录文件,在开机过程中的所有信息,包括启动服务与服务若启动失败的情况等等,都可以直接被记录到 systemd-journald.

1.5 rsyslog

rsyslog服务启动后(以监控本地日志为例子,也就是加载module(load=”imuxsock”)) 从/run/systemd/journal/syslog 这个socket获取syslog类型日志,然后进入主队列根据对应规则写日志.
rsyslog采用C/S结构,可以日志信息追加到对应的日志文件中,一般在/var/log目录下。它还可以把日志信息通过网络协议发送到另一台Linux服务器上,或者将日志存储在MySQL或Oracle等数据库中。
除此之外,rsyslog能够快速的过滤,转发,发送日志,(还有官方说的每秒支持百万级日志),所以rsyslog的内容非常丰富.我们只要通过对配置文件进行简单的修改,就能实现传输,过滤等功能.
如上面的结构图,rsyslog中只有一个主消息队列,任何消息都要先进入这个队列,然后直到进入到动作队列之后消息才会从这个队列中删除。通常,我们都不会去动主队列的配置,因为默认的设置已经工作得很好;消息经过主消息队列之后,就被rule processor解析和处理,然后根据预先配置的规则压入各自的动作队列,动作队列之后消息最终被消费掉。

2.journald的配置

一般来说,只使用到journald的暂存日志并转发到rsyslog的功能,所以只需要看与暂存内存相关的配置即可

  • Storage 指定如何存数据,默认none
    “volatile” 表示仅保存在内存中, 也就是仅保存在 /run/log/journal 目录中(将会被自动按需创建)。 “persistent” 表示优先保存在磁盘上, 也就优先保存在 /var/log/journal 目录中(将会被自动按需创建), 但若失败(例如在系统启动早期”/var”尚未挂载), 则转而保存在 /run/log/journal 目录中(将会被自动按需创建)。 “auto” 与 “persistent” 类似, 但不自动创建 /var/log/journal 目录, 因此可以根据该目录的存在与否决定日志的保存位置。 “none” 表示不保存任何日志(直接丢弃所有收集到的日志), 但日志转发不受影响。 默认值是 “auto”

  • Compress 默认值”yes”表示 压缩存储大于特定阈值(默认为512字节)的对象。 也可以直接设置一个 字节值(可以带有 K, M, G 后缀) 表示的阈值, 表示压缩存储 大于指定阈值的对象。

  • Seal 默认值”yes”表示: 如果存在一个”sealing key”(由 journalctl(1) 的 –setup-keys 命令创建), 那么就为所有持久保存的日志文件启用 FSS(Seekable Sequential Key Generators)保护, 以避免日志文件 被恶意或无意的修改。

  • SplitMode 设置是否按照每个用户分割日志文件,以实现对日志的访问控制(日志守护进程会确保每个用户都能读取自己的日志文件). 默认值为uid
    可以使用的分割策略如下: “uid” 表示每个用户都有自己专属的日志文件(无论该用户是否拥有登录会话),但系统用户的日志依然记录到系统日志中。”none” 表示不对日志文件按不同用户进行分割,而是将所有日志都记录到系统日志中。这意味着非特权用户根本无法读取属于自己的日志信息。 注意, 仅分割持久保存的日志(/var/log/journal), 永不分割内存中的日志(/run/log/journal)。

  • RateLimitIntervalSec 用于设置一个时间段长度,可以使用下面的时间单位: “ms”, “s”, “min”, “h”, “d”
    限制日志的生成速率.表示在 RateLimitIntervalSec 时间段内, 每个服务最多允许产生 RateLimitBurst 数量(条数)的日志。 在同一个时间段内,超出数量限制的日志将被丢弃,直到下一个时间段才能再次开始记录。 对于所有被丢弃的日志消息,仅用一条类似”xxx条消息被丢弃”的消息来代替。 这个限制是针对每个服务的限制,一个服务超限并不会影响到另一个服务的日志记录。
    如果一个服务已经通过 LogRateLimitIntervalSec= 和/或 LogRateLimitBurst= (参见 systemd.exec(5) 手册) 限制了自身的日志生成速率,那么将会覆盖此处的设置。

  • RateLimitBurst 用于设置一个正整数,表示消息条数,默认值是10000条.
    说明见RateLimitIntervalSec

  • SystemMaxUse
    限制磁盘使用量, 也就是 /var/log/journal 的使用量。限制全部日志文件加在一起最多可以占用多少空间。默认值是空间的10%与4G空间两者中的较小者;

  • SystemKeepFree
    限制磁盘使用量, 也就是 /var/log/journal 的使用量。除日志文件之外,至少保留多少空间给其他用途。systemd-journald 会同时SystemKeepFree与SystemMaxUse , 并且尽量限制日志文件的总大小,以同时满足这两个限制。默认值是空间的15%与4G空间两者中的较大者;

  • SystemMaxFileSize
    限制磁盘使用量, 也就是 /var/log/journal 的使用量。限制单个日志文件的最大体积, 到达此限制后日志文件将会自动滚动。 默认值是对应的 SystemMaxUse值的1/8 , 这也意味着日志滚动 默认保留7个历史文件。日志大小 可以使用以1024为基数的 K, M, G, T, P, E 后缀, 分别对应于 1024, 1024², … 字节。

  • SystemMaxFiles,
    限制磁盘使用量, 也就是 /var/log/journal 的使用量。 限制最多允许同时存在多少个日志文件, 超出此限制后, 最老的日志文件将被删除, 而当前的活动日志文件 则不受影响。 默认值为100个。

  • RuntimeMaxUse
    限制内存使用量, 也就是 /run/log/journal 的使用量。限制全部日志文件加在一起最多可以占用多少空间。默认值是空间的10%与4G空间两者中的较小者;

  • RuntimeKeepFree
    限制内存使用量, 也就是 /run/log/journal 的使用量。除日志文件之外,至少保留多少空间给其他用途。systemd-journald 会同时RuntimeKeepFree与RuntimeMaxUse , 并且尽量限制日志文件的总大小,以同时满足这两个限制。默认值是空间的15%与4G空间两者中的较大者;

  • RuntimeMaxFileSize
    限制内存使用量, 也就是 /run/log/journal 的使用量。限制单个日志文件的最大体积, 到达此限制后日志文件将会自动滚动。 默认值是对应的 RuntimeMaxUse值的1/8 , 这也意味着日志滚动 默认保留7个历史文件。日志大小 可以使用以1024为基数的 K, M, G, T, P, E 后缀, 分别对应于 1024, 1024², … 字节。

  • RuntimeMaxFiles
    限制内存使用量, 也就是 /run/log/journal 的使用量。 限制最多允许同时存在多少个日志文件, 超出此限制后, 最老的日志文件将被删除, 而当前的活动日志文件 则不受影响。 默认值为100个。

  • MaxFileSec 日志滚动的时间间隔。 默认值是一个月, 设为零表示禁用基于时间的日志滚动策略。 可以使用 “year”, “month”, “week”, “day”, “h”, “m” 时间后缀, 若不使用后缀则表示以秒为单位。
    通常 并不需要使用基于时间的日志滚动策略, 因为由 SystemMaxFileSize 与 RuntimeMaxFileSize 控制的基于文件大小的日志滚动策略 已经可以确保日志文件的大小不会超标。

  • MaxRetentionSec 日志文件的最大保留期限。 默认值零表示不使用基于时间的日志删除策略。可以使用 “year”, “month”, “week”, “day”, “h”, “m” 时间后缀, 若不使用后缀则表示以秒为单位。
    当日志文件的最后修改时间(mtime)与当前时间之差, 大于此处设置的值时,日志文件将会被删除。 通常并不需要使用基于时间的日志删除策略,因为由 SystemMaxUse= 与 RuntimeMaxUse= 控制的基于文件大小的日志滚动策略 已经可以确保日志文件的大小不会超标。

  • SyncIntervalSec 向磁盘刷写日志文件的时间间隔, 默认值是五分钟。
    刷写之后,日志文件将会处于离线(OFFLINE)状态。 注意,当接收到 CRIT, ALERT, EMERG 级别的日志消息后, 将会无条件的立即刷写日志文件。 因此该设置仅对 ERR, WARNING, NOTICE, INFO, DEBUG 级别的日志消息有意义。

  • ForwardToSyslog 表示是否将接收到的日志消息转发给传统的 syslog 守护进程,默认值为”no”。 如果设为”yes”,但是没有任何进程监听对应的套接字,那么这种转发是无意义的。 此选项可以被内核引导选项 “systemd.journald.forward_to_syslog” 覆盖。

  • ForwardToKMsg 表示是否将接收到的日志消息转发给内核日志缓冲区(kmsg),默认值为”no”。 此选项可以被内核引导选项 “systemd.journald.forward_to_kmsg” 覆盖。

  • ForwardToConsole 表示是否将接收到的日志消息转发给系统控制台,默认值为”no”。 如果设为”yes”,那么可以通过下面的 TTYPath= 指定转发目标。 此选项可以被内核引导选项 “systemd.journald.forward_to_console” 覆盖。

  • ForwardToWall 表示是否将接收到的日志消息作为警告信息发送给所有已登录用户,默认值为”yes”。 此选项可以被内核引导选项 “systemd.journald.forward_to_wall” 覆盖。

  • MaxLevelStore 设置记录到日志文件中的最高日志等级,默认值为”debug”;可以被内核引导选项”systemd.journald.max_level_store”覆盖
    可以设为日志等级的名称, 也可以设为日志等级对应的数字: “emerg”(0), “alert”(1), “crit”(2), “err”(3), “warning”(4), “notice”(5), “info”(6), “debug”(7) 。 所有高于设定等级的日志消息都将被直接丢弃, 仅保存/转发小于等于设定等级的日志消息。

  • MaxLevelSyslog 设置转发给传统的 syslog 守护进程的最高日志等级, 默认值为”debug”;可以被内核引导选项”systemd.journald.max_level_syslog”覆盖
    选项说明同MaxLevelStore

  • MaxLevelKMsg 设置转发给内核日志缓冲区(kmsg)的最高日志等级,默认值为”notice”; 可以被内核引导选项”systemd.journald.max_level_kmsg”覆盖
    选项说明同MaxLevelStore

  • MaxLevelConsole 设置转发给系统控制台的最高日志等级,默认值为”info”;可以被内核引导选项”systemd.journald.max_level_console”覆盖
    选项说明同MaxLevelStore

  • MaxLevelWall 设置作为警告信息发送给所有已登录用户的最高日志等级,默认值为”emerg”;可以被内核引导选项”systemd.journald.max_level_wall”覆盖
    选项说明同MaxLevelStore

  • ReadKMsg 是否收集内核日志。 默认值 yes 表示从 /dev/kmsg 中读取内核产生的日志消息。

  • TTYPath 指定 ForwardToConsole=yes 时所使用的控制台TTY, 默认值是 /dev/console

  • LineMax
    在将日志流转化为日志记录时,每条日志记录最大允许的长度(字节)。 如果将单元的标准输出(STDOUT)/标准错误(STDERR)通过流套接字连接到日志中, 那么将会以换行符(“\n”, ASCII 10)与NUL字符(“\0”, ASCII 0)作为分割符, 把日志流切分成一条条独立的日志记录。 如果超过此处设置的长度之后仍然没有遇到分割符, 那么将会自动插入一个分割符,以强制将单行超长日志截断为多行。 此选项的值越大,每个日志流客户端日志守护进程占用的内存也越大(最大值等于此选项的值)。 另外,此选项的值太大也会造成与传统日志传输协议的不兼容(太长的日志无法封装在单个 AF_UNIX 或 AF_INET 报文内)。 此选项的值以字节为单位,同时也可以在数字的末尾加上 K, M, G, T 后缀(以1024为基准)。 默认值 48K 是一个足够大并且也能保持与传统日志传输协议兼容的值。 注意, 不能设为小于 79 的值(将被自动提升到79)。

    3.rsyslog配置

    rsyslog目前支持两种语法配置,个人觉得两种都有它的方便性,所以都是混用

    3.1过滤器

    过滤器有时候被称为选择器(selector),rsyslog可以配置三种形式的过滤器:

  • Facility/Priority-based filter

  • Property-based filter

  • Expression-based filter

3.1.1Facility/Priority-based 过滤器

Facility
代码 名称 描述
0 kern 内核
1 user 用户级
2 mail 邮件
3 daemon 系统
4 auth 安全与授权
5 syslog 守护进程
6 lpr 打印相关
7 news 网络消息
8 uucp uucp子系统
9 时钟
10 authpriv 安全与授权
11 ftp FTP
12 - NTP
13 - 日志审计
14 - 日志报警
15 cron 定时器
16 local0 用户自定义
17 local1 用户自定义
18 local2 用户自定义
19 local3 用户自定义
20 local4 用户自定义
21 local5 用户自定义
22 local6 用户自定义
23 local7 用户自定义
Priority
0 Emergency emerg 紧急
1 Alert alert 报警
2 Critical crit 关键
3 Error err 错误
4 Warning warn 警告
5 Notice notice 通知
6 Informational info 消息
7 Debug debug 调试

通配符*的意思是任何类型。例如*.* ,即所有的Facility和Priority。
举个例子:cron.alert的意思是:cron定期任务所产生的警告日志,任何等于alert或者高于alert等级的日志(crit、err、warning等)都会被指定的动作处理。
如果希望只处理定义等级的日志,而不处理高于这个等级的日志,可以使用等号(=),例如:

1
cron.=alert /var/log/cron

有一些子系统产生的日志可能没有Priority,那么可以使用关键字none,例如

1
news.none /var/log/messages

除了星号和等号,过滤器中还可以使用逗号(,)和感叹号(!),逗号用于分隔多个Priority,而感叹号的作用是取反,例如:

1
cron.!info,!debug /var/log/cron

意思是除了info和debug等级的日志外,都写入到/var/log/cron中。

3.1.2Property-based 过滤器

基于属性的过滤器,使我们可以根据不同的属性值进行日志处理。配置文件中常用的属性有:msg、hostname、fromhost、programname、timegenerated等
基本语法:

:PROPERTY,[!]COMPARE_OPERATION,”VALUE”

属性过滤器可用的操作符如下:

  • contains 检查属性值是否包含指定的字符串(大小写敏感)
  • contains_i 和上面一样,但忽略大小写
  • isequal 属性值是否等于目标字符串
  • startswith 属性值是否以某字符串开头(大小写敏感)
  • startswith_i 如上,但忽略大小写
  • regex 正则表达式匹配
  • ereregex 使用扩展正则表达式匹配
  • isempty 属性值是否为空

属性过滤器例子:

1
2
3
4
#日志信息中是否包含“error”字符串
:msg, contains, "error"
#主机名称是否相等
:hostname, isequal, "host1"

3.1.3Expression-based 过滤器

基于表达式的过滤器,这个表达式是一个条件表达式,即当满足特定条件的时候,执行指定的操作。
一般来说,表达式过滤器需要结合Rsyslogd中的属性来使用。
基本语法:

1
if expression_true then action else action

else后续部分并不是必须的,它可以指定不满足条件的时候所执行的操作。
表达式中可用的操作符有:

  • and、or、not
  • ==、!=、<>、<、>、<=、>= (!=和<>的作用基本相等)
  • contains
  • startswith、startswith_i(case-insensitive)

一些例子:

1
2
3
4
5
#日志中包含error,保存到/var/log/errlog中
if $msg contains 'error' then /var/log/errlog
#如果要同时满足多个条件,使用and连接这些条件,整个表达式需要写在一行中
if $syslogfacility-text == 'local0' and $msg startswith 'DEVNAME' and ($msg contains 'error1' or $msg contains 'error0') then /var/log/somelog
if $syslogfacility-text == 'local0' and $msg startswith 'DEVNAME' and not ($msg contains 'error1' or $msg contains 'error0') then /var/log/somelog

3.1.4动作

在rsyslog的配置中,过滤器与动作都是一起配置的.rsyslog把日志过滤后分发到各个指定的action.
常见的action有:

  • 写入文件
  • 转发到另一台服务器
  • 写入数据库
  • 丢弃
  • 发送给用户

如rsyslog的默认配置:

1
2
3
4
5
6
7
8
9
10
auth,authpriv.*	/var/log/auth.log
*.*;auth,authpriv.none -/var/log/syslog
cron.* /var/log/cron.log
daemon.* -/var/log/daemon.log
kern.* -/var/log/kern.log
lpr.* -/var/log/lpr.log
mail.* -/var/log/mail.log
user.* -/var/log/user.log

*.emerg :omusrmsg:*

rsyslog会根据规则写入到各个指定的文件夹,动作前面有一个(-)横杠,表示日志不会马上写入到文件中,而是缓存到内存中,这样可以提高日志系统的性能,但有可能会造成日志的丢失,使用波浪符号(~)处理需要丢弃的日志。
而omusrmsg则会把消息转发给指定的用户,用户登录时就可以收到该消息.默认为全部用户,如果需要指定用户则如下编写:

1
*.emerg	:omusrmsg:root,so1n

3.1.5动作-传输日志

传输方式
rsyslog提供三个远程日志传输方式:

  • UDP: 数据包传输可信度不高

基于传统UDP协议进行远程日志传输,也是传统syslog使用的传输协议;
可靠性比较低,但性能损耗最少, 在网络情况比较差,
或者接收服务器压力比较高情况下,可能存在丢日志情况。
在对日志完整性要求不是很高,在可靠的局域网环境下可以使用。

  • TCP: 数据包传输可信度比较高

基于传统TCP协议明文传输,需要回传进行确认,可靠性比较高;
但在接收服务器宕机或者两者之间网络出问题的情况下,会出现丢日志情况。
这种协议相比于UDP在可靠性方面已经好很多,并且rsyslog原生支持,配置简单,
同时针对可能丢日志情况,可以进行额外配置提高可靠性,因此使用比较广。

  • RELP: 数据包传输可信度最高,避免数据丢失,比较新的协议,目前应用较少

RELP(Reliable Event Logging Protocol)是基于TCP封装的可靠日志消息传输协议;
是为了解决TCP 与 UDP 协议的缺点而在应用层实现的传输协议,也是三者之中最可靠的。
需要多安装一个包rsyslog-relp以支持该协议。

客户端配置
根据需要打开对应的传输模块

1
2
3
4
5
6
7
# provides UDP syslog reception
module(load="imudp")
input(type="imudp" port="514")

# provides TCP syslog reception
module(load="imtcp")
input(type="imtcp" port="514")

在动作那里配上如下格式

1
@[(zNUMBER)]HOST:[PORT]

其中@代表udp,可选值zNUMBER设置了是否允许使用zlib对日志压缩(压缩级别1-9)
UDP 在主机名前加”@”
TCP 在主机名前加”@@”
RELP 在主机名前加”:omrelp:”
服务端配置
UDP:在服务端创建配置文件:/etc/rsyslog.d/udp.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# server configure
$ModLoad imudp # 加载模块
$UDPServerRun 10514 # 指定监听端口
$AllowedSender UDP, 10.0.0.0/16 # 设置白名单

# 根据客户端IP存放到不同目录下,以日期命名文件
$template location,/data/%fromhost-ip%/%$YEAR%-%$MONTH%-%$DAY%.log
# 自定义日志格式
$template uformat,"%fromhost-ip% %msg%\n"

# 把非本地传输的日志按照指定的文件路径及格式保存
:fromhost-ip, !isequal, "127.0.0.1" -?location;uformat
# & 表示已经匹配处理的内容,~ 表示不再进行其他处理
& ~

TCP: 服务端配置:/etc/rsyslog.d/tcp.conf

1
2
3
4
5
6
7
8
9
10
11
12
# server configure
$ModLoad imtcp # 加载模块
$InputTCPServerRun 20514 # 指定监听端口
$AllowedSender TCP, 10.0.0.0/16 # 设置白名单
# 根据客户端IP存放到不同目录下,以日期命名文件
$template location,"/data/log/syslog/%fromhost-ip%.log"
# 自定义日志格式
$template uformat,"%timestamp% %fromhost-ip% %rawmsg%\n"
# 把非本地传输的日志按照指定的文件路径及格式保存
:fromhost-ip, !isequal, "127.0.0.1" -?location;uformat
# & 表示已经匹配处理的内容,stop 表示不再进行其他处理
& stop

RELP
需要先在客户端和服务端安装RELP

1
2
apt-get update
apt-get -y install rsyslog-relp

客户端需要额外加载模块

1
module(load="omrelp")

服务端配置(/etc/rsyslog.d/relp.conf)

1
2
3
4
5
6
7
8
9
10
11
# server configure
$ModLoad imrelp # 加载模块
$InputRELPServerRun 30514 # 指定监听端口
# 根据客户端IP存放到不同目录下,以日期命名文件
$template location,"/data/log/syslog/%fromhost-ip%.log"
# 自定义日志格式
$template uformat,"%timestamp% %fromhost-ip% %rawmsg%\n"
# 把非本地传输的日志按照指定的文件路径及格式保存
:fromhost-ip, !isequal, "127.0.0.1" -?location;uformat
# & 表示已经匹配处理的内容,stop 表示不再进行其他处理
& stop

3.1.6模板

模板 $template, 最主要的一个指令,在 接收端 可用来定义消息格式、文件名。主要是在接收端使用。
语法:

1
2
$template <name>,<内容>,<可选项>
$template MyTemplateName,"\7Text %property% some more text\n",<options>

默认消息格式

1
2
<接收内容的时间> <发送者的hostname> <$InputFileTag> <原始消息%msg%>
Dec 18 20:39:27 jumper-172-31-56-18 karltestdemoTag blala... dummy msg

如果只需要显示原始消息,可设置

1
$template CleanMsgFormat,"%msg%\n"

模板支持一些变量,常见变量如下(官网文档):

1
2
3
4
5
6
7
8
%msg%
%syslogfacility%
%HOSTNAME%
%syslogpriority%
%timereported:::date-mysql%
%timegenerated:::date-mysql%
%iut%
'%syslogtag%'

如果要生成动态文件名,并把日志写入该文件,那可以这样配置:

1
2
$template DynamicFile,"/var/log/test_logs/%timegenerated%-test.log"    # timegenerated属性从日志信息中提取出消息的时间戳,这样可以为每个日志生成唯一文件名称。
*.* ?DynamicFile

3.1.7常用模块

imfile模块
imfile模块主要解决的问题是将非syslog日志转发到远程服务端
如日志:/var/log/helloworld.log

1
2
3
4
5
6
7
# 加载imfile这个模块
module(load="imfile" mode="inotify" PollingInterval="1")
# 指定日志文件路径以及tag, severity, facility这些参数
input(type="imfile" File="/var/log/helloworld.log" Tag="helloworld" Severity="error" Facility="local0")
# 由于local有限,一般可以专门预留一个local用来接受带有Tag的日志,解决local不足的问题
# 将helloworld的应用日志发送到远程服务器
:programname, contains, "helloworld" @192.168.1.2

其他imfile配置如下,如果使用input,input的参数基本是以下配置的名称去掉input前缀:
更多配置见官网

1
2
3
4
5
6
7
8
9
10
11
12
$InputFileName /path/to/file # 待监控的文件路径
$InputFileTag tag # 文件唯一标识tag,最好保持唯一,用于接收端区分原始log文件,可以包含特殊字符,如":"、","等
$InputFileStateFile /path/to/state/file
# 需要保证发送端唯一,记录读取到哪儿,状态文件保存在$WorkDirectory,默认为 /var/lib/rsyslog
# 如果某个要监控的文件名变化了,一定要重新设置该值
$InputFileFacility facility # log类型,默认local0, local开头的表示自定义类型
$InputFileSeverity severity # log级别:info,warning,默认notice
$InputRunFileMonitor # 启动监控当前的文件,如果忘记这行,则啥事也不会发生
$InputFilePollInterval seconds # 全局设置,默认轮询是10s
$InputFilePersistStateInterval lines # 每多少行更新state文件状态
$InputFileMaxLinesAtOnce number # 默认10240,如果在发送端,需要同时监控多个文件,会处理完当前文件特定行后,切换到下一个文件,避免一个文件一直占用处理,导致收集别的文件不及时。
$InputFileBindRuleset ruleset # 绑定ruleset,可以把这个listener绑定到特点的规则(http://www.rsyslog.com/doc/v5-stable/concepts/multi_ruleset.html)

在input的语法中stateFile参数已经不建议使用。原因在于,为了防止出现重复的state files,rsyslog会基于下面的规则自动生成这些文件:

  • 在具体的被监控文件前添加”imfile-state:”字符串
  • 文件名前的反斜杠会被替换为短横杠。
    尽量在文件刚生成时初始化日志,或者使用freshStartTail参数,然rsyslog并不建议使用该参数…

omprog模块
omprog模块可以让日志通过管道的形式发送给程序(以每行日志分开发送),然后再由程序处理日志,以下是官网的一个例子:
日志被发送到Python程序的stdin,python程序将它们写入数据库.
执行配置的程序,并通过stdin将日志消息馈送到该二进制文件。二进制文件可以随意处理提供的数据。如果程序终止,则重新启动。如果rsyslog终止,则程序的stdin将看到EOF。然后该程序必须终止。
该模块会执行Python程序,并通过stdin的形式发送到Python,Python会一直运行,等待数据的到来,如果收到数据则处理数据(这个例子是写入数据库), 如果程序终止,则重新启动,如果rsyslo终止,则程序的stdin会捕获到EOF,此时程序会终止.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 配置
module(load="omprog")

action(type="omprog"
name="db_forward"
binary="/usr/share/logging/db_forward.py"
confirmMessages="on" # 它告诉rsyslog等待程序确认其初始化以及收到的每条消息。该设置的目的是防止由于数据库连接失败而导致日志丢失。如果程序无法将日志写入数据库,它将通过stdout向rsyslog返回否定确认
confirmTimeout="30000" # 指定超时时间内未收到程序的响应,则rsyslog将终止并重新启动它
queue.type="LinkedList"
queue.saveOnShutdown="on"
queue.workerThreads="5" # 使用具有(最多)5个工作线程的专用磁盘辅助队列,以避免在高负载时影响其他日志目标
action.resumeInterval="5" # Rsyslog将失败的日志保留在队列中,并在5秒后再次将其发送给程序。
killUnresponsive="on"
output="/var/log/db_forward.log" # 程序将错误详细信息写入stderr,rsyslog捕获并写入/var/log/db_forward.log
)

除了使用模块接收日志,还可以用程序读取日志(建议用上inotify),或者开个端口接收日志

3.1.8RainerScript

RainerScript是一个比较新的配置语言,RainerScript具有更紧凑的语法,使配置过程更加清晰,更不容易出错。

  • 加载模块

    1
    2
    3
    4
    # 旧语法
    $ModLoad imtcp
    # 新语法
    module(load="imtcp")
  • input
    上面已经有使用imfile的例子了,这里就不多阐述

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 旧语法
    $ModLoad imfile #导入模块
    $InputFileName /var/log/nginx/access.log #需要导入的文件
    $InputFileTag ng-acc #添加标签名称
    $InputFilePersistStateInterval 10 #多久处理一次追踪文件
    $InputFileStateFile state-ng-acc
    $InputRunFileMonitor #开始监控文件
    # 新语法
    module(load="builtin:imfile")
    input(Type="imfile" File="/var/log/nginx/access.log" Tag="ng-acc"PersistStateInterval=10)
  • action
    action是输出模块,包括了结构图里的action和队列

    1
    2
    3
    4
    5
    6
    7
    8
    # 旧语法
    *.* /var/log/messages
    # 新语法
    *.* action(Type="omfile" File="/var/log/messages")
    # 包含队列的新语法
    action(type="ommysql" server="localhost" db="Syslog" uid="root" pwd="password"\
    queue.type="LinkedList" queue.filename="name" queue.saveonshutdown="on"\
    action.resumeRetryCount="-1"
  • template
    新的template对象提供了两种常用的模板定义方式,一种是string,另一种是list。string方式比较接近旧template的定义方式,而list方式可以更清晰的区分字符串和属性值。不过我比较喜欢的是string方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # 旧语法
    $template remote, "message from %hostname%, received at %timegenerated%."
    # 新语法string
    template(namme="remote" type="string" string="message from %hostname%, received at %timegenerated%.")
    # 新语法list
    # constant用于定义字面字符串值,而property用于定义实际的属性
    template(name="dbFormat" type="list" option.sql="on") {
    constant(value="insert into SystemEvents (Message, FromHost,ReceivedAt)")
    constant(value=" values ('")
    property(name="msg")
    constant(value=", '")
    property(name="hostname")
    constant(value="', '")
    property(name="timegenerated" dateFormat="mysql")
    constant(value="')")
    }
  • ruleset
    ruleset推荐用新的语法,比原来的清晰了很多

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 旧语法
    $Ruleset remote
    mail.none /var/log/mail.log
    cron.none /var/log/cron.log

    $ModLoad imtcp
    $InputTCPBindRuleset remote
    $InputTCPServerRun 514
    # 新语法
    ruleset(name="remote-514") {
    cron.none action(type="omfile" file="/var/log/remote-514-cron")
    mail.none action(type="omfile" file="/var/log/remote-514-mail")
    }

    input(type="imtcp" port="514" ruleset="remote-514");

    3.2 各个日志文件简介

  • /var/log/secure:记录用户登陆系统的信息,比如SSH,telnet,ftp等记录

  • /var/log/btmp:记录登陆失败的信息,被编码过,所以必须使用last解析

  • /var/log/messages:在开机运行中几乎所有的系统发生的错误都在此记录。

  • /var/log/boot.log:记录一些开机或者关机启动的一些服务信息

  • /var/log/cron:用来记录crontab这个服务执行任务计划产生的日志

  • /var/log/utmp:记录现在登陆的用户

  • /var/log/dmesg:内核日志

  • /var/log/kern:内核产生的信息

  • /var/log/daemon.log:系统监控程序产生的日志。

3.3队列

rsyslog是我们在使用中最无感,通常也是最重要的,因为队列可以加速日志的传输,还会让传输更加可靠,内容大多数来源于官方文档

3.3.1主队列

一般日志进来到rsyslog时,都会先进入主队列,然后根据配置消费日志分发到各个队列以及执行动作,一般主队列的鲁棒性很强,我们一般都不会去修改他,而是去修改动作队列
使用下面命令可以告诉主消息队列在关闭时保存其内容

1
$MainMsgQueueSaveOnShutdown on

3.3.2动作队列

动作队列用于接受主队列的消息,并根据规则执行动作,一般有以下4种:

  • Direct queue
    该队列是默认队列,如果对action没进行配置,则默认采用该队列,该队列既不排队也不缓冲任何队列消息,直接消息传给消费者.同时,该队列是唯一一个会把执行结果从消费者(action processor)返回给生产者的队列。action processor,通过这个返回值提醒action queue,让action queue取回这些处理失败的消息,如此循环,直到消息处理成功。

  • Disk queue
    该队列使用硬盘进行缓冲,而不在内存中缓冲任何内容。因此该队列是超级可靠的,但到也是最慢的队列。正常情况下,不建议使用此队列模式。如果日志数据非常重要,为了确保在极端情况下也不能丢失,可以使用该队列。
    写入该队列时,它是分块完成的。每个块接收其各自的文件。文件以前缀命名(通过$<object>QueueFilename设置),后跟7位数字(从1开始,每个文件递增)。默认情况下,块为10mb,可通过$<object>QueueMaxFileSize设置不同的大小。不过,大小限制不是一个很严格的限制,因为rsyslog总是写一个完整的队列条目,即使它会比大小限制还大。因此,块实际上比配置的大小大一点(通常小于1k)。所以,每个块的大小都会不一样。
    每一个队列可以使用不同的位置保存数据,通过$WorkDirectory指令设置,这个指令要在队列创建之前配置。

  • memory queue (LinkedList/FixedArray)
    这种类型的队列把所有的消息都保存在内存中,因此它的处理速度非常快,缺点是当电脑关闭或死机的时候,所有未被处理的消息都会丢失。如果希望电脑关机的时候保存这些消息,可以设置$<Object>QueueSaveOnShutdown
    memory queue带有两种模式,如果不知道用哪个模式,建议使用LinkedList模式。因为它与FixedArray相比,处理开销较低,并且可以通过减少内存使用量来弥补。在大多数不使用的指针数组页面中分页可能比动态分配它们慢得多。
    分别使用$<object>QueueType LinkedList or /$<object>QueueType FixedArray创建 LinkedLIst和FixesArray队列

    • FixedArray queue 预先分配一定的内存来保存这些消息,它的缺点是,无论你的日志有多少,它都需要完全占用这些内存;好处是当数据量不大的时候,它的性能是最好的。
    • LinkedList queue 内存是运行时分配的,会根据数据量的不同而作出调整,好处是内存利用率高,LinkedList队列适合使用在一些突发数据量大的场景。
  • Disk-Assisted In-memory queue
    这种队列实际上是以内存队列为主,Disk Queue为辅的队列。在正常情况下,不会使用辅助的Disk queue,但当内存队列被填满,或者主机关闭的时候,Disk Queue就会被激活,数据被写入硬盘。结合两者使用,可以同时满足速度和数据的可靠性。
    设置队列的语法如下:

    1
    2
    3
    4
    5
    6
    $ActionQueueType LinkedList
    $ActionQueueFileName fileName

    #还有另外两个参数设置
    $<Object>QueueHighWatermark #当队列中的数据超过这个设置的值的时候,要么把数据保存,要么把数据丢弃,如果是Disk-Assisted In-memory Queue,队列中的数据超过这个值,Disk Queue就会被激活。
    $<Object>QueueLowWatermark #和上面的相反,这是一个低水位设置,当数据小于这个值的时候,就停止相关的操作,如果是Disk-Assisted In-memory Queue,数据低于这个值,Disk Queue就会被取消激活状态。

    3.3.3队列管理

    队列的管理过程实际上是对队列的参数进行调优的过程。main message queue的参数和action queue的参数基本一样。这些参数必须在队列创建之后才能使用,每个不同的队列可以设置不同的数值,这些值在下一个队列创建之前被重置,前一个队列设置的值不会影响到下一个队列。

  • 限制队列容量

    • $<Object>QueueSize <number>
    • $<Object>QueueHighWaterMark <number>
      两者之间有细微的差别 $<Object>QueueSize用于设置队列的总容量,即队列可容纳的消息数量。
      $<Object>QueueHighWaterMark只用于disk-assisted类型的队列,当队列中的消息数量达到这个值之后,消息就会被写入到硬盘。但是这种行为是有依赖性的,仅当日志的输出目标无法到达的时候(数据库无法访问,远程服务器离线等),它才会发生。
  • 丢弃消息

    • $<Object>QueueDiscardMark 设置队列的最高值,当队列中的消息达到这个指定的值时,消息就会被丢弃
    • $<Object>QueueDiscardSeverity 设定要丢弃哪些日志消息(见rsyslog的 Priority)
  • 队列的终止
    只有在系统被关闭的那一刻,队列才会被结束。当队列被终止的时候,队列中可能有数据尝试进入,rsyslog会试图处理这些数据,可以使用配置控制rsyslog的做法.

    • $<Object>QueueTimeoutShutdown <milliseconds> 队列会仍然去处理这些数据,当队列关闭时间超过这个值,队列中的所有数据被丢弃
    • $<Object>QueueTimeoutActionCompletion 只处理当前被处理的消息,其他的消息全部被抛弃
    • $<Object>QueueSaveOnShutdown 不丢弃任何消息且队列是Disk-Queue或者Disk-assisted-Queue

3.4Ruleset

Ruleset就是多个规则的集合,rsyslogd从ruleset的第一条规则开始处理,直到这个ruleset的最后一条规则。rsyslogd有一个默认的Ruleset,名为RSYSLOG_DefaultRuleset。
一个例子:

1
2
3
4
5
$template Centos7Server,"/var/log/%hostname%/messages-%$now%.log"
$RuleSet remote
*.* ?Centos7Server

$RuleSet RSYSLOG_DefaultRuleset

这个例子先创建了一个名叫remote的Ruleset,规则中使用了一个预先定义的模板。最后切换回默认的Ruleset,不切换回去的话,后面的配置就还是remote Ruleset
多个Ruleset的使用场景在于区分本地写日志和网络传日志.
本地通过$DefaultRuleset命令指定Ruleset,而网络日志绑定可以如下:

1
2
3
$ModLoad imtcp
$InputTCPServerBindRuleset remote #绑定自定以的Ruleset
$InputTCPServerRun 514

这时走TCP的日志就会使用remote Rules,如果是正常启用TCP传输日志,那么会走DefaultRuleset指定的ruleset,因为没有使用InputTCPServerBindRuleset去覆盖Ruleset.
如果有多个端口传输日志,每个端口的ruleset不同,那可以利用InputTCPServerBindRuleset 的覆盖性进行如下配置:

1
2
3
4
5
6
7
8
$InputTCPServerBindRuleset remote10001
$InputTCPServerRun 10001

$InputTCPServerBindRuleset remote10002
$InputTCPServerRun 10002

$InputTCPServerBindRuleset remote10003
$InputTCPServerRun 10003

4.日志轮转

在查看日志时我们很容易就发现出现syslog syslog.1 syslog.2.gz等类型的日志,这些日志都是考logrotate进行日志轮转的,方便我们对日志进行查找和管理
Logrotate是基于CRON来运行的,其脚本是/etc/cron.daily/logrotate,日志轮转是系统自动完成的。
使用logrotate不止是针对系统日志,还可以使一些应用本身不带日志轮转功能,或者本身日志轮换功能残缺的应用(对就是说Supervisor)拥有完善,高自定义的日志轮转功能.
实际运行时,Logrotate会调用配置文件/etc/logrotate.conf。
可以在/etc/logrotate.d目录里放置自定义好的配置文件,用来覆盖Logrotate的缺省值。
我们也可以手动执行日志轮转,不过要记得添加-f参数,表示强制轮转,手动运行最好添加-d参数 测试配置文件是否有错误,常用参数如下:

1
2
3
4
5
6
logrotate [OPTION...] <configfile>
-d, --debug :debug模式,测试配置文件是否有错误。
-f, --force :强制转储文件。
-m, --mail=command :压缩日志后,发送日志到指定邮箱。
-s, --state=statefile :使用指定的状态文件。
-v, --verbose :显示转储过程。

logrotate的原理是检查日志是否需要轮转,在轮转后对进程进行重启(一般是发送信号量),确保进程能写入到新的文件,
一般来说,我们只要在/etc/logrotate.d/目录下配置针对某个日志的日志文件轮转配置就可以了,配置主要是声明要轮换的日志文件路径以及花括号内配置轮转属性,以nginx为例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/usr/local/nginx/logs/*log {
daily
# 每天转储
rotate 30
# 保存30个备份
missingok
# 在日志转储期间,任何错误将被忽略
notifempty
# 文件为空时不转储
compress
# 通过 gzip 压缩
dateext
# 日志文件以当前日期为格式结尾
sharedscripts
# 所有日志文件转储完毕后执行一次脚本
postrotate
# 转储之后执行命令,和endscript成对使用
/bin/kill -USR1 \$(cat /usr/local/nginx/logs/nginx.pid 2>/dev/null) 2>/dev/null || :
endscript
# 转储之后执行命令,和postrotate成对使用
}

rsyslog控制的日志比较多,可以像以下这样配置,多个日志文件多行显示,并同样的用花括号把配置包起来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/var/log/mail
/var/log/messages
/var/log/syslog
{
sharedscripts
dateext
rotate 25
size 40M
compress
dateformat -%Y%m%d%s
postrotate
/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
endscript
}

4.1logrotate参数

logrotate的主要使用也是以配置为主,没啥好说的,需要注意一些配置,多打日志,不然logrotate会以文件太小或者时间间隔比较低(如配置1天轮转一次,logrotate首次轮转可能要间隔两天)而不进行轮转
| 参数 | 描述 |
| ———————– | ———————————————————— |
|dateext | 切换后的日志文件会附加上一个短横线和YYYYMMDD格式的日期,没有这个配置项会附加一个小数点加一个数字序号.|
|dateformat | 配合dateext使用可以为切割后的日志加上YYYYMMDD格式的日期,如dateformat -%Y%m%d|
| compress | 通过gzip 压缩转储以后的日志 |
| nocompress | 不需要压缩时,用这个参数 |
| copytruncate | 用于还在打开中的日志文件,把当前日志备份并截断 |
| nocopytruncate | 备份日志文件但是不截断 |
| create mode owner group | 转储文件,使用指定的文件模式创建新的日志文件 |
| nocreate | 不建立新的日志文件 |
| delaycompress | 一起使用时,转储的日志文件到下一次转储时才压缩 |
| nodelaycompress | 覆盖 delaycompress 选项,转储同时压缩。 |
| errors address | 专储时的错误信息发送到指定的Email 地址 |
| ifempty | 即使是空文件也转储,这个是 logrotate 的缺省选项。 |
| notifempty | 如果是空文件的话,不转储 |
| mail address | 把转储的日志文件发送到指定的E-mail 地址 |
| nomail | 转储时不发送日志文件 |
| olddir directory | 转储后的日志文件放入指定的目录,必须和当前日志文件在同一个文件系统 |
| noolddir | 转储后的日志文件和当前日志文件放在同一个目录下 |
|sharedscripts | 运行postrotate脚本,作用是在所有日志都轮转后统一执行一次脚本。如果没有配置这个,那么每个日志轮转后都会执行一次脚本 |
| prerotate/endscript | 在转储以前需要执行的命令可以放入这个对,这两个关键字必须单独成行 |
| postrotate/endscript | 在转储以后需要执行的命令可以放入这个对,这两个关键字必须单独成行 |
| daily | 指定转储周期为每天 |
| weekly | 指定转储周期为每周 |
| monthly | 指定转储周期为每月 |
| rotate count | 指定日志文件删除之前转储的次数,0 指没有备份,5 指保留5 个备份 |
| tabootext [+] list | 让logrotate 不转储指定扩展名的文件,缺省的扩展名是:.rpm-orig, .rpmsave, v, 和 ~ |
| size size | 当日志文件到达指定的大小时才转储,后缀MB. |

5.一些常见坑

  • log太长了,被截断
    被$MaxMessageSize限制的,它的默认大小是2k,大概可以保存1000个中文字符,在加载imtcp/imudp之前设置, 此配置包括发送和接收,所以rsyslog客户端、服务端都要设置
  • 一行日志消息大小大于4K,只能用TCP。这是因为UDP栈大小限制的。
  • 某个系统日志文件过大
    像用debian的话,可以看到/var/log/syslog会随着你的配置,里面的东西越来越多,主要要对该行默认配置进行修改,不然所有日志都会发送到这里了(以定义了local5,6为例子)
    1
    2
    *.info;mail.none;authpriv.none;cron.none /var/log/syslog
    *.info;mail.none;authpriv.none;cron.none;local5.none;local6.none /var/log/messages
  • 接收端保存的文件路径不对
    如果两个tag有共同的前缀,需要把长的放在前面,调整好顺序
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # For erp_wms
    $template erp_wms_FileFormat,"/Data/logs/erp/wms/%fromhost-ip%/%syslogtag:F,44:2%-%$YEAR%%$MONTH%%$DAY%.log"
    if $syslogtag startswith 'erp_wms' then ?erp_wms_FileFormat;CleanMsgFormat
    & ~

    # For erp_wms3
    $template erp_wms3_FileFormat,"/Data/logs/erp/wms3/%fromhost-ip%/%syslogtag:F,44:2%-%$YEAR%%$MONTH%%$DAY%.log"
    if $syslogtag startswith 'erp_wms3' then ?erp_wms3_FileFormat;CleanMsgFormat
    & ~
    修改后
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 这里注意下面的tag的顺序, 一定要让长的tag(erp_wms3)保持在上面,因为他们有共同的前缀(erp_wms)
    # For erp_wms3
    $template erp_wms3_FileFormat,"/Data/logs/erp/wms3/%fromhost-ip%/%syslogtag:F,44:2%-%$YEAR%%$MONTH%%$DAY%.log"
    if $syslogtag startswith 'erp_wms3' then ?erp_wms3_FileFormat;CleanMsgFormat
    & ~

    # For erp_wms
    $template erp_wms_FileFormat,"/Data/logs/erp/wms/%fromhost-ip%/%syslogtag:F,44:2%-%$YEAR%%$MONTH%%$DAY%.log"
    if $syslogtag startswith 'erp_wms' then ?erp_wms_FileFormat;CleanMsgFormat
    & ~
  • 接收端 rsyslog 文件名太长后被截断
    由于发送端默认配置
    1
    2
    template (name="ForwardFormat" type="string" string="<%PRI%>%TIMESTAMP:::date-rfc3339% %HOSTNAME%
    %syslogtag:1:32%%msg:::sp-if-no-1st-sp%%msg%")
    中的 %syslogtag:1:32%限制了文件名长度,所以需要发送端重新绑定到一个新的模板

    6.常见rsyslog不记日志问题

  • 1.OOM kernel不能及时释放cache满足应用程序的突发内存需求的情况
  • 2.系统内存严重不够或者Rsyslog限制了它将在内存中保留的消息数量.如果该消息大于系统中的内存,则需要调整它。要么给机器更多内存,要么将rsyslog配置为更小的队列大小。
  • 3.回车控制符(来源于网络,没遇到过)
    有可能是由于某用户的debug或者info log中,包含了回车控制符\n,而我们rsyslog client段的配置文件中EscapeControlCharactersOnReceive是off的,即不对控制符做转义,所以含有\n控制符的log被发送给了rsyslog center。而rsyslog center是根据回车控制符\n来判断是不是一条log的。如果用户的log中包含类似字段:GET /123/id=123&\n90887294–sdf,那么rsyslog会把”GET /123/id=123&“当作一条log,而把90887294作为下一条message的长度,并且会有刚才的Framing Error的报错。rsyslog会等待接收90887294byte的数据,然后判断大于了MaxMessageSize 4KB,然后rsyslog就只保存了从90887294开始之后的4KB日志,剩下的90887294 - 4*1024= 90883198byte的数据全被截断丢弃。这就有了received oversize message的报错。
    解决办法:
    1
    2
    3
    4
    5
    issues:https://github.com/rsyslog/rsyslog/issues/111
    1,开启rsyslog client的EscapeControlCharactersOnReceive为on状态。对回车控制符进行转义,即可避免此问题
    影响:把用户log中的\n转换成了以#开头的三位八进制数#012。(根基ascii表转换)
    2,关闭rsyslog center的SupportOctetCountedFraming为off状态。即不支持Octet数据流。
    影响:当用户log中有\n的时候,log会被截断。
  • 4.rsyslog 性能跟不上导致丢日志,需要进行调优如对rsyslog的main queue和action queue进行调优

    7.附录A:用python发送日志到syslog

    python的logging模块也兼容Linux的日志机制只需要对logger更改就可以把日志发向/dev/log/从而被rsyslog捕获到日志
    示例代码
    1
    2
    3
    4
    5
    logger = logging.getLogger('exp')
    logger.setLevel(logging.INFO)
    filehandler = logging.FileHandler(os.environ['HOME'] + '/exp.log', encoding='utf8')
    filehandler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
    logger.addHandler(filehandler)
    改为下面代码即可
    1
    2
    3
    4
    5
    logger = logging.getLogger('exp')
    logger.setLevel(logging.INFO)
    sys_handler = logging.handlers.SysLogHandler('/dev/log', facility=logging.handlers.SysLogHandler.LOG_LOCAL0)
    sys_handler.setFormatter(logging.Formatter('exp_log' + ":%(asctime)s - %(name)s - %(levelname)s - %(message)s"))
    logger.addHandler(sys_handler)
    另外,如果你想用python读日志的话也可以直接监听/dev/log/再打印日志
    1
    2
    3
    4
    5
    6
    7
    8
    import socket
    import time
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
    sock.bind('/dev/log') #需要先手动kill掉已经在运行的[r]syslogd进程,否则这里无法执行成功
    while True:
    time.sleep(5)
    data, addr = sock.recvfrom(1024)
    print(data)
查看评论