linux日志:syslogd和klogd及syslog
Syslog是一个通过IP网络允许一台机器发送事件通知信息给事件收集者(Syslog服务器或者Syslog Daemon)的协议。换言之,就是一台机器或者设备能够被配置,使之产生Syslog信息并且发送到一台特定的Syslog服务器/Daemon。
Syslog信息建立在UDP之上,一般Syslog信息在UDP514端口上被收集,Syslog信息的长度不大于1024字节。由于基于UDP协议,所以当如果因为网络拥塞等情况导致信息包丢失,那么信息将不再重发,而是简单的丢失掉。之后RF3195又增加了TCP514端口。
tftpd64.exe集成多种协议,其中包含syslog(UDP514端口)服务,可接收日志。
零. 日志格式
syslog协议支持RFC3164和RFC5424。
Syslog-ng与Syslog协议与之数据格式RFC5424、 RFC3164详解
// RFC3164 <PRI>HEADER MESSAGE <15>Jul 10 12:00:00 192.168.1.1 SyslogGen MESSAGE // RFC5424 <PRI>VERSION TIMESTAMP HOSTNAME APP-NAME PROCID MSGID <34>1 2003-10-11T22:14:15.003Z mymachine.example.com su - ID47 - BOM'su root' failed for lonvick on /dev/pts/8 <165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1 myproc 8710 - - %% It's time to make the do-nuts.
PRI:即Priority(优先级),有效值范围为0 - 191。不能有空格、数字前也不能补0。合法的形式如:<15>。PRI值包含两部分信息:Facility和Level。其中Facility值用于判断哪个程序产生了日志信息。Level值用于判断严重等级。计算方法:PRI = Facility * 8 + Level。只有一种情况,当0跟着<时,表示优先级为0。其他情况,不能以0开头
一. 日志守护进程
syslogd和klogd是很有意思的守护进程,syslogd是一个分发器,它将接收到的所有日志按照/etc/syslog.conf的配置策略发送到这些日志应该去的地方,当然也包括从klogd接收到的日志。klogd首先接收内核的日志,然后将之发送给syslogd。
syslogd日志记录器由两个守护进程(klogd,syslogd)和一个配置文件(syslog.conf)组成。klogd不使用配置文件,它负责截获内核消息,它既可以独立使用也可以作为syslogd的客户端运行。syslogd默认使用/etc/syslog.conf作为配置文件,负责截获应用程序消息,还可以截获klogd向其转发的内核消息。支持internet/unix domain sockets的特性使得这两个工具可以用于记录本地和远程的日志。
二.日志目录
Linux系统日志一般保存在/var/log下,其中一些只有特定版本才用,如dpkg.log只在基于Debian的系统中有。
/var/log/messages或/var/log/syslog — 包括整体系统信息,其中也包含系统启动期间的日志。此外,mail,cron,daemon,kern和auth等内容也记录在var/log/messages日志中。
/var/log/dmesg — 包含内核缓冲信息(kernel ring buffer)。在系统启动时,会在屏幕上显示许多与硬件有关的信息。可以用dmesg查看它们。
/var/log/auth.log — 包含系统授权信息,包括用户登录和使用的权限机制等。
/var/log/boot.log — 包含系统启动时的日志。
/var/log/daemon.log — 包含各种系统后台守护进程日志信息。
/var/log/dpkg.log — 包括安装或dpkg命令清除软件包的日志。
/var/log/kern.log — 包含内核产生的日志,有助于在定制内核时解决问题。
/var/log/lastlog — 记录所有用户的最近信息。这不是一个ASCII文件,因此需要用lastlog命令查看内容。
/var/log/maillog 与 /var/log/mail.log — 包含来着系统运行电子邮件服务器的日志信息。例如,sendmail日志信息就全部送到这个文件中。
/var/log/user.log — 记录所有等级用户信息的日志。
/var/log/Xorg.x.log — 来自X的日志信息。
/var/log/alternatives.log — 更新替代信息都记录在这个文件中。
/var/log/btmp — 记录所有失败登录信息。使用last命令可以查看btmp文件。例如,last -f /var/log/btmp | more 。
/var/log/cups — 涉及所有打印信息的日志。
/var/log/anaconda.log — 在安装Linux时,所有安装信息都储存在这个文件中。
/var/log/yum.log — 包含使用yum安装的软件包信息。
/var/log/cron — 每当cron进程开始一个工作时,就会将相关信息记录在这个文件中。
/var/log/secure — 包含验证和授权方面信息。例如,sshd会将所有信息记录(其中包括失败登录)在这里。
/var/log/wtmp或/var/log/utmp — 包含登录信息。使用wtmp可以找出谁正在登陆进入系统,谁使用命令显示这个文件或信息等。
/var/log/faillog —包含用户登录失败信息。此外,错误登录命令也会记录在本文件中。
除了手动存档和清除这些日志文件以外,还可以使用logrotate在文件达到一定大小后自动删除。可以尝试用vi,tail,grep和less等命令查看这些日志文件。
tail -F /var/log/messages
三. 日志应用编程
syslog是lib函数,用于向系统发送日志(send messages to the system logger)。
#include <syslog.h> void openlog(const char *ident, int option, int facility); void syslog(int priority, const char *format, ...); void closelog(void); void vsyslog(int priority, const char *format, va_list ap);
默认的日志操作步骤为openlog() -> syslog()/ vsyslog() -> closelog()。
openlog()的参数ident指向一个字符串,追加到每条日志前,用于标记日志属主,一般为程序名,为NULL时默认是程序名(不统一);
option控制log行为,下列值可OR:
LOG_CONS Write directly to system console if there is an error while sending to system logger. LOG_NDELAY Open the connection immediately (normally, the connection is opened when the first message is logged). LOG_NOWAIT Don't wait for child processes that may have been created while logging the message.
(The GNU C library does not create a child process, so this option has no effect on Linux.) LOG_ODELAY The converse of LOG_NDELAY; opening of the connection is delayed until syslog() is called.
(This is the default, and need not be specified.) LOG_PERROR (Not in POSIX.1-2001 or POSIX.1-2008.) Print to stderr as well. LOG_PID Include PID with each message.
facility指定哪种类型程序在发送日志,配置文件可指定不同facility日志可进行不同处理:
LOG_AUTH security/authorization messages LOG_AUTHPRIV security/authorization messages (private) LOG_CRON clock daemon (cron and at) LOG_DAEMON system daemons without separate facility value LOG_FTP ftp daemon LOG_KERN kernel messages (these can't be generated from user processes) LOG_LOCAL0 through LOG_LOCAL7 reserved for local use LOG_LPR line printer subsystem LOG_MAIL mail subsystem LOG_NEWS USENET news subsystem LOG_SYSLOG messages generated internally by syslogd(8) LOG_USER (default) generic user-level messages LOG_UUCP UUCP subsystem
syslog()负责写日志,priority指定日志级别:
LOG_EMERG system is unusable LOG_ALERT action must be taken immediately LOG_CRIT critical conditions LOG_ERR error conditions LOG_WARNING warning conditions LOG_NOTICE normal, but significant, condition LOG_INFO informational message LOG_DEBUG debug-level message
man手册明确指出不要向format传入用户数据(Never pass a string with user-supplied data as a format, use the following instead)
syslog(priority, "%s", string);
一般应用程序中都要都其进行封装,以便于直接打印相关级别日志(封装LOG_EMERG级别日志):
#define BUF_SIZE 1024 char *ident = "hello"; void hello_syslog_emerg(char *format,...) { va_list ptr; char buf[BUF_SIZE] = {0}; // ident null or format message null if(!ident || !format) { return; } openlog(ident, 0, LOG_DAEMON); // put log va_start(ptr, format); vsprintf(buf, format, ptr); va_end(ptr); syslog(LOG_EMERG, "%s", buf); return; }
示例:
#include <stdio.h> #include <stdarg.h> #include <syslog.h> #define BUF_SIZE 1024 char *ident = "hello"; void hello_syslog_emerg(char *format,...) { va_list ptr; char buf[BUF_SIZE] = {0}; // ident null or format message null if(!ident || !format) { return; } openlog(ident, 0, LOG_DAEMON); // put log va_start(ptr, format); vsprintf(buf, format, ptr); va_end(ptr); syslog(LOG_EMERG, "%s", buf); return; } int main(void) { char cbuf[BUF_SIZE] = {0}; printf("send one emergency message to system:\n"); scanf("%s", cbuf); hello_syslog_emerg("%s", cbuf); return 0; }
@ubuntu:~/vmlinux$ gcc hello.c -o hello -Wall @ubuntu:~/vmlinux$ ./hello send one emergency message to system: thesystemisoff @ubuntu:~/vmlinux$ Broadcast message from systemd-journald@ubuntu (Sat 2018-05-12 17:12:50 CST): hello[3786]: thesystemisoff
或宏定义封装:
#define ERROR(fmt, ...) do { \ syslog(LOG_ERR, "jail: "fmt, ## __VA_ARGS__); \ } while (0)
四. 日志循环
linux日志一般会按一定的规则进行循环,保证日志量控制在一定的范围内。
日志循环的原理一般是:在特定的时间点,或日志达到一定大小,就触发循环脚本。
循环脚本通过新增新日志,备份老日志,调度应用重新加载配置(重新写日志)达到日志循环的目的。
1. 手工创建脚本实现
通过脚本执行的日志循环,常见的方法一般分为有损循环和无损循环两种形式。
以nginx日志循环为例,nginx作为常用的代理转发服务器,每天承载上万级甚至百万级的量,正常情况下几天就可能把100G的磁盘打满。
据了解,nginx没有内置的日志循环配置(apache好像有)。
1.1 有损循坏
直接清理日志
cp /usr/local/nginx/logs/access.log /usr/local/nginx/logs/access_$(date -d '-1day' '+%Y-%m-%d').log echo > /usr/local/nginx/logs/access.log
配合定时任务
0 0 * * * cp /usr/local/nginx/logs/access.log /usr/local/nginx/logs/access.log.1 && echo > /usr/local/nginx/logs/access.log
该方法通过cp+echo的方式到达日志循环的效果。
好处是:
- 简单地把日志置空,可以达到快速清理日志的效果
- 历史日志通过cp进行了备份
- echo置空相比笨方法(停止nginx,rm日志,启动nginx)快很多,当日志到达GB级别,效果更明显,nginx也无需重启
坏处是:
- 日志过大时,cp时间过长
- 日志短时间需要占用size*2的磁盘容量
之所以称之为有损循环,是因为echo >
命令执行时,nginx工作进程依然在打印日志,这时候会出现两种可能:
- 0时0分前几秒的日志被清除了,丢了部分日志;
- nginx工作进程无法写入日志,进程报错甚至挂掉。
因此,不推荐使用该方法
1.2 无损循环
crontab设置
crontab -e 0 0 * * * /data/op_shell/nginx_log_division.sh
nginx_log_division.sh
#!/bin/bash #设置日志文件存放目录 logs_path="/usr/local/nginx/logs/" #设置pid文件(也有可能在/var/run中) pid_path="/usr/local/nginx/logs/nginx.pid" #日志文件 filepath=${logs_path}"access.log" #重命名日志文件 mv ${logs_path}access.log ${logs_path}access_$(date -d '-1 day' ' +%Y-%m-%d'.log #向nginx主进程发信号重新打开日志 kill -USR1 `cat ${pid_path}`
该方法通过mv+kill的方式进行日志循环,因为linux中,日志打开底层原理是通过inode信息寻址找到对应的block进行内容读取,mv操作不改变文件的inode值。
首先日志mv重命名,期间nginx依然打印日志到重命名的文件中,通过kill向nginx master进程发送信号,nginx重新读取配置文件,触发新的access日志重新打印。
两种方法存在以下问题:
- 循环保存的日志,需要再通过crontab任务清理,例如只保留最新7天的日志;
- 日志如果按size循环,需要重新编写脚本。
2. logrotate循环
logrotate是一个日志循环的工具,linux内置的syslog也是使用它进行日志循环。
logrotate的配置存放于/etc/logrotate.d
中
[root@zero /etc/logrotate.d]# ll /etc/logrotate.d/ total 32 -rw-r--r-- 1 root root 289 Jun 22 2016 conman -rw-r--r-- 1 root root 194 Jul 18 2016 httpd -rw-r--r-- 1 root root 136 Jun 22 2016 iptraf-ng -rw-r--r-- 1 root root 893 Aug 12 2016 mariadb -rw-r--r-- 1 root root 140 Oct 23 2014 mgetty -rw-r--r-- 1 root root 409 Jun 22 2016 psacct -rw-r--r-- 1 root root 224 Nov 5 2016 syslog -rw-r--r-- 1 root root 100 Oct 12 2017 yum
添加nginx配置
/data/log/nginx/*log { hourly rotate 5 missingok notifempty nocompress sharedscripts postrotate [ -f /data/log/nginx/nginx.pid ] && kill -USR1 `cat /data/log/nginxnginx.pid` endscript }
五. 常用日志服务syslog、syslog-ng、rsyslog、zlog、aliyun日志服务
zlog:zlog的安装与使用 zlog使用手册http://hardysimpson.github.io/zlog/UsersGuide-CN.html
rsyslog:用RSYSLOG进行加密传输#2
aliyun日志服务:使用Syslog协议上传日志 SDK
Syslog项目是第一个项目,始于1980年,它是Syslog协议的根项目。此时Syslog是一个非常简单的协议。一开始它只支持UDP进行传输,因此它不保证消息的传递。
接下来是1998年的syslog-ng,它扩展了基本的syslog协议,具有以下新功能:
>基于内容的过滤
>直接登录数据库
> TCP用于传输
> TLS加密
接下来是2004年的Rsyslog,它扩展了syslog协议,具有以下新功能:
> RELP协议支持
>缓冲操作支持
参考:
1. http://blog.csdn.net/dog250/article/details/5707979 syslog的点滴--集中处理日志
2. http://www.360doc.com/content/13/0102/10/7775902_257612487.shtml
6. linux日志循环