一前言
对于程序员来说,排查问题最重要的方式之一就是记录日志和查看日志了。日志就像系统的化验单,程序员就是医生,根据化验单,对症下药;特别是在系统在客户现场出现问题的时候,现场维护同事咨询问题的时候,提供一份详细的"化验单" 就非常重要。所以维护做的好一点的,一般都有日志分析系统,或在出现故障时候,可以从系统中导出关键日志,发送给程序员,完整的日志,便于快速对系统进行把脉、开出药方。
相对我们对自己开发的系统日志的重视程度来说,我们对OS的日志重视程度一般都不太够的。因为对系统日志的研究好像没有那么高的能效比,导致一旦操作系统出现问题,通过系统日志排查的方式来解决问题的,反而比较少; 除了记录几个必要的查看系统日志的命令外,对整个系统的日志架构缺少认识,(主要说像我这样的程序员),有时候排查系统问题没有找到合适的日志比较抓瞎,事倍而功半,有力无处使的感觉。这时才觉得对自己操作系统了解的只是内核方面的,反而使用方面的了解的更少,追求高深的东西,忽略了基本的应用。
由于我们系统跑在Centos 7/8 下,所以以这个系统为准来介绍下Centos下的日志分布和管理。
二 系统日志说明
上述日志和命令都是比较重要的,其他像 /var/log/httpd/* 、/var/log/samba/* 这些日志为应用日志,不在我们讨论之中了。 重点说明:utmpdump /var/log/wtmp这个命令特别重要,如果怀疑被攻击了,通过这个命令看看有没有可疑IP过来的登录账号。 简单结合写,写个脚本,查询登录用户的归属地:
#!/bin/bash
utmpdump /var/log/wtmp | awk -F '[][]' '{if ($8 != "") print $14}'|grep -v '0.0.0.0' |sort |uniq > ./ip_list.txt
while read ip; do
echo $ip $(curl -s http://ip-api.com/json/$ip | jq -r '"\(.country) \(.region) \(.city)"')
done < ip_list.txt
观察下,如果非你所在地登录的就注意是不是被攻破了,可以将ip加入到/etc/host.deny中禁止登录。
三 日志管理者
Centos下有三个主要的服务:
systemd-journald.service: 最主要的信息记录者、由systemd提供
rsyslog.service :收集登录信息和网络等服务信息;
logrotate:主要是轮转日志;
3.1 systemd-journald
系统启动的时候,会先启动systemd,然后它会主动调用systemd-journald来记录启动过程中的信息、以及后续systemd管理的服务信息。 systemd-journald 默认将日志记录在内存中,不会保存,当然可以配置长久保存,也可以发送给rsyslog来保存。 查看启动情况:
root@iZwz97vcvjlst5yp9ifxzvZ ~]# systemctl status systemd-journald
● systemd-journald.service - Journal Service
Loaded: loaded (/usr/lib/systemd/system/systemd-journald.service; static; vendor preset: disabled)
Active: active (running) since Wed 2024-01-03 09:22:23 CST; 2 months 20 days ago
Docs: man:systemd-journald.service(8)
man:journald.conf(5)
Main PID: 616 (systemd-journal)
Status: "Processing requests..."
Tasks: 1 (limit: 47107)
Memory: 95.6M
CGroup: /system.slice/systemd-journald.
└─616 /usr/lib/systemd/systemd-journald
那如何将其日志内容长久保存那:
# ①新建目录保存日志
mkdir /var/log/journal
chmod 2775 /var/log/journal
# ② 编辑配置
vim /etc/systemd/journald.conf
// 将Storage 配置为:persistent
[Journal]
Storage=persistent
[...]
# ③重启服务
systemctl restart systemd-journald
#其他 更改日志大小:SystemMaxUse=50M
#其他 转发到syslog: ForwardToSyslog=yes
#临时持久化
sudo mkdir /var/log/journal
sudo systemd-tmpfiles --create --prefix=/var/log/journal
sudo journalctl --flush
在centos8 下,这个日志默认保存的,Storage默认配置为auto;
Systemd-journald的日志是二进制格式的,如何查看,我们有特定的命令:journalctl,这个命令我以前用的时候,时常记不住名字,后来分解了下: jour-nal-ctl这样好记多了。
journalctl常用法:
实用命令 显示最新10条crontab的日志:
[root@iZwz97vcvjlst5yp9ifxzvZ ~]# journalctl _SYSTEMD_UNIT=crond.service -n 10
-- Logs begin at Tue 2024-01-16 22:20:48 CST, end at Sun 2024-03-24 15:20:09 CST. --
3月 24 06:01:01 iZwz97vcvjlst5yp9ifxzvZ CROND[322862]: (root) CMD (run-parts /etc/cron.hourly)
3月 24 07:01:01 iZwz97vcvjlst5yp9ifxzvZ CROND[323794]: (root) CMD (run-parts /etc/cron.hourly)
3月 24 08:01:01 iZwz97vcvjlst5yp9ifxzvZ CROND[324721]: (root) CMD (run-parts /etc/cron.hourly)
3月 24 09:01:01 iZwz97vcvjlst5yp9ifxzvZ CROND[325647]: (root) CMD (run-parts /etc/cron.hourly)
3月 24 10:01:01 iZwz97vcvjlst5yp9ifxzvZ CROND[326581]: (root) CMD (run-parts /etc/cron.hourly)
3月 24 11:01:01 iZwz97vcvjlst5yp9ifxzvZ CROND[327549]: (root) CMD (run-parts /etc/cron.hourly)
3月 24 12:01:01 iZwz97vcvjlst5yp9ifxzvZ CROND[328557]: (root) CMD (run-parts /etc/cron.hourly)
3月 24 13:01:01 iZwz97vcvjlst5yp9ifxzvZ CROND[332059]: (root) CMD (run-parts /etc/cron.hourly)
3月 24 14:01:01 iZwz97vcvjlst5yp9ifxzvZ CROND[332990]: (root) CMD (run-parts /etc/cron.hourly)
3月 24 15:01:01 iZwz97vcvjlst5yp9ifxzvZ CROND[334006]: (root) CMD (run-parts /etc/cron.hourly
显示最近10条登录或切换用户的日志:
[root@iZwz97vcvjlst5yp9ifxzvZ ~]# journalctl _COMM=su _COMM=login -n 10
-- Logs begin at Tue 2024-01-16 22:20:48 CST, end at Sun 2024-03-24 15:20:09 CST. --
3月 02 23:13:15 iZwz97vcvjlst5yp9ifxzvZ login[2956272]: pam_unix(remote:auth): authentication failure; logname= uid=0 euid=0 tty=pts/9 ruser= rhost=230.239.212.222.broad.cd.sc.dynamic.163data>
3月 02 23:13:24 iZwz97vcvjlst5yp9ifxzvZ login[2956272]: FAILED LOGIN 1 FROM 230.239.212.222.broad.cd.sc.dynamic.163data.com.cn FOR root, Authentication failure
3月 02 23:13:58 iZwz97vcvjlst5yp9ifxzvZ login[2956305]: pam_unix(remote:session): session opened for user root by (uid=0)
3月 02 23:14:03 iZwz97vcvjlst5yp9ifxzvZ login[2956305]: ROOT LOGIN ON pts/9 FROM 230.239.212.222.broad.cd.sc.dynamic.163data.com.cn
3月 03 04:02:21 iZwz97vcvjlst5yp9ifxzvZ login[2955970]: pam_unix(remote:session): session closed for user root
3.2 日志记录者logger
我们如何将日志记录主动记录系统日志,通过logger可以办到,这在我们写脚本的时候,不想单独记录日志文件可以用这个办法。 主要还可以向远程发送syslog日志,包括tcp或udp方法。 具体命令帮助查看:https://www.unix.com/man-page/centos/1/logger/
简单形式:
logger [-p 工具名.等级] [-t 标识] [-i (会记录进程id] 日志信息
举例:
logger -p user.notice -t MYAPP -i "this is a test message"
[root@iZwz97vcvjlst5yp9ifxzvZ ~]# logger -p user.notice -t MYAPP -i "this is a test message"
[root@iZwz97vcvjlst5yp9ifxzvZ ~]# journalctl -n 5
-- Logs begin at Tue 2024-01-16 22:20:48 CST, end at Sun 2024-03-24 15:41:24 CST. --
3月 24 15:30:09 iZwz97vcvjlst5yp9ifxzvZ systemd[1]: Started system activity accounting tool.
3月 24 15:40:09 iZwz97vcvjlst5yp9ifxzvZ systemd[1]: Starting system activity accounting tool...
3月 24 15:40:09 iZwz97vcvjlst5yp9ifxzvZ systemd[1]: sysstat-collect.service: Succeeded.
3月 24 15:40:09 iZwz97vcvjlst5yp9ifxzvZ systemd[1]: Started system activity accounting tool.
3月 24 15:41:24 iZwz97vcvjlst5yp9ifxzvZ MYAPP[334718]: this is a test message
这里面注意点工具名和等级有个集合的,不能随便写:
Valid facility names are: auth, authpriv (for security information of a sensitive nature), cron, daemon, ftp, kern (can't be generated from
user process), lpr, mail, news, security (deprecated synonym for auth), syslog, user, uucp, and local0 to local7, inclusive.
Valid level names are: alert, crit, debug, emerg, err, error (deprecated synonym for err), info, notice, panic (deprecated synonym for
emerg), warning, warn (deprecated synonym for warning). For the priority order and intended purposes of these levels, see syslog(3).
3.3 日志总管rsyslog
3.3.1 rsyslog说明
对于Systemd-journald 是将systemctl管理的服务日志记录到日志缓存或日志文件,而rsyslog 来负责将多个服务的日志按照配置的等级、记录到的具体日志文件。
rsyslog是也是通过systemctl来进行管理的。
[root@iZwz97vcvjlst5yp9ifxzvZ ~]# systemctl status rsyslog
● rsyslog.service - System Logging Service
Loaded: loaded (/usr/lib/systemd/system/rsyslog.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2024-01-03 09:22:36 CST; 2 months 20 days ago
Docs: man:rsyslogd(8)
https://www.rsyslog.com/doc/
Main PID: 1078 (rsyslogd)
Tasks: 3 (limit: 47107)
Memory: 4.8M
CGroup: /system.slice/rsyslog.service
└─1078 /usr/sbin/rsyslogd -n
2月 27 08:52:03 iZwz97vcvjlst5yp9ifxzvZ rsyslogd[1078]: imjournal: journal files changed, reloading... [v8.2102.0-5.el8 try https://www.rsyslog.com/e/0 ]
2月 28 13:36:16 iZwz97vcvjlst5yp9ifxzvZ rsyslogd[1078]: imjournal: journal files changed, reloading... [v8.2102.0-5.el8 try https://www.rsyslog.com/e/0 ]
2月 29 08:19:49 iZwz97vcvjlst5yp9ifxzvZ rsyslogd[1078]: imjournal: journal files changed, reloading... [v8.2102.0-5.el8 try https://www.rsyslog.com/e/0 ]
2月 29 08:19:49 iZwz97vcvjlst5yp9ifxzvZ rsyslogd[1078]: imjournal: journal files changed, reloading... [v8.2102.0-5.el8 try https://www.rsyslog.com/e/0 ]
3月 01 04:54:04 iZwz97vcvjlst5yp9ifxzvZ rsyslogd[1078]: imjournal: journal files changed, reloading... [v8.2102.0-5.el8 try https://www.rsyslog.com/e/0 ]
这几个关系按照我自己理解画了下:
简单说明:
systemd-journald 和rsyslog 都是linux下的日志服务、都是通过systemctl来进行管理的。
systemd-journald 可以记录内核信息、用户调用syslog输出的信息,默认写入到日志缓存区(内存)、二进制带索引结构、需要journalctl来进行过滤查看;
rsyslog是开源的日志系统,可以管理各种服务的日志、将日志根据等级、应用记录到不同的日志文件或转发到远程syslog日志服务器上。可以看做和systemd-journald并行的日志服务。
Rsyslog 配置文件为/etc/rsyslog.conf 和下层目录/etc/rsyslog.d
3.3.2 配置说明
看下配置核心内容: 核心内容为: 【服务-等级-- 记录到日志文件】
# Log all kernel messages to the console.
# Logging much else clutters up the screen.
#kern.* /dev/console
# Log anything (except mail) of level info or higher.
# Don't log private authentication messages!
*.info;mail.none;authpriv.none;cron.none /var/log/messages
# The authpriv file has restricted access.
authpriv.* /var/log/secure
# Log all the mail messages in one place.
mail.* -/var/log/maillog
# Log cron stuff
cron.* /var/log/cron
# Everybody gets emergency messages
*.emerg :omusrmsg:*
# Save news errors of level crit and higher in a special file.
uucp,news.crit /var/log/spooler
# Save boot messages also to boot.log
local7.* /var/log/boot.log
说明:.info;mail.none;authpriv.none;cron.none /var/log/messages
说明是任何>info 基本的日志都记录到/var/log/messages 中,但是mail、authpriv、cron这三个服务的日志不记录在这里面。
cron. /var/log/cron cron服务的任何日志都记录到/var/log/cron日志里面。
mail.* -/var/log/maillog
mail的任何日志都记录到/var/log/maillog文件中,注意前面的-号说明先写入缓存,达到一定量再一次性写入到日志,因为mail的信息太多。
新增加的服务,可以放在/etc/rsyslog.d中,会自动加载.
3.3.3 rsyslog服务器和客户端配置
为了便于日志集中管理、或者防止日志被人删除,则可以将rsyslog管理的日志集中发到一台服务器上。 在服务器端配置:
vim /etc/rsyslog.conf
#开启udp服务修改
# Provides UDP syslog reception
# for parameters see http://www.rsyslog.com/doc/imudp.html
module(load="imudp") # needs to be done just once
input(type="imudp" port="514")
#开启tcp服务修改
# Provides TCP syslog reception
# for parameters see http://www.rsyslog.com/doc/imtcp.html
module(load="imtcp") # needs to be done just once
input(type="imtcp" port="514")
重启服务:
systemctl restart rsyslogd
客户端配置:
vim /etc/rsyslog.conf
对于udp服务增加类似:
*.* @10.21.23.123
对于tcp服务增加类似:
*.* @@10.21.23.123
3.4 日志轮转logrotate
3.4.1 logrotate的作用和配置说明
有些系统的日志只有一个文件,随着系统的运行会越来越大,这时候为了便于维护,比如保存最近3天的日志,超过三天的日志均需要删除,或者只保存500MB的日志,超过了删除,这些需求都可以通过logrotate来实现。 系统中将logrotate做成按天自动运行的程序:
[root@iZwz90jb8mqajkli0ttrcbZ ~]# ll /etc/cron.daily/
总用量 4
-rwxr-xr-x. 1 root root 189 1月 4 2018 logrotate
[root@iZwz90jb8mqajkli0ttrcbZ ~]# ll /etc/cron.daily/logrotate
-rwxr-xr-x. 1 root root 189 1月 4 2018 /etc/cron.daily/logrotate
[root@iZwz90jb8mqajkli0ttrcbZ ~]# more /etc/cron.daily/logrotate
#!/bin/sh
/usr/sbin/logrotate /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
/usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit $EXITVALUE
[root@iZwz90jb8mqajkli0ttrcbZ ~]#
通过上面程序,我们可以看到利用logger 进行运行结果的记录,在执行失败的时候。 logrotate 的配置文件为:/etc/logrotate.conf 我们来看下配置:
root@iZwz90jb8mqajkli0ttrcbZ ~]# cat /etc/logrotate.conf
# see "man logrotate" for details
# rotate log files weekly 默认每周对日志进行一次轮训
weekly
# keep 4 weeks worth of backlogs 默认保留最新四个文件即保留 log log.1 log.2 log.3
rotate 4
# create new (empty) log files after rotating old ones 滚动后建立新的文件
create
# use date as a suffix of the rotated file 滚动的文件名会加上日期
dateext
# uncomment this if you want your log files compressed 是否压缩日志
#compress
# RPM packages drop log rotation information into this directory 其他配置目录
include /etc/logrotate.d
我们来看下其中一个滚动日志的具体配置:
[root@iZwz90jb8mqajkli0ttrcbZ ~]# cat /etc/logrotate.d/syslog
/var/log/cron
/var/log/maillog
/var/log/messages
/var/log/secure
/var/log/spooler
{
missingok
sharedscripts
postrotate
/usr/bin/systemctl kill -s HUP rsyslog.service >/dev/null 2>&1 || true
endscript
}
前面的部分每一行都是一个日志,包括绝对路径和日志名,花括号里面的内容是对滚动日志的具体配置。
missingok : 标识日志不存在也不会报错
sharedscripts和endscript 是一对,标识内部要执行脚本了。
postrotate: 是滚动后执行脚本、prerotate : 是滚动前执行脚本。
/usr/bin/systemctl kill: 通过systemctl的kill 来发送信号,确保信号发送给rsyslog.service的所有进程包括子进程、如果kill只能发给主进程 ;
>/dev/null 2>&1 :将执行结果放入到垃圾桶、包括错误输出和一般输出 ;
|| true: 前面脚本如果执行失败的话,仍然返回true,不然后可能会阻塞后面的执行。 ```
总体来说,后面几句的意思是日志滚动后,需要给rsyslog发送HUP信号,一般是重启程序,这样可以重新写同名的新日志文件了,防止日志不写了。
我们如果想确保日志只能写入不能删除,在滚动的时候就需要把a属性去掉,再滚动,新建日志文件再添加a属性,如下:
sharedscripts
prerotate
/usr/bin/chattr -a /var/log/messages
endscript
sharedscripts
postrotate
/usr/bin/systemctl kill -s HUP rsyslog.service >/dev/null 2>&1 || true
/usr/bin/chattr +a /var/log/messages || true
endscript
我们来看下日志滚动的效果:
[root@iZwz90jb8mqajkli0ttrcbZ ~]# ll /var/log/maillog*
-rw------- 1 root root 0 3月 24 03:20 /var/log/maillog
-rw------- 1 root root 0 2月 25 03:29 /var/log/maillog-20240303
-rw------- 1 root root 0 3月 3 03:43 /var/log/maillog-20240310
-rw------- 1 root root 0 3月 10 03:15 /var/log/maillog-20240317
-rw------- 1 root root 0 3月 17 03:39 /var/log/maillog-20240324
3.4.2 logrotate的测试
测试如下:
新建/var/log/miaolog 日志,设置为不可删除和修改;
配置滚动策略:1个月滚动一次、文件容量大于500M开始滚动、保留5个文件、进行压缩
[root@iZwz90jb8mqajkli0ttrcbZ ~]# touch /var/log/miaolog
[root@iZwz90jb8mqajkli0ttrcbZ ~]# chattr +a /var/log/miaolog
[root@iZwz90jb8mqajkli0ttrcbZ ~]# rm /var/log/miaolog
rm:是否删除普通空文件 '/var/log/miaolog'?y
rm: 无法删除'/var/log/miaolog': 不允许的操作
[root@iZwz90jb8mqajkli0ttrcbZ ~]# echo "test a log" >/var/log/miaolog
-bash: /var/log/miaolog: 不允许的操作
[root@iZwz90jb8mqajkli0ttrcbZ ~]# echo "test a log" >> /var/log/miaolog
[root@iZwz90jb8mqajkli0ttrcbZ ~]# cat /var/log/miaolog
test a log
[root@iZwz90jb8mqajkli0ttrcbZ ~]# vim /etc/log
login.defs logrotate.conf logrotate.d/
[root@iZwz90jb8mqajkli0ttrcbZ ~]# vim /etc/log
login.defs logrotate.conf logrotate.d/
[root@iZwz90jb8mqajkli0ttrcbZ ~]# vim /etc/logrotate.d/miao
[root@iZwz90jb8mqajkli0ttrcbZ ~]# cat /etc/logrotate.d/miao
/var/log/miaolog
{
monthly
size = 100M
rotate 5
compress
prerotate
/usr/bin/chattr -a /var/log/miaolog || true
endscript
sharedscripts
postrotate
/usr/bin/chattr +a /var/log/miaolog || true
endscript
}
测试效果:
# 只看过程 不执行
[root@iZwz90jb8mqajkli0ttrcbZ ~]# logrotate -v /etc/logrotate.conf
reading config file /etc/logrotate.conf
including /etc/logrotate.d
reading config file bootlog
reading config file btmp
reading config file chrony
reading config file cups
reading config file dnf
...
...
...
rotating pattern: /var/log/up2date weekly (4 rotations)
empty log files are rotated, old logs are removed
considering log /var/log/up2date
log /var/log/up2date does not exist -- skipping
rotating pattern: /var/log/wpa_supplicant.log 30720 bytes (4 rotations)
empty log files are not rotated, old logs are removed
considering log /var/log/wpa_supplicant.log
log /var/log/wpa_supplicant.log does not exist -- skipping
rotating pattern: /var/log/wtmp monthly (1 rotations)
empty log files are rotated, only log files >= 1048576 bytes are rotated, old logs are removed
considering log /var/log/wtmp
Now: 2024-03-24 16:59
Last rotated at 2020-12-28 15:00
log does not need rotating ('minsize' directive is used and the log size is smaller than the minsize value)
强制执行:
#logrotate -vf /etc/logrotate.conf
...
...
...
最终查看日志情况:
[root@iZwz90jb8mqajkli0ttrcbZ ~]# ll /var/log/miaolog*
-rw-r--r-- 1 root root 0 3月 24 16:59 /var/log/miaolog
-rw-r--r-- 1 root root 31 3月 24 16:56 /var/log/miaolog-20240324.gz
花了大概一天时间把日志情况理的差不多了,各种日志还可以通过logwatch等工具对日志进行分析汇总,发个mail到root上,感兴趣的朋友可以继续探索。