一. 日志守护进程
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的特性使得这两个工具可以用于记录本地和远程的日志。
二. 日志应用编程
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)
参考:
1. http://blog.csdn.net/dog250/article/details/5707979
2. http://www.360doc.com/content/13/0102/10/7775902_257612487.shtml