Linux日志管理-syslog和rsyslog

1 syslogd简介#

syslogd不仅仅是记录kernel log的服务,还能记录user space中的日志。

syslogd是Linux下的一个记录日志文件服务。新版本叫做rsyslogd。

syslogd有一系列的子服务,例如mail、auth、cron、kern等等,这些子服务提供日志记录的功能,。当程序要记录log时,可以直接调用这些子服务将日志记录到设定的地方。

syslogd是一个守护进程,配置这整个守护进程以及其子服务的地方就是/etc/syslog.conf这个文件。可以从https://www.rsyslog.com/doc/master/获取官方文档。

1.1 日志格式#

如果配置好并运行了 syslogd 或 klogd,一般所有 log的信息也会追加到 /var/log/messages。并且kernel log信息被记录在/val/log/kern.log

img

可以看到基本日志格式包含以下四列:

  1. 事件产生的时间(Jan 1 08:00:09)
  2. 发生事件的服务器的主机名 (cvitek)
  3. 产生事件的服务名或程序名 (kernel or local5)
  4. 事件的具体信息(…cif a0c2000.cif:..)

当开启rsyslogd后,不能透过/proc/kmsg来查看kernel log。

1.2 /etc/syslog.conf服务配置#

  1. /etc/rsyslog.conf 是rsyslog服务的总配置文件
  2. /etc/rsyslog.d 该目录是单独配置的rsyslog配置文件

1.2.1 总配置/etc/syslog.conf#

rsyslog记录哪些日志,到底记录了什么样的日志,是通过这个/etc/rsyslog.conf配置文件来决定的,先分析一下rsyslogd的总配置文件:

img

默认规则会定义在/etc/rsyslog.d/50-default.conf中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#################
#### MODULES ####
#################
module(load="imuxsock") # provides support for local system logging ;加载提供对本地系统日志的支持
module(load="imklog") # provides kernel logging support;加载读取内核消息模块
#module(load="immark") # provides --MARK-- message capability
# provides UDP syslog reception (接收使用UDP 协议转发过来的日志,这里#注释掉了表示不启用)
#module(load="imudp")
#input(type="imudp" port="514") (允许514端口接收)
# provides TCP syslog reception (接收使用UDP 协议转发过来的日志)
#module(load="imtcp")
#input(type="imtcp" port="514")(允许514端口接收)
# Enable non-kernel facility klog messages
$KLogPermitNonKernelFacility on
###########################
#### GLOBAL DIRECTIVES ####
###########################
#
# Use traditional timestamp format.
# To enable high precision timestamps, comment out the following line.
#
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
# Filter duplicated messages
$RepeatedMsgReduction on
#
# Set the default permissions for all log files.
#
$FileOwner syslog
$FileGroup adm
$FileCreateMode 0640
$DirCreateMode 0755
$Umask 0022
$PrivDropToUser syslog
$PrivDropToGroup syslog
#
# Where to place spool and state files
#
$WorkDirectory /var/spool/rsyslog
(记录所有日志类型的info级别以及大于info级别的信息到/var/log/messages,但是mail邮件信息,authpriv验证方面的信息和cron时间任务相关的信息除外)
#*.info;mail.none;authpriv.none;cron.none /var/log/messages
# Include all config files in /etc/rsyslog.d/
#
$IncludeConfig /etc/rsyslog.d/*.conf (表示加载该目录中的所有配置)

1.2.2 rsyslog规则(/etc/rsyslog.d/*.conf)#

rsyslog规则配置文件一般由以下3部分组成,每一行表示一个项目,格式为:facility.level action,分别表示日志类型,日志等级,日志输出路径。一般系统默认的规则定义在/etc/rsyslog.d/50-default.conf

img

一般所有日志类型都会被追加在/val/log/messages。如:

1
*.info;mail.none;authpriv.none;cron.none    /var/log/messages  

1.2.2.1 facility-日志类型#

  • kern: 内核信息
  • user: 用户进程相关信息
  • mail: 电子邮件相关信息
  • Local0- local7: 为本地使用预留的服务
  • daemon: 后台进程相关信息
  • syslog: 系统日志信息

1.2.2.2 level-按严重程度由低到高排序#

  • none: 没有重要级
  • debug: 调试信息
  • info: 打印的信息
  • notice: 具有重要信息的普通条件
  • warning: 警告信息
  • err: 错误信息
  • crit: 阻止某些工具或子系统功能实现的错误条件
  • alert: 需要立即被修改的条件
  • emerg: 该系统不可用

1.2.2.3 action-表示log保存的位置#

那下面我也抄过来一份比较全面的规则定义示例供大家参考:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 记录mail日志等级为error及以上日志
mail.err /var/log/mail_err.log
# 记录mail所有等级为warn级别的日志(仅记录warn级别)
mail.=warn /var/log/mail_err.log
# 记录kern所有日志
kern.* /var/log/kern.log
# 将mail的所有信息,除了info以外,其他的都写入/var/adm/mail
mail.*;mail.!=info /var/adm/mail
# 将日志等级为crit或更高的内核消息定向到远程主机finlandia
# 如果主机崩溃,磁盘出现不可修复的错误,可能无法读取存储的消息。如果有日志在远程主机上,可以尝试找出崩溃的原因。
kern.crit @finlandia
# 记录所有类型的warning等级及以上日志
*.warning /var/log/syslog_warn.log
# 记录mail的warning日志和kern的error日志,其他所有的info日志
*.info;mail.warning;kern.error /var/log/messages
# 记录kernel的info到warning日志
kern.info;kern.!err /var/adm/kernel-info
# 将mail和news的info级别日志写入/var/adminfo
mail,news.=info /var/adm/info
# 将所有系统中所有类型的info日志和notice日志存入/var/log/massages,mail的所有日志除外。
*.=info;*.=notice;\
mail.none /var/log/messages
# 紧急消息(emerg级别)将使用wall显示给当前所有登录的用户,这里用等号表示只对emerg日志级别有效
*.=emerg *
# 该规则将所有alert以及更高级别的消息定向到操作员的终端,即登录的用户“root”和“joey”的终端。
*.alert root,joey

1.3 程序如何配置syslog子服务(自定义rsyslog规则)#

问题:进程如何发送消息给rsyslog守护进程,rsyslog守护进程是如何对各种日志区分开来的?

/usr/sbin/sshd、/usr/bin/login、/usr/bin/su这些进程,它们是调用一个叫syslog的系统调用, syslog系统调用是一个用于向rsyslog守护进程发送消息的的系统函数。
/usr/sbin/sshd,/usr/bin/login、/usr/bin/su这些进程专门执行登录验证时,它们在调用syslog系统函数会一般会传入LOG_AUTH这个常量。

/usr/bin/crond和/usr/bin/at这些在调用syslog系统调用会传入LOG_CRON这个常量(具体请看**syslog()**函数),日志归类规则如下:

img

所以如果用LOG_AUTH的syslog()函数调用,那么会归类到了/val/log/secure

如果用LOG_CRON的syslog()调用则归类到了/val/log/cron。而kernel等其他log被记录在了/val/log/messages中。

那么我们可以自定义规则如下:

img

1
2
3
4
5
6
syslogfacility-text:表示facility日志类型
syslogseverity-text:表示level日志级别

这里对aisdk.conf用local7日志类型产生的大于warn日志级别的log都将记录到/val/log/aisdk,
对kern.conf用kern类型产生的所有级别日志都记录到/val/log/kern,
Local5类型的日志记录到/val/log/middleware, 并且当日志级别等于或高于4(warn)时也会追加到console.

注意busybox要开启使能syslog.conf解析:/etc/syslog.conf解析,CONFIG_FEATURE_SYSLOGD_CFG=y

img

2 syslog()函数#

img

用户空间也可以用syslog()函数来记录自己的进程的日志,所以用户进程可以自定义日志规则。
调用openlog是可选择的。如果不调用openlog,则在第一次调用syslog时,会自动调用openlog。
syslog的相关函数和宏定义一般在toolchain中都会有定义:

img

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

2.1 openlog函数#

第1个参数为ident,该参数常用来表示信息的来源。ident信息会被固定地添加在每行日志的前面:
第2个参数 option控制标志:

option控制标志 作用
LOG_CONS 如果将信息发送给syslogd守护进程时发生错误,直接将相关信息输出到终端
LOG_PID 每条日志信息中都包括进程号

第3个参数为facility:

facility参数 syslog.conf中对应的facility取值
LOG_KERN kern
LOG_USER user
LOG_MAIL mail
LOG_DAEMON daemon
LOG_AUTH auth
LOG_SYSLOG syslog
LOG_LPR lpr
LOG_NEWS news
LOG_UUCP uucp
LOG_CRON cron
LOG_AUTHPRIV authpriv
LOG_FTP ftp
LOG_LOCAL0~LOG_LOCAL7 local0~local7

img

2.2 syslog函数#

第一个参数priority表示日志级别:

priority参数 syslog.conf中对应的level取值
LOG_EMERG emerg
LOG_ALERT alert
LOG_CRIT crit
LOG_ERR err
LOG_WARNING warning
LOG_NOTICE notice
LOG_INFO info
LOG_DEBUG debug

img

下面是具体的例子:

img

这里printf("%m")等价于printf("%s",strerror(errno));它表示把errno用string形式打印出来。

由于我这里facility为user时,是记录在/val/log/syslog中的:

img

因此打印log如下:

img

2.3 重定向log#

我们也可以把log定向到自己想要的地方。

2.3.1 方法1-修改rsyslog.conf#

img

facility=user时的所有level级别的log重定向到/val/log/user.log, 重启rsyslog服务:

img

此时log将被写入到新配置的位置/val/log/user.log, 当然/val/log/syslog也会保留一份.(因为也符合/val/log/syslog这条规则)

img

2.3.2 方法2-修改code中的facility#

img

那这里的facility被设置成了local0, 那也会记录在/val/log/syslog:

img

2.4 设置log等级#

  1. 这里新增一个app.conf,然后自定义log路径:

img

当然还可以类似于这样子写, syslogfacility-text和syslogseverity-text是rsyslog自带的系统变量。

img

  1. 重启rsyslog服务

    img

img

这里切成4个文件,每个文件记录1024k。

  1. 运行程序,查看log如下:

    img

img

  1. 那现在修改log等级为warn, 表示只有大于等于该等级的log才会记录。

    img

  2. 再次重启rsyslog服务,运行程序,可以看到”log debug”不再打印:

    img

2.5 重定向log到console#

img

再次重启rsyslog服务,运行程序,那么可以看到err级别的log打印在了console上,但是低于err级别还是会记录在/val/log/app。

img

3 dup函数介绍#

img

用来将标准输出重定向到文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static int dup_fd;
static int dup_fd_bak = 1000;

static int dup_fd(void) {
dup_fd = open( "./printf_dup_log.txt ", O_CREAT | O_RDWR | O_TRUNC);
dup2(STDOUT_FILENO, dup_fd_bak);/*backup stdout*/
dup2(dup_fd, STDOUT_FILENO);
return 0;
}
static int rst_fd(void) {
dup2(dup_fd_bak, fileno(stdout));/*recover stdout*/
close(dup_fd);
return 0;
}