在CentOS系统运维中,journalctl是systemd日志管理的核心工具,按时间段筛选日志并导出是日常排障最常用的操作。直接说结论:使用--since--until参数可以精确指定时间范围,配合-o指定输出格式,再通过重定向符号>或管道|导出到文件即可。比如你要查今天上午9点到11点的所有错误日志并导出,一条命令就能搞定:journalctl --since "2024-01-15 09:00:00" --until "2024-01-15 11:00:00" -p err -o short > /tmp/error_log.txt。下面我把这套操作从头到尾、从基础到进阶全部讲透。

一、journalctl基础认知:为什么不用传统tail/grep了

CentOS 7及以后的版本全面采用systemd作为初始化系统,日志不再分散在/var/log/messages、/var/log/secure这些文件里,而是统一收归到journald守护进程管理。journalctl就是查询这套日志系统的命令行接口。相比传统的grep+tail组合,journalctl有三个明显优势:第一,它支持结构化查询,可以按时间、优先级、服务单元、PID等多维度过滤;第二,它自带时间戳解析能力,不用你手动换算;第三,它支持二进制日志直接读取,性能更好,不依赖文本文件的实时刷新。

二、按时间段筛选日志的核心参数详解

journalctl提供了两个关键时间参数:--since--until。它们接受的时间格式非常灵活,下面逐一说明。

1. 绝对时间格式

最精确的写法是"YYYY-MM-DD HH:MM:SS",比如:

journalctl --since "2024-01-15 08:00:00" --until "2024-01-15 12:00:00"

这种写法不会有任何歧义,推荐在脚本中使用。

2. 相对时间格式

日常排障时用相对时间更方便。支持的写法包括:

journalctl --since "1 hour ago"
journalctl --since "today"
journalctl --since "yesterday" --until "today"
journalctl --since "2024-01-15" --until "2024-01-16"

"today"表示当天零点开始,"yesterday"表示昨天零点开始,"1 hour ago"就是当前时间往前推一小时。注意:如果只写--since不写--until,默认查询从指定时间到现在的所有日志。

3. 短格式时间

还有一些简写形式:

journalctl --since "10min ago"
journalctl --since "-5min"
journalctl --since "2024-01-15 14:30" --until "14:45"

其中--since "-5min"表示5分钟前到现在,--since "10min ago"--since "-10min"效果一样。同一行里如果--until只写时间不写日期,默认和--since同一天。

三、组合筛选:时间+优先级+服务单元

光按时间筛出来的日志量可能很大,实际运维中通常要叠加其他条件。最常用的组合是时间+日志级别+服务名。

1. 按优先级过滤(-p参数)

journalctl的优先级从高到低分为:emerg(0)、alert(1)、crit(2)、err(3)、warning(4)、notice(5)、info(6)、debug(7)。常用写法:

journalctl --since "2024-01-15 09:00:00" --until "2024-01-15 11:00:00" -p err

这条命令只看错误及以上级别。如果要看警告和错误,可以写-p warning或者用逗号分隔:-p err -p crit

2. 按服务单元过滤(-u参数)

如果你只关心某个服务的日志,比如nginx、sshd、docker:

journalctl --since "today" -u nginx.service -p err
journalctl --since "1 hour ago" -u sshd.service

3. 按PID过滤(_PID参数)

追踪某个进程的日志:

journalctl --since "2024-01-15 10:00:00" _PID=1234

4. 按内核日志过滤(-k参数)

只看内核相关的日志(等同于dmesg):

journalctl -k --since "today"

四、导出日志的四种实用方式

筛选出来之后,导出是关键步骤。根据场景不同,有四种导出方式。

方式一:直接重定向到文件(最简单)

journalctl --since "2024-01-15 09:00:00" --until "2024-01-15 11:00:00" -p err > /tmp/err_20240115.log

这种方式导出的是默认的short格式,包含时间戳、主机名、服务名、PID和消息内容。适合快速保存原始日志。

方式二:指定输出格式(-o参数)

journalctl支持多种输出格式,常用的有:

journalctl --since "today" -o short > /tmp/short.log       # 默认短格式
journalctl --since "today" -o verbose > /tmp/verbose.log   # 显示所有字段
journalctl --since "today" -o json-pretty > /tmp/json.log  # JSON格式,方便程序解析
journalctl --since "today" -o cat > /tmp/cat.log           # 只输出消息内容,无元数据
journalctl --since "today" -o export > /tmp/export.bin      # 二进制导出,可用journalctl --import重新导入

如果你要把日志发给开发或者导入其他分析平台,json-pretty格式最合适,结构清晰可解析。

方式三:管道配合grep/awk二次处理

有时候需要在导出前做文本处理:

journalctl --since "today" -u nginx.service | grep "500\|502\|503" > /tmp/nginx_5xx.log
journalctl --since "today" --no-pager | awk '/error/{print $0}' > /tmp/errors.txt

注意加上--no-pager参数,否则journalctl默认会调用less分页显示,管道会出问题。

方式四:导出为压缩文件(大日志场景)

当时间范围很大、日志量达到几百MB甚至几GB时,直接导出文本文件不现实,建议压缩:

journalctl --since "2024-01-01" --until "2024-01-31" -u myapp.service | gzip > /tmp/myapp_jan.log.gz

或者先导出再压缩:

journalctl --since "2024-01-01" --until "2024-01-31" -u myapp.service > /tmp/myapp_jan.log
gzip /tmp/myapp_jan.log

五、实战场景:常见运维排障命令模板

下面给几个拿来就能用的命令模板,覆盖高频场景。

场景1:排查某时间段服务崩溃原因

journalctl --since "2024-01-15 14:00:00" --until "2024-01-15 14:30:00" -u myapp.service -p err --no-pager | less

场景2:导出昨天全天的安全相关日志给审计

journalctl --since "yesterday" --until "today" -u sshd.service -o json-pretty > /tmp/sshd_audit.json

场景3:查看某个时间点前后的系统异常

journalctl --list-boots | head -5

先用--list-boots查看历史启动记录,找到对应启动编号,再指定:

journalctl --list-boots
journalctl -b -1 --since "10:00" --until "11:00" -p crit

-b -1表示上次启动的日志,-b -2表示上上次,以此类推。

场景4:定时任务自动导出日志

写一个crontab任务,每天凌晨导出前一天的错误日志:

0 2 * * * root /usr/bin/journalctl --since "yesterday" --until "today" -p err -o short > /var/log/daily_err/err_$(date +\%Y\%m\%d).log

六、常见坑和注意事项

1. 时区问题

journalctl默认使用系统时区。如果你的服务器设置的是UTC时间,而你按北京时间写--since "2024-01-15 09:00:00",实际查到的是UTC的9点,差了8小时。解决办法:要么统一用UTC写时间,要么在命令里加TZ=Asia/Shanghai环境变量:

TZ=Asia/Shanghai journalctl --since "2024-01-15 09:00:00" --until "2024-01-15 11:00:00"

2. 日志轮转和存储限制

journald默认日志存储在/run/log/journal(内存)和/var/log/journal(持久化)。如果磁盘空间有限,日志会被自动清理。可以查看当前配置:

journalctl --disk-usage

如果发现日志被清理了,之前的时间段可能查不到。建议在/etc/systemd/journald.conf里调整SystemMaxUseMaxRetentionSec参数,或者把重要日志及时导出备份。

3. --no-pager必须加

在脚本和管道操作中,不加--no-pager会导致命令挂起等待分页器退出,这是新手最常踩的坑。

4. 大时间范围查询慢

如果查询跨度超过一个月,journalctl可能需要较长时间扫描索引。可以加--no-tail避免从末尾开始显示,或者用--output=cat只输出纯文本加速处理。

七、进阶技巧:导出后的日志分析建议

导出的日志文件建议配合以下工具做进一步分析:用awk统计错误类型分布,用sort | uniq -c | sort -rn找高频错误,用sed提取关键字段。如果是JSON格式导出,可以用jq工具做结构化查询。对于长期运维,建议搭建ELK或者Loki这样的日志聚合平台,把journalctl的输出通过filebeat或promtail实时采集,实现集中检索和告警。

总结

journalctl按时间段筛选和导出日志是CentOS运维的基本功。核心就是--since--until定时间范围,-p定级别,-u定服务,-o定格式,>|做导出。掌握这些参数的组合使用,再注意时区、pager、存储限制这几个坑,日常排障和日志归档就能高效完成。把上面的命令模板存到自己的运维脚本库里,遇到问题直接套用,效率会提升很多。