开发项目中遇到这个syslog的东西,稍微研究了一下,总结出一份心得,皮毛浅薄之作,错误之处欢迎斧正。

顾名思义,syslog就是系统日志的意思,关于它的出身我就不讲了,wiki一下,你就知道。这里我只举个例子,我们在写程序的时候,应该大都会遇到需要记录日志的场景。这时候一个比较直接的做法,就是将信息按照一定的格式(如时间、事件类型及严重程度、发生位置、详情等)写入到文件中,这种方式虽然具有更高的自由度,形式格式都可以自由发挥,然而无规矩不成方圆,计算机科学界也是如此,从各种协议到各种接口,无不系统化、国际化。否则大家各自搞一套,自成一家,相互之间没法通用和沟通,这样就不美了(扯远了)。


同理,系统中存在着很多的服务,如内核、网络、数据库等,如果它们有着各自的方式记录日志,那么对于我们开发/运维人员,要排查问题,必须先了解每个服务的日志格式,毫无疑问这太痛苦了。因此,syslog应运而生。


其实,syslog只是一个广义的概念,并不是一个实物,其具体的实物,是linux中一个叫做syslogd的东西,你可以称它为syslog服务器。它其实是一个服务进程,任何想要使用syslog记录日志的程序,都必须和它交互,然后由它来完成日志的记录。比如最常见的,我们使用一个普通用户(名为haha),来执行一个sudo的操作:


$sudo mkdir /U_are_FOOL

会得到一个反馈信息:

"haha is not in the sudoers file.  This incident will be reported."


信息中该提示事件会被report。会被report到哪里呢?其实就是会利用syslog记录到日志文件中。




好了,那么我们在写自己的程序时,如何也利用syslog,将其写入到系统的日志中呢?其实很简单,遵循三步走战略:打开-写入-关闭.对应三个函数:openlog()-syslog()-closelog().下面一一讲解。



openlog()
		原型:void openlog(const char *ident, int option, int facility);
		参数: ident -- 为你的程序产生的消息命名,该串会添加到log的前面。
				option -- 记录的选项,可取:
					LOG_PID:在每条log中加入此进程的pid,pid用"[]"扩起来。
					LOG_CONS: 如果消息不能被记录到日志文件,则输出到控制台。
					LOG_ODELAY: open-delay,即延迟打开日志功能,调syslog()时再打开。
					LOG_NDELAY: open-no-delay,与上面对应,立即打开。
					另外还有两个不重要的:
						LOG_NOWAIT: 在记录时不必等待子进程创建完毕,此函数在linux中无效,因为linux的gnu C库不会创建子进程。.
						LOG_PERROR: 加了此参数,在记录的同时,也会输出到stderr(不知道stderr的童鞋请Google)
					上面的值可取多个,通过或运算来达到目的,如 "LOG_PID|LOG_ODELAY"
				facility -- 直译就是"设备",类型不同我们可以归为不同类型的进程,如用户进程、守护进程、认证系统进程等等,它的取值也有如下:
					LOG_AUTH:认证系统:login、su、getty等
					LOG_AUTHPRIV:同LOG_AUTH,但只登录到所选择的单个用户可读的文件中
					LOG_CRON:cron守护进程
					LOG_DAEMON:其他系统守护进程,如routed
					LOG_FTP:文件传输协议:ftpd、tftpd
					LOG_KERN:内核产生的消息
					LOG_LPR:系统打印机缓冲池:lpr、lpd
					LOG_MAIL:电子邮件系统
					LOG_NEWS:网络新闻系统
					LOG_SYSLOG:由syslogd(8)产生的内部消息
					LOG_USER:随机用户进程产生的消息
					LOG_UUCP:UUCP子系统
					LOG_LOCAL0~LOG_LOCAL7:为本地使用保留
					如果暂时不理解,没关系,下面会有例子,转回头来再看就清晰多了。
	syslog()
		原型:void syslog(int priority, const char *format, ...);
		参数: priority -- 优先级,可以取下列值之一:
					LOG_EMERG:紧急情况,需要立即通知技术人员。
					LOG_ALERT:应该被立即改正的问题,如系统数据库被破坏,ISP连接丢失。
					LOG_CRIT:重要情况,如硬盘错误,备用连接丢失。
					LOG_ERR:错误,不是非常紧急,在一定时间内修复即可。
					LOG_WARNING:警告信息,不是错误,比如系统磁盘使用了85%等。
					LOG_NOTICE:不是错误情况,也不需要立即处理。
					LOG_INFO:情报信息,正常的系统消息,比如骚扰报告,带宽数据等,不需要处理。
					LOG_DEBUG:包含详细的开发情报的信息,通常只在调试一个程序时使用。
					从上到下优先级依次降低,syslog会记录大于等于你所指定的优先级的日志,如你指定LOG_ERR,那么(LOG_EMERG,LOG_ALERT,LOG_CRIT,LOG_ERR)这四项类型的日志都会被记录.
					针对这种严重级别,syslogd会根据配置进行不同的处理,比如LOG_EMERG可能会广播给所有用户,LOG_ALERT可能发送给管理员,LOG_DEBUG可能会被忽略,其他的则可能只是记录在日志文件之中。
			format,... -- 这个参数我就不多说了吧,如果你知道printf的原型、会用printf,那么这个就不难理解,否则,请"$man 3 printf"查看手册去吧.
			
			
	closelog()
		原型: void closelog(void);
			这个没什么好讲的,记录完成后关闭就可以了。







例1:下面是一个简单的小例子:


#include <syslog.h>

	int main(int argc, char *argv[])
	{
		char *log = "Hello world";
		int num = 100;
		
		openlog("kyle", LOG_PID, LOG_DAEMON); /*使用LOG_DAEMON*/
		syslog(LOG_INFO, "%s%d", log, num);
		closelog();
		
		return 0;
	}






编译运行.


我的是ubuntu12.04,所以我的LOG_DAEMON输出目录为 /var/log/syslog,我们使用事先设置的标志'kyle'来筛选查看:


$ cat /var/log/syslog | grep kyle\\[



可以看到如下输出:


Oct 16 15:33:11 Edge1-12-04 kyle[4709]: Hello world100




例2:稍微修改一下程序,将LOG_DAEMON改为认证系统LOG_AUTH:


#include <syslog.h>

	int main(int argc, char *argv[])
	{
		char *log = "Hello world";
		int num = 200; /* 为了区别上次的记录,这里改为200 */
		
		openlog("kyle", LOG_PID, LOG_AUTH); /*LOG_AUTH*/
		syslog(LOG_INFO, "%s%d", log, num);
		closelog();
		
		return 0;
	}




此时查看 /var/log/syslog,并没有"Hello world200"的日志输出,但是查看另个文件/var/log/auth.log:


$cat /var/log/auth.log | grep kyle\\[


可以得到如下输出:


Oct 16 15:39:14 Edge1-12-04 kyle[4728]: Hello world200


这才知道,原来设备(进程)类型不同,输出的log目录也不尽相同。


那么一个问题就产生了,我怎么知道这不同类型的设备(进程),各自输出到那个log呢?


答案很简单,其实有个conf配置文件,Ubuntu12.04下,在/etc/rsyslog.d/50-default.conf中,里面有一行:


auth,authpriv.*                 /var/log/auth.log


可以看出,关于auth的日志,都输出在auth.log里了,验证了例2。


还有:


*.*;auth,authpriv.none          -/var/log/syslog


*.*表示了所有的log(如无特别指定则)默认输出到/var/log/syslog中。这正验证了例1。




大致的理解就是这些。


对于centos,据说其配置应该在/etc/syslog.conf,这里没有亲自尝试,就不献丑了。