在的Linux系统上使用的日志系统一般为rsyslogd
。rsyslogd
守护进程既能接收用户进程输出的日志,又能接收内核日志。用户进程是通过调用syslog
函数生成系统日志的。该函数将日志输出到一个UNIX本地域socket类型(AF_UNIX)的文件/dev/log中,rsyslogd
则监听该文件以获取用户进程的输出。
一、日志的输出
1.1、打开日志
#include <syslog.h>
void openlog(const char* ident, int logopt, int facility);
-
ident
参数指定的字符串将被添加到每条日志消息的开头,以便于识别消息的来源,通常是程序名称 -
logopt
参数对后续syslog
调用的行为进行配置,它可取下列值的按位或:-
#define LOG_PID 0x01/*在日志消息中包含程序PID*/ #define LOG_CONS 0x02/*如果消息不能记录到日志文件,则打印至终端*/ #define LOG_ODELAY 0x04/*延迟打开日志功能直到第一次调用syslog*/ #define LOG_NDELAY 0x08/*不延迟打开日志功能*/
-
-
facility
参数可用来修改syslog
函数中的默认设施值-
LOG_USER
:用户级别的消息。 -
LOG_MAIL
:邮件系统。 -
LOG_DAEMON
:系统守护进程。 -
LOG_AUTH
:安全/授权消息。 -
LOG_SYSLOG
:由syslogd(8)内部生成的消息。
-
1.2、打印日志
#include <syslog.h>
void syslog(int priority, const char* message, ...);
-
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/*调试*/
-
-
format
:一个格式字符串,类似于printf
函数中的格式字符串。它指定了如何格式化后续参数
1.3、关闭日志
#include <syslog.h>
void closelog();
1.4、设置日志掩码
程序在开发阶段可能需要输出很多调试信息,而发布之后我们又需要将这些调试信息关闭。解决这个问题的方法并不是在程序发布之后删除调试代码(因为日后可能还需要用到),而是简单地设置日志掩码,使日志级别大于日志掩码的日志信息被系统忽略。下面这个函数用于设置syslog的日志掩码:
#include <syslog.h>
int setlogmask(int maskpri);
maskpri
参数指定日志掩码值。该函数始终会成功,它返回调用进程先前的日志掩码值。
二、日志的保存
rsyslogd守护进程在接收到用户进程或内核输入的日志后,会把它们输出至某些特定的日志文件。常见日志文件
/var/log/debug
:调试信息
/var/log/btmp
:记录登录失败的用户信息、时间及远程 ip
/var/log/cron
:记录 crontab 执行情况
/var/log/kern.log
:内核消息
/var/log/dmesg
:开机自检信息
/var/log/lastlog
:记录最后一次登录的时间、IP 等信息
/var/log/maillog
:记录邮件收发详细信息
/var/log/wtmp
:永久记录所有用户的登陆、注销信息,同时记录系统的后动、重启、关机事件
/var/log/messages
:记录内核消息及各种应用程序的日志信
/var/log/secure
:系统安全日志,记录用户登录认证情况,如 pop3、ssh、telnet、ftp 等记录
/var/run/utmp
:记录当前登录的用户信息
三、日志的配置
内核日志由printk函数打印至内核的环状缓存中。缓存直接映射到/proc/kmsg
文件中。rsyslogd
则通过读取该文件获得内核日志。
用户日志则是调用 syslog
函数,向文件 /dev/log
中写入信息,rsyslogd
则通过读取该文件获得用户日志。
日志信息具体如何分发,可以在rsyslogd
的配置文件中设置。rsyslogd
的主配置文件是/etc/rsyslog.conf
。
主要可以设置的项包括:内核日志输入路径,是否接收UDP日志及其监听端口(默认是514,见/etc/services文件),是否接收TCP日志及其监听端口,日志文件的权限,包含哪些子配置文件(比如/etc/rsyslog.d/*.conf)。rsyslogd的子配置文件则指定各类日志的目标存储文件。
3.1、修改日志默认输出文件
在/etc/rsyslog.conf
文件末尾添加:
if $programname == 'httpp' then /var/log/httpp
& stop
if $programname == 'httpp' then /var/log/httpp
:如果日志消息的程序名($programname
)是'httpp'
,那么将该消息写入/var/log/httpp
文件。& stop
:执行完上述写入操作后,停止对这条消息的进一步处理。
修改完配置后需要重启服务
sudo systemctl restart rsyslog
四、仿真
通过配置文件将httpp程序的日志输出到 /var/log/httpp
文件中。
现在输出日志信息
#include <unistd.h>
#include <syslog.h>
int main() {
// 打开日志
openlog("httpp", LOG_PID | LOG_CONS, LOG_USER);
// 记录日志消息
syslog(LOG_INFO, "LOG_INFO: Program started by user %d", getuid());
syslog(LOG_NOTICE, "LOG_NOTICE: Program started by user %d", getuid());
syslog(LOG_WARNING, "LOG_WARNING: Program started by user %d", getuid());
syslog(LOG_ERR, "LOG_ERR: Program started by user %d", getuid());
syslog(LOG_CRIT, "LOG_CRIT: Program started by user %d", getuid());
syslog(LOG_ALERT, "LOG_ALERT: Program started by user %d", getuid());
syslog(LOG_EMERG, "LOG_EMERG: Program started by user %d", getuid());
// 关闭日志
closelog();
return 0;
}
仿真结果如下所示: