logstash 不适合直接读取 /var/log/messages 或 journalctl 输出,因其 file 插件无法可靠处理 logrotate 切割、inode 变更、权限限制及 journald 二进制格式,易导致丢行、乱序、漏日志;正确做法是让 rsyslog 或 journald 先标准化转发至 logstash 的 tcp/syslog 输入插件。

Logstash 不适合直接读取 /var/log/messages 或 journalctl 输出来收集系统日志——这是生产环境里最常踩的坑,不是配置不对,而是架构错位。
为什么不能用 file 输入插件读系统日志文件
-
logrotate执行copytruncate时,Logstash 会丢失截断点之后、下一次扫描前的所有日志 - 系统日志文件(如
/var/log/auth.log)权限通常是root:adm,非 root 运行的 Logstash 根本打不开 -
file插件把journalctl -o json的输出当纯文本读,丢掉_HOSTNAME、PRIORITY、UNIT等关键字段 - 多个进程(rsyslog + Logstash)同时写/读同一文件,inode 变更导致 offset 记录失效,出现乱序或重复
正确路径是:让 rsyslog 或 journald 先做标准化转发,Logstash 只负责稳收网络流。
怎么配 rsyslog 转发到 Logstash 的 tcp 输入
- 在客户端(即你要采集日志的机器)编辑
/etc/rsyslog.d/10-logstash.conf,内容如下:template(name="json-template" type="list") { constant(value="{") constant(value="\"@timestamp\":\"") property(name="timereported" dateFormat="rfc3339") constant(value="\",\"host\":\"") property(name="hostname") constant(value="\",\"severity\":\"") property(name="syslogseverity-text") constant(value="\",\"facility\":\"") property(name="syslogfacility-text") constant(value="\",\"tag\":\"") property(name="syslogtag" format="json") constant(value="\",\"message\":\"") property(name="msg" format="json") constant(value="\"}\n") } *.* action(type="omfwd" protocol="tcp" target="192.168.1.100" port="5044" template="json-template" keepalive="on") - 重启 rsyslog:
sudo systemctl restart rsyslog - 验证语法:
sudo rsyslogd -N1(无输出表示 OK) - 测试发送:
logger "test from rsyslog",然后在 Logstash 端确认是否收到 JSON 行
注意:目标 IP(192.168.1.100)需替换为 Logstash 所在服务器地址;端口 5044 是常用且推荐的非特权端口。
Logstash 端怎么写 input + filter 收 JSON 系统日志
- 创建
/etc/logstash/conf.d/01-syslog-input.conf:input { tcp { port => 5044 codec => "json" tags => ["rsyslog-json"] } } - 创建
/etc/logstash/conf.d/02-syslog-filter.conf:filter { if "rsyslog-json" in [tags] { date { match => ["@timestamp", "ISO8601"] target => "@timestamp" } mutate { remove_field => ["message", "host", "port"] rename => { "hostname" => "host" } } } } - 关键点:
-
codec => "json"必须和 rsyslog 的 template 输出格式对齐,否则字段全空 - 不要用
grok解析 rsyslog JSON 日志——它已经是结构化的,强行 grok 反而破坏字段 -
date插件必须指定target => "@timestamp",否则 Logstash 会用接收时间而非日志真实时间 -
mutate.remove_field清理冗余字段,避免污染 ES mapping
-
journald 用户该选哪条路
- 如果你用的是 systemd 系统且想绕过 rsyslog,不推荐直接监听 UDP 514 或用 syslog 输入插件(不可靠、无重传、易丢包)。
- 更稳妥的做法是启用 journald 的 export 接口,配合 Logstash 的
exec输入插件定时拉取:input { exec { command => "journalctl -o json --no-tail -n 1000" interval => 10 codec => "json" tags => ["journald-exec"] } } - 注意事项:
-
journalctl -o json输出每行一个 JSON 对象,codec => "json"能正确解析 -
--no-tail保证每次拉取都从头开始(配合since参数可做增量) -
interval => 10是秒级间隔,太短会加重 journal 压力,太长则延迟高
-
真正容易被忽略的是:无论走 rsyslog 还是 journald,Logstash 本身必须以 root 权限运行,否则无法绑定 5044 等低编号端口,也无法读取 /run/systemd/journal/socket(如果用 socket 输入)。这个权限问题在调试阶段经常卡住整条链路。











