linux日志:syslogd和klogd及syslog

Syslog是一个通过IP网络允许一台机器发送事件通知信息给事件收集者(Syslog服务器或者Syslog Daemon)的协议。换言之,就是一台机器或者设备能够被配置,使之产生Syslog信息并且发送到一台特定的Syslog服务器/Daemon。
Syslog信息建立在UDP之上,一般Syslog信息在UDP514端口上被收集,Syslog信息的长度不大于1024字节。由于基于UDP协议,所以当如果因为网络拥塞等情况导致信息包丢失,那么信息将不再重发,而是简单的丢失掉。之后RF3195又增加了TCP514端口。

tftpd64.exe集成多种协议,其中包含syslog(UDP514端口)服务,可接收日志。

零. 日志格式

syslog协议支持RFC3164和RFC5424。

RFC3164协议手册   

Syslog-ng与Syslog协议与之数据格式RFC5424、 RFC3164详解

// RFC3164
<PRI>HEADER MESSAGE
<15>Jul 10 12:00:00 192.168.1.1 SyslogGen MESSAGE 

// RFC5424
<PRI>VERSION TIMESTAMP HOSTNAME APP-NAME PROCID MSGID
<34>1 2003-10-11T22:14:15.003Z mymachine.example.com su - ID47
- BOM'su root' failed for lonvick on /dev/pts/8
<165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1
 myproc 8710 - - %% It's time to make the do-nuts.

PRI:即Priority(优先级),有效值范围为0 - 191。不能有空格、数字前也不能补0。合法的形式如:<15>。PRI值包含两部分信息:Facility和Level。其中Facility值用于判断哪个程序产生了日志信息。Level值用于判断严重等级。计算方法:PRI = Facility * 8 + Level。只有一种情况,当0跟着<时,表示优先级为0。其他情况,不能以0开头

  

一. 日志守护进程

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的特性使得这两个工具可以用于记录本地和远程的日志。

二.日志目录

Linux系统日志一般保存在/var/log下,其中一些只有特定版本才用,如dpkg.log只在基于Debian的系统中有。

/var/log/messages或/var/log/syslog   — 包括整体系统信息,其中也包含系统启动期间的日志。此外,mail,cron,daemon,kern和auth等内容也记录在var/log/messages日志中。
/var/log/dmesg             — 包含内核缓冲信息(kernel ring buffer)。在系统启动时,会在屏幕上显示许多与硬件有关的信息。可以用dmesg查看它们。
/var/log/auth.log          — 包含系统授权信息,包括用户登录和使用的权限机制等。
/var/log/boot.log          — 包含系统启动时的日志。
/var/log/daemon.log        — 包含各种系统后台守护进程日志信息。
/var/log/dpkg.log          — 包括安装或dpkg命令清除软件包的日志。
/var/log/kern.log          — 包含内核产生的日志,有助于在定制内核时解决问题。
/var/log/lastlog           — 记录所有用户的最近信息。这不是一个ASCII文件,因此需要用lastlog命令查看内容。
/var/log/maillog 与 /var/log/mail.log — 包含来着系统运行电子邮件服务器的日志信息。例如,sendmail日志信息就全部送到这个文件中。
/var/log/user.log         — 记录所有等级用户信息的日志。
/var/log/Xorg.x.log       — 来自X的日志信息。
/var/log/alternatives.log — 更新替代信息都记录在这个文件中。
/var/log/btmp             — 记录所有失败登录信息。使用last命令可以查看btmp文件。例如,last -f /var/log/btmp | more 。
/var/log/cups             — 涉及所有打印信息的日志。
/var/log/anaconda.log     — 在安装Linux时,所有安装信息都储存在这个文件中。
/var/log/yum.log          — 包含使用yum安装的软件包信息。
/var/log/cron             — 每当cron进程开始一个工作时,就会将相关信息记录在这个文件中。
/var/log/secure            — 包含验证和授权方面信息。例如,sshd会将所有信息记录(其中包括失败登录)在这里。
/var/log/wtmp或/var/log/utmp — 包含登录信息。使用wtmp可以找出谁正在登陆进入系统,谁使用命令显示这个文件或信息等。
/var/log/faillog            —包含用户登录失败信息。此外,错误登录命令也会记录在本文件中。

除了手动存档和清除这些日志文件以外,还可以使用logrotate在文件达到一定大小后自动删除。可以尝试用vi,tail,grep和less等命令查看这些日志文件。

tail -F /var/log/messages

三. 日志应用编程

 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)

四. 日志循环

linux日志一般会按一定的规则进行循环,保证日志量控制在一定的范围内。

日志循环的原理一般是:在特定的时间点,或日志达到一定大小,就触发循环脚本。

循环脚本通过新增新日志,备份老日志,调度应用重新加载配置(重新写日志)达到日志循环的目的。

1. 手工创建脚本实现

通过脚本执行的日志循环,常见的方法一般分为有损循环和无损循环两种形式。

以nginx日志循环为例,nginx作为常用的代理转发服务器,每天承载上万级甚至百万级的量,正常情况下几天就可能把100G的磁盘打满。

据了解,nginx没有内置的日志循环配置(apache好像有)。

1.1 有损循坏

直接清理日志

cp /usr/local/nginx/logs/access.log /usr/local/nginx/logs/access_$(date -d '-1day' '+%Y-%m-%d').log
echo > /usr/local/nginx/logs/access.log

配合定时任务

0 0 * * * cp /usr/local/nginx/logs/access.log /usr/local/nginx/logs/access.log.1 && echo > /usr/local/nginx/logs/access.log

该方法通过cp+echo的方式到达日志循环的效果。

好处是:

  • 简单地把日志置空,可以达到快速清理日志的效果
  • 历史日志通过cp进行了备份
  • echo置空相比笨方法(停止nginx,rm日志,启动nginx)快很多,当日志到达GB级别,效果更明显,nginx也无需重启

坏处是:

  • 日志过大时,cp时间过长
  • 日志短时间需要占用size*2的磁盘容量

之所以称之为有损循环,是因为echo >命令执行时,nginx工作进程依然在打印日志,这时候会出现两种可能:

  1. 0时0分前几秒的日志被清除了,丢了部分日志;
  2. nginx工作进程无法写入日志,进程报错甚至挂掉。

因此,不推荐使用该方法

1.2 无损循环

crontab设置

crontab -e

0 0 * * * /data/op_shell/nginx_log_division.sh

nginx_log_division.sh

#!/bin/bash
#设置日志文件存放目录  
logs_path="/usr/local/nginx/logs/"  
#设置pid文件(也有可能在/var/run中)
pid_path="/usr/local/nginx/logs/nginx.pid"  
#日志文件
filepath=${logs_path}"access.log"  
#重命名日志文件  
mv ${logs_path}access.log ${logs_path}access_$(date -d '-1 day' '   +%Y-%m-%d'.log  
#向nginx主进程发信号重新打开日志  
kill -USR1 `cat ${pid_path}`  

该方法通过mv+kill的方式进行日志循环,因为linux中,日志打开底层原理是通过inode信息寻址找到对应的block进行内容读取,mv操作不改变文件的inode值。

首先日志mv重命名,期间nginx依然打印日志到重命名的文件中,通过kill向nginx master进程发送信号,nginx重新读取配置文件,触发新的access日志重新打印。


两种方法存在以下问题:

  1. 循环保存的日志,需要再通过crontab任务清理,例如只保留最新7天的日志;
  2. 日志如果按size循环,需要重新编写脚本。

2. logrotate循环

logrotate是一个日志循环的工具,linux内置的syslog也是使用它进行日志循环。

logrotate的配置存放于/etc/logrotate.d

[root@zero /etc/logrotate.d]# ll /etc/logrotate.d/
total 32
-rw-r--r-- 1 root root 289 Jun 22  2016 conman
-rw-r--r-- 1 root root 194 Jul 18  2016 httpd
-rw-r--r-- 1 root root 136 Jun 22  2016 iptraf-ng
-rw-r--r-- 1 root root 893 Aug 12  2016 mariadb
-rw-r--r-- 1 root root 140 Oct 23  2014 mgetty
-rw-r--r-- 1 root root 409 Jun 22  2016 psacct
-rw-r--r-- 1 root root 224 Nov  5  2016 syslog
-rw-r--r-- 1 root root 100 Oct 12  2017 yum

添加nginx配置

/data/log/nginx/*log {
    hourly
    rotate 5
    missingok
    notifempty
    nocompress
    sharedscripts
    postrotate
        [ -f /data/log/nginx/nginx.pid ] && kill -USR1 `cat /data/log/nginxnginx.pid`
    endscript
}

五. 常用日志服务syslog、syslog-ng、rsyslog、zlog、aliyun日志服务

zlog:zlog的安装与使用   zlog使用手册http://hardysimpson.github.io/zlog/UsersGuide-CN.html

rsyslog:用RSYSLOG进行加密传输#2

syslog和syslog-ng详解

aliyun日志服务:使用Syslog协议上传日志   SDK

Syslog项目是第一个项目,始于1980年,它是Syslog协议的根项目。此时Syslog是一个非常简单的协议。一开始它只支持UDP进行传输,因此它不保证消息的传递。

接下来是1998年的syslog-ng,它扩展了基本的syslog协议,具有以下新功能:

>基于内容的过滤
>直接登录数据库
> TCP用于传输
> TLS加密

接下来是2004年的Rsyslog,它扩展了syslog协议,具有以下新功能:

> RELP协议支持
>缓冲操作支持
 

参考:

1. http://blog.csdn.net/dog250/article/details/5707979  syslog的点滴--集中处理日志

2. http://www.360doc.com/content/13/0102/10/7775902_257612487.shtml

3. sysLog 服务器端及客户端配置

4. 【协议分析】Syslog协议介绍

5. 嵌入式系统中使用远程syslog进行调试与诊断

6. linux日志循环

7. 浅谈Linux下的syslog守护进程

8. 搭建rsyslog日志服务器

posted @ 2016-02-19 15:22  yuxi_o  阅读(7250)  评论(0编辑  收藏  举报