工欲善其事,必先利其器。
服务器的调试和维护都需要一个专业的日志系统
linux提供一个守护进程处理系统日志-syslogd,现在使用的基本都是rsyslogd。
rsyslogd守护进程既能接收用户输出日志,也能接收内核日志。
用户进程通过syslog系统调用生成系统日志,该日志输出到一个UNIX本地域socket类型的文件/dev/log中,rsyslog则监听该文件以获取用户进程的输出。
系统上是通过另外一个守护进程rklogd来管理的,rsyslogd利用额外的模块实现了相同的功能。内核日志由printk等函数打印至内核的环状缓存(ring buffer)中。环状缓存的内容直接映射到/proc/kmsg文件中。rsyslogd则通过读取该文件获得内核日志。rsyslogd守护进程在接收到用户进程或内核输入的日志后,会把它们输出至某些特定的日志文件。默认情况下,调试信息会保存至/var/log/debug文件,普通信息保存至/var/log/messages文件,内核消息则保存至/var/log/kern.log文件。不过,日志信息具体如何分发,可以在rsyslogd 的配置文件中设置。rsyslogd 的主配置文件是/etc/rsyslog.conf,其中主要可以设置的项包括:内核日志输入路径,是否接收UDP日志及其监听端口(默认是514,见 /etclservices文件),是否接收TCP日志及其监听端口,日志文件的权限,包含哪些子配置文件图7-1总结了Linux的系统日志体系
sudo systemctl status syslog.service // 查看syslog服务状态 ● rsyslog.service - System Logging Service Loaded: loaded (/lib/systemd/system/rsyslog.service; enabled; vendor preset: enabl> Active: active (running) since Sat 2021-10-02 01:50:08 PDT; 3 days ago TriggeredBy: ● syslog.socket Docs: man:rsyslogd(8) https://www.rsyslog.com/doc/ Main PID: 732 (rsyslogd) Tasks: 4 (limit: 2273) Memory: 3.4M CGroup: /system.slice/rsyslog.service └─732 /usr/sbin/rsyslogd -n -iNONE sudo systemctl status rsyslog.service // 查看rsyslog服务状态 ● rsyslog.service - System Logging Service Loaded: loaded (/lib/systemd/system/rsyslog.service; enabled; vendor preset: enabl> Active: active (running) since Sat 2021-10-02 01:50:08 PDT; 3 days ago TriggeredBy: ● syslog.socket Docs: man:rsyslogd(8) https://www.rsyslog.com/doc/ Main PID: 732 (rsyslogd) Tasks: 4 (limit: 2273) Memory: 3.4M CGroup: /system.slice/rsyslog.service └─732 /usr/sbin/rsyslogd -n -iNONE
#include <syslog.h> void syslog(int priority, const char *format, ...);
可变参数函数来结构化输出。priority参数是所谓的设施值与日志级别的按位或。设施值的默认值是LOG_USER,日志级别如下
#include <syslog.h> #define LOG_EMERG 0 /* 系统不可用 */ #define LOG_ALERT 1 /* 报警,需要立即采取措施 */ #define LOG_CRIT 2 /* 非常严重的情况 */ #define LOG_ERR 3 /* 错误 */ #define LOG_WARNING 4 /* 警告 */ #define LOG_NOTICE 5 /* 通知 */ #define LOG_INFO 6 /* 信息 */ #define LOG_DEBUG 7 /* 调试 */
下面这个函数可以改变syslog的默认输出方式,进一步结构化日志
#include <syslog.h> void openlog(const char *ident, int option, int facility);
ident参数指定的字符串将被添加到日志消息的日期和时间之后,通常被设置为程序的名字。logopt参数对后序的syslog调用的参数进行配置,它可以去以下值的按位与。
#define LOG_PID 0x01 /* 在消息日志中包含程序的pid */ #define LOG_CONS 0x02 /* 如果消息不能记录到日志文件,则打印至终端 */ #define LOG_ODELAY 0x04 /* 延迟打开日志功能直到第一次调用syslog */ #define LOG_NDELAY 0x08 /* 不延迟打开日志功能 */
此外,日志过滤也很重要,设置日志掩码,是日志级别大于日志掩码的日志信息被系统忽视,设置日志掩码的函数
#include <syslog.h> int setlogmask(int mask);
mask是掩码的值。成功(始终成功的)该函数返回之前掩码的值。
关闭日志功能
#include <syslog.h> void closelog(void);