syslog详解

syslog 详解

一、syslog协议介绍

1、介绍

在Unix类操作系统上,syslog广泛应用于系统日志。syslog日志消息既可以记录在本地文件中,也可以通过网络发送到接收syslog的服务器。接收syslog的服务器可以对多个设备的syslog消息进行统一的存储,或者解析其中的内容做相应的处理。常见的应用场景是网络管理工具、安全管理系统、日志审计系统。
完整的syslog日志中包含产生日志的程序模块(Facility)、严重性(Severity或 Level)、时间、主机名或IP、进程名、进程ID和正文。在Unix类操作系统上,能够按Facility和Severity的组合来决定什么样的日志消息是否需要记录,记录到什么地方,是否需要发送到一个接收syslog的服务器等。由于syslog简单而灵活的特性,syslog不再仅限于 Unix类主机的日志记录,任何需要记录和发送日志的场景,都可能会使用syslog。
长期以来,没有一个标准来规范syslog的格式,导致syslog的格式是非常随意的。最坏的情况下,根本就没有任何格式,导致程序不能对syslog 消息进行解析,只能将它看作是一个字符串。

在2001年定义的RFC3164中,描述了BSD syslog协议:
http://www.ietf.org/rfc/rfc3164.txt
不过这个规范的很多内容都不是强制性的,常常是“建议”或者“约定”,也由于这个规范出的比较晚,很多设备并不遵守或不完全遵守这个规范。接下来就介绍一下这个规范。
约定发送syslog的设备为Device,转发syslog的设备为Relay,接收syslog的设备为Collector。Relay本身也可以发送自身的syslog给Collector,这个时候它表现为一个Device。Relay也可以只转发部分接收到的syslog消息,这个时候它同时表现为Relay和Collector。
syslog消息发送到Collector的UDP 514端口,不需要接收方应答,RFC3164建议 Device 也使用514作为源端口。规定syslog消息的UDP报文不能超过1024字节,并且全部由可打印的字符组成。完整的syslog消息由3部分组成,分别是PRI、HEADER和MSG。大部分syslog都包含PRI和MSG部分,而HEADER可能没有。

2、syslog的格式

下面是一个syslog消息:

<30>Oct 9 22:33:20 hlfedora auditd[1787]: The audit daemon is exiting.

其中“<30>”是PRI部分,“Oct 9 22:33:20 hlfedora”是HEADER部分,“auditd[1787]: The audit daemon is exiting.”是MSG部分。

2.1、PRI部分

PRI部分由尖括号包含的一个数字构成,这个数字包含了程序模块(Facility)、严重性(Severity),这个数字是由Facility乘以 8,然后加上Severity得来。不知道他们为什么发明了这么一种不直观的表示方式。
也就是说这个数字如果换成2进制的话,低位的3个bit表示Severity,剩下的高位的部分右移3位,就是表示Facility的值。
十进制30 = 二进制0001 1110
0001 1… = Facility: DAEMON – system daemons (3)
…. .110 = Severity: INFO – informational (6)
Facility的定义如下,可以看出来syslog的Facility是早期为Unix操作系统定义的,不过它预留了User(1),Local0~7 (16~23)给其他程序使用:

      Numerical             Facility
         Code
          0             kernel messages
          1             user-level messages
          2             mail system
          3             system daemons
          4             security/authorization messages (note 1)
          5             messages generated internally by syslogd
          6             line printer subsystem
          7             network news subsystem
          8             UUCP subsystem
          9             clock daemon (note 2)
         10             security/authorization messages (note 1)
         11             FTP daemon
         12             NTP subsystem
         13             log audit (note 1)
         14             log alert (note 1)
         15             clock daemon (note 2)
         16             local use 0  (local0)
         17             local use 1  (local1)
         18             local use 2  (local2)
         19             local use 3  (local3)
         20             local use 4  (local4)
         21             local use 5  (local5)
         22             local use 6  (local6)
         23             local use 7  (local7)
       Note 1 - Various operating systems have been found to utilize
          Facilities 4, 10, 13 and 14 for security/authorization,
          audit, and alert messages which seem to be similar.
       Note 2 - Various operating systems have been found to utilize
          both Facilities 9 and 15 for clock (cron/at) messages.

Severity的定义如下:

       Numerical         Severity
        Code
         0       Emergency: system is unusable
         1       Alert: action must be taken immediately
         2       Critical: critical conditions
         3       Error: error conditions
         4       Warning: warning conditions
         5       Notice: normal but significant condition
         6       Informational: informational messages
         7       Debug: debug-level messages

也就是说,尖括号中有1~3个数字字符,只有当数字是0的时候,数字才以0开头,也就是说00和01这样在前面补0是不允许的。

2.2、HEADER部分

HEADER部分包括两个字段,时间和主机名(或IP)。
时间紧跟在PRI后面,中间没有空格,格式必须是“Mmm dd hh:mm:ss”,不包括年份。“日”的数字如果是1~9,前面会补一个空格(也就是月份后面有两个空格),而“小时”、“分”、“秒”则在前面补“0”。月份取值包括:

Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec

时间后边跟一个空格,然后是主机名或者IP地址,主机名不得包括域名部分。
因为有些系统需要将日志长期归档,而时间字段又不包括年份,所以一些不标准的syslog格式中包含了年份,例如:

<165>Aug 24 05:34:00 CST 1987 mymachine myproc[10]: %% It's
time to make the do-nuts. %% Ingredients: Mix=OK, Jelly=OK #
Devices: Mixer=OK, Jelly_Injector=OK, Frier=OK # Transport:
Conveyer1=OK, Conveyer2=OK # %%

这样会导致解析程序将“CST”当作主机名,而“1987”开始的部分作为MSG部分。解析程序面对这种问题,可能要做很多容错处理,或者定制能解析多种syslog格式,而不仅仅是只能解析标准格式。
HEADER部分后面跟一个空格,然后是MSG部分。
有些syslog中没有HEADER部分。这个时候MSG部分紧跟在PRI后面,中间没有空格。

2.3、MSG部分

MSG部分又分为两个部分,TAG和Content。其中TAG部分是可选的。
在前面的例子中(“<30>Oct 9 22:33:20 hlfedora auditd[1787]: The audit daemon is exiting.”),“auditd[1787]”是TAG部分,包含了进程名称和进程PID。PID可以没有,这个时候中括号也是没有的。
进程PID有时甚至不是一个数字,例如“root-1787”,解析程序要做好容错准备。
TAG后面用一个冒号隔开Content部分,这部分的内容是应用程序自定义的。

二、syslog函数

Linux C中提供一套系统日记写入接口,包括三个函数:openlog,syslog和closelog。
调用openlog是可选择的。如果不调用openlog,则在第一次调用syslog时,自动调用openlog。调用closelog也是可选择的,它只是关闭被用于与syslog守护进程通信的描述符。

#include<syslog.h> 
void openlog (char*ident, int option, int facility); 
void closelog(); 
void syslog(int priority, char*format,……);

priority参数的格式(severity level|facility code)
示例:

LOG_ERR|LOG_USER

severity level:
Priority Level               Description
LOG_EMERG                    An emergency situation
LOG_ALERT                    High-priority problem, such as database corruption
LOG_CRIT                     Critical error, such as hardware failure
LOG_ERR                      Errors
LOG_WARNING                  Warning
LOG_NOTICE                   Special conditions requiring attention
LOG_INFO                     Informational messages
LOG_DEBUG                    Debug messages 

facility value(转自syslog.h头文件):

#define LOG_KERN        (0<<3)  
#define LOG_USER        (1<<3)  
#define LOG_MAIL        (2<<3)  
#define LOG_DAEMON      (3<<3)  
#define LOG_AUTH        (4<<3)  
#define LOG_SYSLOG      (5<<3)  
#define LOG_LPR         (6<<3)  
#define LOG_NEWS        (7<<3)  
#define LOG_UUCP        (8<<3)  
#define LOG_CRON        (9<<3)  
#define LOG_AUTHPRIV    (10<<3)
#define LOG_FTP         (11<<3)


<br />    #include <syslog.h>   
    int main(int argc, char *argv[])   
    {   
        openlog("testsyslog", LOG_CONS | LOG_PID, 0);   
        syslog(LOG_USER | LOG_INFO, "syslog test message generated in program %s \n", argv[0]);   
        closelog();   
        return 0;   
    }

编译生成可执行文件后,每运行一次,程序将往/var/log/messages添加一条如下的记录:

Apr 23 17:15:15 lirong-920181 testsyslog[27214]: syslog test message generated in program ./a.out

格式基本是:

timestamp hostname ident[pid]:log message

其中ident就是我们调用openlog是指定的”testsyslog”,而之所以会打印出[27214]是openlog的option参数中指定了LOG_PID。

三、linux syslog配置

1)、syslog日志服务:
1、守护进程:syslog
2、端口:514
3、配置文件:/etc/syslog.conf
4、常见日志文件:

/var/log/dmesg      内核引导信息日志
/var/log/message    标准系统错误信息日志
/var/log/maillog    邮件系统信息日志
/var/log/cron       计划任务日志
/var/log/secure     安全信息日志

2)、 配置文件:

syslog配置文件如下

[root@server ~]# vim /etc/syslog.conf
# Log all kernel messages to the console.
# Logging much else clutters up the screen.
#kern.*                                                 /dev/console
# Log anything (except mail) of level info or higher.
# Don't log private authentication messages!
*.info;mail.none;authpriv.none;cron.none                /var/log/messages
# The authpriv file has restricted access.
authpriv.*                                              /var/log/secure
# Log all the mail messages in one place.
mail.*                                                  -/var/log/maillog
# Log cron stuff
cron.*                                                  /var/log/cron
# Everybody gets emergency messages
*.emerg                                                 *
# Save news errors of level crit and higher in a special file.
uucp,news.crit                                          /var/log/spooler
# Save boot messages also to boot.log
local7.*     

配置文件中每行表示一个项目,格式为:facility.level action
由两个部分组成:
第一部分:选择条件(可以有一个或者多个条件),分为两个字段。
第二部分:操作动作;
1、选择条件
选择条件本身分为两个字段,之间用一个小数点(.)分隔。前一字段是一项服务,后一字段是一个优先级。选择条件是对消息类型的一种分类,这种分类便于人们把不同类型的消息发送到不同的地方。在同一个syslog配置行上允许出现一个以上的选择条件,但必须用分号(;)隔开。
常见facility:
kern 内核信息;
user 用户进程信息;
mail 电子邮件相关信息;
daemon 后台进程相关信息;
authpriv 包括特权信息如用户名在内的认证活动;
cron 计划任务信息;
syslog 系统日志信息
lpr 打印服务相关信息。
news 新闻组服务器信息
uucp uucp 生成的信息
local0—-local7 本地用户信息
2、重要级:
重要级是选择条件的第二个字段,它代表消息的紧急程度。
按严重程度由低到高排序:
debug 不包含函数条件或问题的其他信息
info 提供信息的消息
none 没有重要级,通常用于排错
notice 具有重要性的普通条件
warning 预警信息
err 阻止工具或某些子系统部分功能实现的错误条件
crit 阻止某些工具或子系统功能实现的错误条件
alert 需要立即被修改的条件
emerg 该系统不可用
不同的服务类型有不同的优先级,数值较大的优先级涵盖数值较小的优先级。如果某个选择条件只给出了一个优先级而没有使用任何优先级限定符,对应于这个优先级的消息以及所有更紧急的消息类型都将包括在内。比如说,如果某个选择条件里的优先级是“warning”,它实际上将把“warning”、 “err”、“crit”、“alert”和“emerg”都包括在内。
3、操作动作
日志信息可以分别记录到多个文件里,还可以发送到命名管道、其他程序甚至另一台机器。
syslog 主要支持以下活动:
file 指定文件的绝对路径
terminal 或 prin 完全的串行或并行设备标志符
@host(@IP地址) 远程的日志服务器

配置服务器:

在Linux中配置Rsyslog

在我们理解syslog之后,现在可以通过rsyslog来将一个Linux服务器配置为一个中心syslog服务器了,另外我们也将看到如何在一个Windows的系统上配置一个syslog客户端来发送内部日志到该syslog服务器中。

第1步: 初始化系统需求

要将linux主机设置为一个中央日志服务器, 我们需要创建一个分离的 /var 分区,并分配足够大的磁盘空间或者创建一个特殊的LVM卷组。这样就会使得syslog服务器能够承担在日积月累收集日志所带来的潜在增长。

第2步: 让rsyslog 后台进程生效

rsyslog守护进程来自于当前的linux发布版本的预装模块,但是默认并没有启动。为了能够让rsyslog守护进程能够接受外部的消息,需要编辑其配置文件/etc/rsyslog.conf.

打开文件进行编辑,查找到下面的两行所在的位置,通过删除其行首的#字符来取消注释。

$ModLoad imudp  
$UDPServerRun 514  

这会使得rsysolog守护进程能够在UDP端口514上接受日志消息了—UDP是一种比TCP速度快,但是并不具有TCP一样的数据流的可靠性。所以如果你需要使用可靠的传送机制,就可以通过取消以下行的注释。

$ModLoad imtcp  
$InputTCPServerRun 514  

需要注意的是,TCP和UDP可以被同时生效来监听TCP/UDP 连接。

第3步:创建日志接收模板

接下来的这步,需要我们来为远程消息创建模板,并告知rsyslog守护进程如何记录从其他客户端机器所接受到的消息。

使用文本编辑器来打开 /etc/rsyslog.conf,然后在GLOBAL DIRECTIVE块前追加以下的模板。

$template RemoteLogs,"/var/log/%HOSTNAME%/%PROGRAMNAME%.log" *  
\*.\* ?RemoteLogs  
& ~  

在此对该模板进行简单解释,$template RemoteLogs(这里“RemoteLogs” 字符串可以为任何其他的描述性的名称)指令使rsyslog后台进程将日志消息写到/var/log下的单独的本地日志文件中,其中日志文件的名称是基于远程日志发送机器的主机名以及生成该日志的应用程序名进行定义的。其中第二行暗示了我们将RemoteLogs模板应用到所有接收到的日志上。

符号”& ~”表示了一个重定向规则,被用来告知rsyslog守护进程停止对日志消息的进一步处理,并且不要在本地写入。如果没有使用该重定向规则,那么所有的远程消息都会在写入上述描述的日志文件之外同时被写入到本地日志文件,这就意味着日志消息实际上被写了两次。使用该规则的另外一个结果就是syslog服务器本身的日志消息只会被以该机器主机名命名的专有文件中。

如果你想要的话,也可以使用下面的模式对特定的设备或严重性级别使用新的模板直接来记录日志消息。

\[facility-level\].\[severity-level\] ?RemoteLogs  

例如:

将全部优先级别的所有内部用户验证消息指定为RemoteLogs模板:

authpriv.* ?RemoteLogs  

将所有系统进程中除开mail、用户验证和cron消息之外的进程产生的消息级别的日志指定为RemoteLogs模板:

*.info,mail.none,authpriv.none,cron.none ?RemoteLogs  

如果我们想要将所有从远程客户端接受到的消息写入到一个以它们的IP地址命名的单个文件中,可以使用以下的模板。在此我们为该模板赋予了“IpTemplate”名称。

$template IpTemplate,"/var/log/%FROMHOST-IP%.log"  
\*.\* ?IpTemplate  
& ~  

在我们启用rsyslog守护进程并编辑好配置文件之后,需要重启该守护进程。

在 Debian,Ubuntu 或 CentOS/RHEL 6中:

$ sudo service rsyslog restart  

在 Fedora 或 CentOS/RHEL 7中:

$ sudo systemctl restart rsyslog  

我们可以通过netstat命令来验证rsyslog守护进程是否正常工作。

$ sudo netstat -tulpn | grep rsyslog  

在UDP监听端口下工作的rsyslog守护进程会有类似下面的输出。

udp 0 0 0.0.0.0:514 0.0.0.0:* 551/rsyslogd  
udp6 0 0 :::514 :::* 551/rsyslogd  

如果rsyslog守护进程被设置在TCP连接端口,那么应该有类似下面所示的输出。

tcp 0 0 0.0.0.0:514 0.0.0.0:* LISTEN 1891/rsyslogd  
tcp6 0 0 :::514 :::* LISTEN 1891/rsyslogd

配置客户端:

1、配置/etc/syslog.conf

修改客户机/etc/syslog.conf文件,在有关配置行的操作动作部分用一个“@”字符指向日志服务器

[root@client ~]# vim /etc/syslog.conf
# Log all kernel messages to the console.
# Logging much else clutters up the screen.
#kern.*                                                 /dev/console
*.*                                                     @10.64.165.210
# The authpriv file has restricted access.
authpriv.*                                              /var/log/secure
……下面省略

另外如果配置了DNS域名的话可以使用域名。

2、重启客户端syslog使设置生效。

检测成果:下图是我们在客户端重启iptables服务后在服务端看到的日志情况:

[root@client ~]# cat /var/log/messages |tail
Nov 30 16:44:29 10.64.165.200 kernel: klogd 1.4.1, log source = /proc/kmsg started.
Nov 30 16:44:33 10.64.165.200 kernel: Removing netfilter NETLINK layer.
Nov 30 16:44:33 10.64.165.200 kernel: ip_tables: (C) 2000-2006 Netfilter Core Team
Nov 30 16:44:33 10.64.165.200 kernel: Netfilter messages via NETLINK v0.30.
Nov 30 16:44:33 10.64.165.200 kernel: ip_conntrack version 2.4 (4096 buckets, 32768 max) - 228 bytes per conntrack

四、其他设置

logger

logger 是一个shell 命令接口,可以通过该接口使用Syslog的系统日志模块,还可以从命令行直接向系统日志文件写入一行信息。

logger 语法
logger [options] [messages]

  • options (选项)
    -d, –udp 使用数据报(UDP)而不是使用默认的流连接(TCP)
    -i, –id 逐行记录每一次logger的进程ID
    -f, –file file_name记录特定的文件
    -h, –help 显示帮助文本并退出
    -n, –server 写入指定的远程syslog服务器,使用UDP代替内装式syslog的例程
    -P, –port port_num 使用指定的UDP端口。默认的端口号是514
    -p, –priority priority_level指定输入消息的优先级,优先级可以是数字或者指定为 ” facility.level” 的格式。默认级别是 “user.notice”
    -s, –stderr 输出标准错误到系统日志。
    -t, –tag tag 指定标记记录
    -u, –socket socket 写入指定的socket,而不是到内置系统日志例程。
    -V, –version 现实版本信息并退出

  • messages:写入log文件的内容消息,可以与-f配合使用。

日志滚动

系统时时刻刻都在产生日志,如果不及时清理,很快就会灌满硬盘,但如果要手工清理,又很麻烦。logrotate 用来把旧的日志文件删除,并创建新的日志文件,我们把它叫做“转储”。

我们可以根据日志文件的大小,也可以根据其天数来转储,这个过程一般通过一个叫做crond的守护进程来执行,logrotate 还可以用于压缩日志文件,以及发送日志到指定的E-mail 。

logrotate 的配置文件是 /etc/logrotate.conf,主要参数如下表:

参数                    功能
compress                通过gzip 压缩转储以后的日志
nocompress              不需要压缩时,用这个参数
copytruncate            用于还在打开中的日志文件,把当前日志备份并截断
nocopytruncate          备份日志文件但是不截断
create mode owner group 转储文件,使用指定的文件模式创建新的日志文件
nocreate                不建立新的日志文件
delaycompress           和 compress 一起使用时,转储的日志文件到下一次转储时才压缩
nodelaycompress         覆盖 delaycompress 选项,转储同时压缩。
errors address          专储时的错误信息发送到指定的Email 地址
ifempty                 即使是空文件也转储,这个是 logrotate 的缺省选项。
notifempty              如果是空文件的话,不转储
mail address            把转储的日志文件发送到指定的E-mail 地址
nomail                  转储时不发送日志文件
olddir directory        转储后的日志文件放入指定的目录,必须和当前日志文件在同一个文件系统
noolddir                转储后的日志文件和当前日志文件放在同一个目录下
prerotate/endscript     在转储以前需要执行的命令可以放入这个对,这两个关键字必须单独成行
postrotate/endscript    在转储以后需要执行的命令可以放入这个对,这两个关键字必须单独成行
daily                   指定转储周期为每天
weekly                  指定转储周期为每周
monthly                 指定转储周期为每月
rotate count            指定日志文件删除之前转储的次数,0 指没有备份,5 指保留5 个备份
tabootext [+] list      不转储指定扩展名的文件,缺省的扩展名是:.rpm-orig .rpmsave

size size               当日志文件到达指定的大小时才转储,可以指定bytes(缺省)以及KB(sizek)或者MB (sizem).

系统对 logrotate 的执行和操作:
/etc/cron.daily/路径下,有一个logrotate的shell脚本,所以cron程序会每天调用一次logrotate程序,然后logrotate程序回去检查日志文件是否符合回滚条件,并执行相应动作。
执行操作:/usr/sbin/logrotate /etc/cron.daily/logrotate.conf;

在/etc/logrotate.conf文件中,有如下选项:

# RPM packages drop log rotation information into this directory
include /etc/logrotate.d

#这个选项说明在执行logrotate程序时,同时执行/etc/logrotated目录下的所有脚本。

执行动作示例:每月清除/var/log/wtmp目录中的相关内容:

/var/log/wtmp {
monthly
create 0664 root root
rotate 1
}

简单封装

C接口使用用例
简洁版:

#include <syslog.h>

int main(int argc, char **argv)
{
    openlog("syslog_test", LOG_PID, LOG_DAEMON);

    syslog(LOG_EMERG, "system is unusable");
    syslog(LOG_ALERT, "action must be taken immediately");
    syslog(LOG_CRIT, "critical conditions");
    syslog(LOG_ERR, "error conditions");
    syslog(LOG_WARNING, "warning conditions");
    syslog(LOG_NOTICE, "normal, but significant, condition");
    syslog(LOG_INFO, "informational message");
    syslog(LOG_DEBUG, "debug-level message");

    closelog();

    return 0;
}

宏定义版:

#include <stdio.h>
#include <syslog.h>
#include <sys/types.h>
#include <unistd.h>

#define log_debug(fmt, ...)      syslog(LOG_DEBUG, fmt, ##__VA_ARGS__)
#define log_info(fmt, ...)       syslog(LOG_INFO, fmt, ##__VA_ARGS__)
#define log_notice(fmt, ...)     syslog(LOG_NOTICE, fmt, ##__VA_ARGS__)
#define log_warning(fmt, ...)    syslog(LOG_WARNING, fmt, ##__VA_ARGS__)
#define log_error(fmt, ...)      syslog(LOG_ERR, fmt, ##__VA_ARGS__)
#define log_crit(fmt, ...)       syslog(LOG_CRIT, fmt, ##__VA_ARGS__)
#define log_alert(fmt, ...)      syslog(LOG_ALERT, fmt, ##__VA_ARGS__)
#define log_emerge(fmt, ...)     syslog(LOG_EMERG, fmt, ##__VA_ARGS__)

int main(int argc, char **argv)
{
    openlog("syslog_test", LOG_PID, LOG_DAEMON);

    log_debug("debug-level message");
    log_info("informational message");
    log_notice("normal, but significant, condition");
    log_warning("warning conditions");
    log_error("error conditions");
    log_crit("critical conditions");
    log_alert("action must be taken immediately");
    log_emerge("system is unusable");

    closelog();

    return 0;
}

参考链接:

  • https://blog.csdn.net/zhangdaisylove/article/details/46843233
  • https://www.cnblogs.com/bonelee/p/6234647.html
  • https://blog.csdn.net/myloveqingmu/article/details/53501987
  • https://blog.csdn.net/zhezhebie/article/details/75222667
  • https://blog.csdn.net/lidonghat/article/details/55004280

发表评论

电子邮件地址不会被公开。 必填项已用*标注

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax

This site uses Akismet to reduce spam. Learn how your comment data is processed.