Sysklogd 系统日志记录器

概述

日志对于系统的重要性不言而喻,好比对于故障诊断和入侵检测,没有日志几乎步履维艰。Linux系统中常见的日志记录器是 Sysklogd ,当前最新版本是 1.5 。php

Sysklogd 日志记录器由两个守护进程(klogd syslogd)和一个配置文件(syslog.conf)组成。klogd 不使用配置文件,它负责截获内核消息,它既能够独立使用也能够做为 syslogd 的客户端运行。syslogd 默认使用 /etc/syslog.conf 做为配置文件,它负责截获应用程序消息,还能够截获 klogd 向其转发的内核消息。支持 internet/unix domain sockets 的特性使得这两个工具能够用于记录本地和远程的日志。linux

 

重要信息

  • syslogd 守护进程默认状况下并不从 syslog/udp 端口接受任何消息,除非在命令行上使用了"-r"选项。此外,你还应当仔细看看"-l"和"-s"命令行选项。
  • syslogd 守护进程默认状况下并不转发任何来自远程主机的消息,这是为了不可能致使的日志无限循环。"-h"选项能够开启转发功能。
  • syslogd 会剥除来自同一个域范围内的主机中的每条消息中的本地域(local domain)信息。若是你使用了日志分析程序,请将这一特性牢记在心。
  • syslogd 不会更改任何文件的属性,因此由它建立的文件将是全局可读的。若是你不想这样(好比"auth.*"被进行了记录),你必须手动事先建立这些文件并设置相应的权限。
  • 若是某些程序发送了大量的日志消息而且致使硬盘很是忙碌,你能够考虑在每一行后面关闭fsync()特性。不过这样可能会致使系统崩溃之后丢失一些日志消息。
  • 若是你使用 init 来直接启动 klogd 或 syslogd ,那么须要在命令行上使用"-n"选项。
  • 若是 System.map 文件存在而且在 klogd 命令行上使用了"-k"的话,那么它能够解码 EIP 地址。这个特性对于诊断系统崩溃很是有用,可是你必须确保 System.map 文件正确无误。
  • 这两个守护进程都会尝试在收到退出信号时删除他们的 .pid 文件,不过若是系统崩溃或者进程被"kill -9"结束,那么可能就会来不及清理。这样,下次启动时就有可能会得到与之前残留的 .pid 文件中的进程号相同的PID,从而致使没法启动(进程号冲突)。解决这个问题的最佳方案是系统的启动脚本(rc.*)自身可以在系统启动的最初就对这些 .pid 文件进行清理(一般是清空 /var/run 目录)。
  • 大文件支持(能够写入大于 2 GB 的日志)并非 syslogd 的功能,而是 glibc 的功能(使用不一样的内核API进行调用)。要启用大文件支持,你必须将 Makefile 中的相应注释取消(两个含有"-D_FILE_OFFSET_BITS"的行中的一个)。

内核的控制台日志等级

内核的控制台日志等级控制哪些内核消息会在控制台上显示。有两种途径能够修改这个等级,一种是经过内核引导参数,另外一种,也是建议的途径是经过 sysctl 来控制,一般这个设置位于 /etc/sysctl.conf 中。好比:shell

  kernel.printk = 4 4 1 7

[注意]控制台日志等级与内核消息等级是不一样的概念,默认的内核消息等级(DEFAULT_MESSAGE_LOGLEVEL)是由内核在编译时肯定的(CONFIG_DEFAULT_MESSAGE_LOGLEVEL),其默认值是"4"(WARNING)。而默认的控制台日志等级(DEFAULT_CONSOLE_LOGLEVEL)是"7"(debug),其含义是等级数字小于等于6的消息(优先级更高)都会显示在控制台上。缓存

安装注意事项

  1. 仔细阅读 README 和 man page 会减小你很多痛苦。目前全部文档都已经放在man page中了。
  2. 按照你的需求修改 Makefile 而后再进行编译。若是你没有认真对待第一步,那么可能会编译出不合格的二进制程序。
  3. FSSTND(Linux文件系统标准)要求二进制文件和其配置文件必须位于不一样的目录。这个包默认状况下遵照FSSTND的约定。你能够经过修改 Makefile 文件和源代码来修改配置文件的位置。
  4. 建议让这两个守护进程都以root身份运行,若是你想了解更多安全方面的问题,请阅读 man page 。

下面是 Makefile 文件开头的一部分节选,这部分是在安装前可能须要改动的:安全

CC= gcc
SKFLAGS= $(RPM_OPT_FLAGS) -O3 -DSYSV -fomit-frame-pointer -Wall -fno-strength-reduce
# 启用大文件支持,根据你的系统是32位仍是64位进行选择
# -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
# -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
# $(shell getconf LFS_SKFLAGS)
LDFLAGS= -s

# 指定 install 程序的位置
INSTALL = /usr/bin/install

# 安装目录
BINDIR = $(prefix)/usr/sbin
MANDIR = $(prefix)/usr/share/man

# 有bug报告说在一个纯 ELF 系统上须要明确指定链接到 libresolv.a 库。
# 若是你在链接 syslogd 时失败,能够试一试取消下面的注释。
# LIBS = /usr/lib/libresolv.a

# 若是你在 ALPHA 平台上链接失败,能够试一试取消下面的注释。
# LIBS = ${LIBS} -linux

# 取消下面的注释可让 klogd 实现启动延迟,这在 klogd 和 syslogd 并行启动或启动顺序靠的很是近的时候颇有用。
# KLOGD_START_DELAY = -DKLOGD_DELAY=5

# 下面的定义表示文件位置遵照FSSTND标准。
FSSTND = -DFSSTND

# 下面的定义指定了 man page 的宿主和权限。
MAN_USER = root
MAN_GROUP = root
MAN_PERMS = 644

# 下面的定义指定了 syslogd 守护进程的 .pid 文件名,
# 源代码(paths.h)中默认的文件名是"syslog.pid",但不少人认为应当叫"syslogd.pid"。
# 你能够在这里指定你喜欢的名字。
SYSLOGD_PIDNAME = -DSYSLOGD_PIDNAME=\"syslogd.pid\"

syslog.conf

syslog.conf 是 syslogd 进程的配置文件,将在程序启动时读取,默认位置是 /etc/syslog.conf 。它指定了一系列日志记录规则。规则的格式以下:服务器

facility.level    action

这个配置文件中的空白行和以"#"开头的行将被忽略。"facility.level"部分也被称为选择符(seletor)。 seletor 和 action 之间使用一个或多个空白分隔。dom

选择符(seletor)

选择符由 facility 和 level 两部分组成,之间用一个句点(.)链接。这两部分将在后面 syslogd 小节中详细描述。下面提到的名字和 /usr/include/syslog.h 中的 LOG_-values 相一致。ssh

facility 指定了产生日志的子系统,能够是下面的关键字之一:socket

auth		由 pam_pwdb 报告的认证活动。
authpriv	包括私有信息(如用户名)在内的认证活动
cron		与 cron 和 at 有关的信息。
daemon		与 inetd 守护进程有关的信息。
ftp		与 FTP 有关的信息
kern		内核信息,首先经过 klogd 传递。
lpr		与打印服务有关的信息。
mail		与电子邮件有关的信息
mark		syslog 内部功能用于生成时间戳
news		来自新闻服务器的信息
syslog		由 syslog 生成的信息
user		由用户程序生成的信息
uucp		由 uucp 生成的信息
local0 ~ local7	由自定义程序使用,例如使用 local5 作为 ssh 功能
*		通配符表明除了 mark 之外的全部功能

在大多数状况下,任何程序均可以经过任何 facility 发送日志消息,可是通常都遵照约定俗成的规则。好比,只有内核才能使用"kern" facility 。tcp

level 指定了消息的优先级,能够是下面的关键字之一(降序排列,严重性愈来愈低):

emerg	系统不可用
alert	须要当即被修改的条件
crit	阻止某些工具或子系统功能实现的错误条件
err	阻止工具或某些子系统部分功能实现的错误条件
warning	预警信息
notice	具备重要性的普通条件
info	提供信息的消息
debug	不包含函数条件或问题的其余信息
none	没有优先级,一般用于排错
*	除了none以外的全部级别

facility 部分能够是用逗号(,)分隔的多个子系统,而多个 seletor 之间也能够经过分号(;)组合在一块儿。须要注意的是,多个组合在一块儿的选择符,后面的会覆盖前面的,这样就容许从模式中排除一些优先级。

默认将对指定级别以及更严重级别的消息进行操做,可是能够经过下面2个操做符进行修改。

等于操做符(=)表示仅对这个级别的消息进行操做,不等操做符(!)表示忽略这个级别以及更严重级别的消息。这两个操做符能够同时使用,不过"!"必须出如今"="的前面。

动做(action)

这个字段定义了对符合条件的消息进行何种操做,能够选择下列操做之一:

普通文件
将消息记录到这个文件中,必须使用绝对路径。若是在文件名以前加上减号(-),则表示不将日志信息同步刷新到磁盘上(也就是使用写入缓存),这样能够提升日志写入性能,可是增长了系统崩溃后丢失日志的风险。
命名管道
在绝对路径表示的FIFO文件(使用mkfifo命令建立)前加上管道符号(|)便可。一般用于调试。好比:|/usr/adm/debug
终端或者控制台
好比:/dev/tty1 或 /dev/console
远程主机
syslogd 可以将消息发送到远程主机或从远程主机接收消息,不过默认并不转发接收到的消息。要将消息发送到远程主机,能够在主机名前加一个"@"便可。
逗号分隔的用户名列表
critical 级别的消息除了记录到日志以外,一般还转发到root用户。
全部当前登陆的用户
若是写上一个星号(*)则表示向当前全部登陆的用户显示这条消息。

实例

下面的例子来自于实践,但愿可以对上面的内容作一个很好的示范以帮助理解。

              # 将全部 crit 级别的消息(排除全部内核消息)记录在 critical 文件中
              #
              *.=crit;kern.none            /var/adm/critical

              # 首先记录全部内核消息到 kernel 文件,
              # crit 级别以上的消息转发到远程同时在本地控制台也显示
              # 最后将info(包含)~err(不含)范围的内核消息记录到kernel-info文件(err和更高的级别被忽略)
              #
              kern.*                       /var/adm/kernel
              kern.crit                    @finlandia
              kern.crit                    /dev/console
              kern.info;kern.!err          /var/adm/kernel-info

              # 将刚好等于mail.info的消息显示在第12个终端(tcpd默认使用mail.info)
              #
              mail.=info                   /dev/tty12

              # 将除mail.info以外的全部mail子系统消息记录到mail文件
              #
              mail.*;mail.!=info           /var/adm/mail

              # 将全部mail.info和news.info消息记录到info文件
              #
              mail,news.=info              /var/adm/info

              # 记录全部info和notice级别的消息,来自mail子系统的除外
              #
              *.=info;*.=notice;mail.none  /var/log/messages

              # 记录全部info级别的消息,来自mail和news子系统的除外
              #
              *.=info;mail,news.none       /var/log/messages

              # 向全部登陆用户通知emerg级别的消息
              #
              *.=emerg                     *

              # 将全部alert以及更高级别的消息转发到root,joey用户的终端上(若是他们已经登陆)
              #
              *.alert                      root,joey

              # 将全部子系统的全部消息都发送到远程名为"finlandia"的主机
              *.*                          @finlandia

syslogd

syslogd 默认经过 /dev/log 这个 unix domain socket 来接收应用程序发送过来的消息,这个位置是由系统的基本C库决定的。

这个程序的命令行参数以下:

syslogd  [ -a socket ] [ -f config-file ] [ -h ] [ -l hostlist ] [ -m interval ]
           [ -n ] [ -p socket ] [ -r ] [ -s domainlist ] [ -v ]

参数说明:

-a socket
指定额外须要监听的 socket ,最多指定19个,能够经过修改 syslogd.c 文件中的 MAXFUNIX 宏修改这个默认值。若是你将某些进程在chroot环境下运行,那么这个选项就颇有用了。
-f config-file
指定配置文件的位置,默认是 /etc/syslog.conf 。
-h
默认状况下 syslogd 并不转发它接收到的远程主机消息。指定这个选项后,进程将会把它接收到的远程主机消息转发到另外一个指定的远程主机。
-l hostlist
指定一个分号(:)分隔的主机名列表,只记录这些主机的 hostname 而不是全限定域名。
-m interval
syslogd 默认每隔20分钟产生一个时间戳标记(-- MARK --)。这个选项用于修改这个默认值。设为零将关闭这个特性。
-n
避免自动做为后台进程运行。若是由 init 来直接启动和控制的话这个选项就必须使用。
-p socket
你能够指定一个 unix domain socket 来代替默认的 /dev/log [这个位置是由libc决定的]
-r
从 internet domain socket 上接收远程消息,也就是监遵从514端口上进来的UDP包。 默认不接受任何远程消息。
-s domainlist
指定一个分号(:)分隔的域名列表,这些域名在记录前都会被剥除。只能指定完整的域名。好比"-s north.de"并不会剥除"satu.infodrom.north.de"的尾巴,你必须这样写才行:
-s north.de:infodrom.north.de
-v
打印版本信息后退出。

信号

在运行时,syslogd 会将本身的进程号保存在 /var/run/syslogd.pid 文件中。因此可使用下面的命令向运行中的进程发送信号:

 kill -信号 `cat /var/run/syslogd.pid`
HUP
使得 syslogd 进程从新初始化。全部打开的文件都会被关闭,而后从新读取配置文件,从新开始记录。
TERM
安全退出
CHLD
若是当前正在向全部登陆的用户发送消息,那么等待这些子进程结束。

安全问题

流氓程序能够经过向 syslogd 进程发送大量日志信息来淹没日志文件或者耗尽磁盘空间。下面是一些建议:

  1. 经过防火墙来限制仅容许某些特定的主机访问 514/UDP socket
  2. 将日志文件放在独立的分区上,这样即便磁盘满了也不会有很大的影响。
  3. ext2文件系统能够保留必定的空间仅给root用户使用。这要求将 syslogd 以非root身份运行。
  4. 禁止监听 inet domain sockets 将会减小很多风险。

相关文件

/etc/syslog.conf
syslogd的配置文件
/dev/log
默认将从这个 Unix domain socket 读取本地 syslog 消息
/var/run/syslogd.pid
包含 syslogd 进程号的文件

klogd

klogd 是一个专门截获并记录 Linux 内核消息的守护进程。其命令行语法以下:

klogd  [ -f file ] [ -iI ] [ -n ] [ -o ] [ -p ] [ -s ] [ -k file ] [ -v ] [ -x ] [ -2 ]

命令行参数说明:

-f file
将日志直接记录到指定的file中,而不是转发到 syslogd 进程。
-i
-I
要求当前正在运行的 klogd 守护进程从新装载内核符号表。
-i 用于让守护进程从新装载内核模块符号。
-I 用于让守护进程从新装载静态内核符号和内核模块符号。
-n
禁止自动后台运行,在 klogd 由 init 启动并直接被 init 控制的状况下必须使用此开关。
-o
klogd 在读取并记录全部内核消息缓冲区中的消息以后当即退出(不做为守护进程)。
-p
只要 klogd 检测到内核消息流中包含了一个 Oops 字符串,那么就从新加载内核符号表。
-s
能够经过两个途径获取内核消息: /proc 文件系统和 sys_syslog 系统调用接口。虽然二者本质上彻底等价,但 klogd 会优先使用 /proc/kmsg 文件。这个开关则强制 klogd 使用系统调用获取内核消息。
-k file
将指定的 file 做为内核符号表文件,也就是System.map文件的位置。
-v
打印版本信息后退出。
-x
忽略 EIP 转换信息,这样就不须要读取 System.map 文件。
-2
当展开符号时打印两行,一行将地址转换为符号,一行是原始文本。这样就容许一些外部程序(好比ksymoops)在原始数据上作一些处理。

消息转发

若是 klogd 将内核消息转发给 syslogd 进程,那么它能够分拣出某些特定的消息。原始内核消息的格式以下:

    <[0-7]>Something said by the kernel.

尖括号中的数字表示内核消息的优先级,这些数字的定义位于 kernel.h 文件中。当 klogd 收到内核消息以后,将会读取这个数字,并在将此消息转发给 syslogd 时按照这个数字分配适当的优先级。

若是使用 -f 将内核消息直接记录到特定的文件中,那么这条消息将保持原样。

内核地址解析

klogd 会尝试将内核地址解析为对应的符号,若是你想获得原始的地址信息,那么可使用"-2"开关。若是没有使用"-k"选项,那么将会依次尝试下面的路径:

       /boot/System.map
       /System.map
       /usr/src/linux/System.map

由于内核模块动态加载因此地址并不固定,这时就要使用"-i"/"-I"通知 klogd 内核模块的变化。这两个开关都将致使当前正在运行的 klogd 守护进程从新加载内核符号表。应当在每一次加载或者卸载内核模块后当即运行下列命令:

       klogd -i

-p 开关也能够用于更新内核符号表。它会让 klogd 在检测到保护性错误的时候从新加载内核符号表。使用这个开关须要当心,由于操做系统在出现保护性错误(protection fault)的时候已经变得不稳定了,而 klogd 必须执行系统调用才能从新装载内核符号表,因此这样作可能会致使更糟糕的结果。

控制台日志等级

内核默认的控制台日志等级(DEFAULT_CONSOLE_LOGLEVEL)是"7"(debug),也就是等级数字小于等于6的消息(优先级更高)都会显示在控制台上。这些不一样等级所表明的意思位于 kernel.h 文件内,这个包内的 syslog.h 中也有一份拷贝。可使用 sysctl 来指定控制台日志等级,这一般是在 /etc/sysctl.conf 文件中设置的,好比下面这一行:

              kernel.printk = 4 4 1 7

就是把内核的控制台日志等级设为了"4"。

信号处理

klogd 能够响应8种信号: SIGHUP, SIGINT, SIGKILL, SIGTERM, SIGTSTP, SIGUSR1, SIGUSR2, SIGCONT 。SIGINT, SIGKILL, SIGTERM, SIGHUP 信号会让进程优雅的正常退出。SIGTSTP 信号会让进程中止记录日志并进入休眠状态;SIGCONT 信号会让处于休眠状态的进程从新开始记录日志。组合使用 SIGSTOP 和 SIGCONT 能够在不退出进程的状况下切换日志消息的来源。好比须要卸载 /proc 文件系统的时候,可使用下面的命令:

            # kill -TSTP pid
            # umount /proc
            # kill -CONT pid

SIGUSR1 和 SIGUSR2 用于加载/从新加载内核符号表。SIGUSR1 表示从新加载内核模块的符号信息;SIGUSR2 表示同时从新加载模块和静态内核的符号信息。若是 System.map 文件位置正确,那么 SIGUSR1 信号将很是有用。特别是在内核模块改变的时候。

相关文件

/proc/kmsg
klogd 默认首选的获取内核消息的来源
/var/run/klogd.pid
保存 klogd 的 PID 的文件
/boot/System.map, /System.map, /usr/src/linux/System.map
默认搜索的内核符号表位置
相关文章
相关标签/搜索