syslog协议
进行封装, 比如用户指定的日志等级, 系统log渠道等等, 然后把封装好的数据发送到指定socket –
/dev/log
。
/dev/log
是一个UNIX域套接字,它负责接受在本地机器上运行的进程所产生的消息。
除此之外还有一个与它十分相似的
/dev/klog
,
/dev/klog
是一个从UNIX内核接受消息的设备的socket, 如果看到syslog记录了kern的日志,却没记录普通日志,那就是
/dev/log
这个socket缓冲区满了, 而
/dev/klog
缓存区还有空间, 还可以正常运行, 这时候可以尝试通过kern.ipc.maxsockbuf改变缓冲区大小,但并不能完全解决问题。
第二步是由系统的
journald
开始服务, 在我的系统中,由于使用了
Systemd
, 它的附属套件
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
.
第三步是
rsyslog
服务了, 在rsyslog服务启动后(以监控本地日志为例子,也就是加载module(load=”imuxsock”)) 从
/run/systemd/journal/syslog
这个socket消费syslog类型日志, 这些日志在经过预处理后会进入到主队列, 然后根据对应规则被分发, 由于
rsyslog
采用C/S结构,它可以将日志的信息追加到对应的日志文件中,一般在
/var/log
目录下(可以通过配置进行更改)。还可以把日志数据通过网络协议发送到另一台Linux服务器上,或者将日志存储在MySQL或Oracle等数据库中。
除此之外,
rsyslog
能够快速的过滤,转发,发送日志(官方说的每秒支持百万级日志),所以rsyslog的内容非常丰富。
rsyslog
为了能让我们方便的使用这些功能, 提供了多个版本的配置语言, 我们只要通过对配置文件进行简单的修改,就能实现传输,过滤等功能。
如上面的结构图,rsyslog中只有一个主消息队列,任何消息都要先进入这个队列,然后直到进入到动作队列之后消息才会从这个队列中删除。通常,我们都不会去动主队列的配置,因为默认的设置已经工作得很好;消息经过主消息队列之后,就被rule processor解析和处理,然后根据预先配置的规则压入各自的动作队列,动作队列的消息最终被消费掉, 而我们经常要配置的就是这一部分。
可以发现, 上面这三步就是一个简单的消息队列, 应用程序通过syslog把日志输出到一个指定的log, 这是一个生产的步骤,
systemd-journald
则是以
FIFO
的形式暂存日志数据, 最后被
rsyslog
以消费者的形式进行消费。而
rsyslog
的内部则更像一个高级版本的消费队列, 一个简易版本的
RabbitMQ
。
更多变量见官网文档
):
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" *.* ?DynamicFile
|
官网
1 2 3 4 5 6 7 8 9 10 11 12
|
$InputFileName /path/to/file $InputFileTag tag $InputFileStateFile /path/to/state/file
$InputFileFacility facility $InputFileSeverity severity $InputRunFileMonitor $InputFilePollInterval seconds $InputFilePersistStateInterval lines $InputFileMaxLinesAtOnce number $InputFileBindRuleset ruleset
|
在input的语法中stateFile参数已经不建议使用。原因在于,为了防止出现重复的state files,rsyslog会基于下面的规则自动生成这些文件:
在具体的被监控文件前添加”imfile-state:”字符串
文件名前的反斜杠会被替换为短横杠。
尽量在文件刚生成时初始化日志,或者使用freshStartTail参数,然rsyslog并不建议使用该参数…
omprog模块
omprog模块可以让日志通过管道的形式发送给程序(以每行日志分开发送),然后再由程序处理日志(类似于Map-Reduce)。
以下是官网的一个例子, 例子中该模块会根据配置执行Python程序,并通过stdin的形式发送到Python程序,Python程序会一直运行,等待数据的到来,如果收到数据则处理数据(这个例子是写入数据库), 如果程序终止,则重新启动,如果rsyslo终止,则程序的stdin会捕获到EOF,此时程序会终止.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
module(load="omprog")
action(type="omprog" name="db_forward" binary="/usr/share/logging/db_forward.py" confirmMessages="on" confirmTimeout="30000" queue.type="LinkedList" queue.saveOnShutdown="on" queue.workerThreads="5" action.resumeInterval="5" killUnresponsive="on" output="/var/log/db_forward.log" )
|
除了使用模块接收日志,还可以用程序读取日志(建议用上inotify),或者开个端口接收日志