syslogd架构
- App通过syslog的接口进行log的打印,该接口define在syslog.h中;
- syslog会通过socket发送消息,将log发送给syslogd;
- syslogd在获取到log后,会进行log的处理;
- syslogd可以将log保存到本地,也可以发送到共享内存或远程服务器
openlog()
在syslog接口使用之前,有必要通过openlog进行一些log信息的初始化工作,openlog定义在系统头文件syslog.h中,函数原型:
void openlog (const char *__ident, int __option, int __facility)
- 第一个参数为log tag,同Android中LOG_TAG;
- 第二个参数为log flags,定义在syslog.h中;
如下:
#define LOG_PID 0x01 /* log the pid with each message */
#define LOG_CONS 0x02 /* log on the console if errors in sending */
#define LOG_ODELAY 0x04 /* delay open until first syslog() (default) */
#define LOG_NDELAY 0x08 /* don't delay open */
#define LOG_NOWAIT 0x10 /* don't wait for console forks: DEPRECATED */
#define LOG_PERROR 0x20 /* log to stderr as well */
例如:
使用LOG_PID,会在每一条log中添加pid信息;
使用LOG_CONS,在出现error信息的时候,会将log输出到congsole上。
- 第三个参数为syslog 的facility,syslog.h中一共有23种选择;
/* facility codes */
#define LOG_KERN (0<<3) /* kernel messages */
#define LOG_USER (1<<3) /* random user-level messages */
#define LOG_MAIL (2<<3) /* mail system */
#define LOG_DAEMON (3<<3) /* system daemons */
#define LOG_AUTH (4<<3) /* security/authorization messages */
#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */
#define LOG_LPR (6<<3) /* line printer subsystem */
#define LOG_NEWS (7<<3) /* network news subsystem */
#define LOG_UUCP (8<<3) /* UUCP subsystem */
#define LOG_CRON (9<<3) /* clock daemon */
#define LOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */
#define LOG_FTP (11<<3) /* ftp daemon */
/* other codes through 15 reserved for system use */
#define LOG_LOCAL0 (16<<3) /* reserved for local use */
#define LOG_LOCAL1 (17<<3) /* reserved for local use */
#define LOG_LOCAL2 (18<<3) /* reserved for local use */
#define LOG_LOCAL3 (19<<3) /* reserved for local use */
#define LOG_LOCAL4 (20<<3) /* reserved for local use */
#define LOG_LOCAL5 (21<<3) /* reserved for local use */
#define LOG_LOCAL6 (22<<3) /* reserved for local use */
#define LOG_LOCAL7 (23<<3) /* reserved for local use */
#define LOG_NFACILITIES 24 /* current number of facilities */
#define LOG_FACMASK 0x03f8 /* mask to extract facility part */
/* facility of pri */
#define LOG_FAC(p) (((p) & LOG_FACMASK) >> 3)
例如:
- 使用LOG_KERN,表示log为kernel信息;
- 使用LOB_USER,表示log为普通用户信息,一般package使用的信息可以设为LOG_USER;
- 使用LOG_DAEMON,表示log为系统守护进程信息;
syslog()
对于syslogd来说,log是通过syslog传入的,函数的原型:
void syslog (int __pri, const char *__fmt, ...)
应用可以通过openlog进行初始化,例如log的tag信息或者是pid信息。如果不进行openlog而直接使用syslog也是可以的,在syslog中会进行openlog的操作。当然,不进行openlog操作,log中有些信息就无法显示,例如pid信息。
下面来看下syslog中的参数:
- 第一个参数为log的优先级,与Android中的LOG_DEBUG或LOG_INFO等类似;
#define LOG_EMERG 0 /* system is unusable */
#define LOG_ALERT 1 /* action must be taken immediately */
#define LOG_CRIT 2 /* critical conditions */
#define LOG_ERR 3 /* error conditions */
#define LOG_WARNING 4 /* warning conditions */
#define LOG_NOTICE 5 /* normal but significant condition */
#define LOG_INFO 6 /* informational */
#define LOG_DEBUG 7 /* debug-level messages */
这里的priority定义与Android略有不同,例如LOG_CRIT表示critical的信息。
- 第二个参数为log的具体信息,同printf;
closelog()
在使用syslog结束之后通过closelog进行扫尾工作。函数原型:
void closelog (void)
主要就是将socket 关闭。
syslog.conf
syslogd机制中可以通过syslog.conf对log进行管理配置。默认存放在etc目录下。当然,也可以通过initrc进行动态设置。
设置syslog.conf必须按照形式:
facility.priority action
例如:
user.debug /var/log/log.debug
将openlog第二个参数为LOG_USER,syslog第一个参数为LOG_DEBUG的所有信息存放到/var/log/log.debug文件中。
- priority有:
alert、crit、debug、emerg、err、error、info、none、notice、panic、warn、warning
- facility有:
auth、authpriv、cron、daemon、ftp、kern、mail、lpr、mark、news、security、syslog、user、uucp、local0~ local7
举例:
mail.info /var/log/mail.log
auth.=info @10.1.1.1
user.!=error /var/log/user.log
*.info /var/log/log.info
第一行表示,mail用户的info级别的信息存放在/var/log/mail.log文件中;
第二行表示,auth(安全相关)用户的info级别的信息记录到服务器10.1.1.1上;前提是该服务器能接受到信息;
第三行表示,user用户非error级别的信息都存放在/var/log/user.log中;
第四行表示,任何用户的info级别的信息都存放在/var/log/log.info中;
读取log
syslogd中提供了很多种获取log 的方式,其中一种就是共享内存。当syslogd获取到log信息的时候,会通过log_to_shmem()将buf传入共享内存,用于其他的进程读取:
if (new_tail < G.shbuf->size) {
/* store message, set new tail */
memcpy(G.shbuf->data + old_tail, msg, len);
G.shbuf->tail = new_tail;
} else {
/* k == available buffer space ahead of old tail */
int k = G.shbuf->size - old_tail;
/* copy what fits to the end of buffer, and repeat */
memcpy(G.shbuf->data + old_tail, msg, k);
msg += k;
len -= k;
G.shbuf->tail = 0;
goto again;
}
在另外的进程中通过shmat进行获取:
/* Attach shared memory to our char* */
shbuf = shmat(log_shmid, NULL, SHM_RDONLY);
if (shbuf == NULL)
bb_perror_msg_and_die("can't %s syslogd buffer", "access");
将拿到的shbuf进行处理,例如输出到stdout中。
需要注意的是:syslogd中要求local和ipc是互斥的,所以想要log既能保存到本地log文件,又能通过共享内存方式读取,需要更改代码。
logread.c
在busybox中提供了通过共享内存方式进行读取log的程序logread.c,可以将syslogd共享内存中的log输出到stdout中。
将CONFIG_LOGREAD打开就可以编译出来,默认放置在sbin目录下,运行命令:
./sbin/logread –f