workerman日志需输出为单行json格式(含@timestamp、level、message、context等字段),logstash必须配置json、date(匹配iso8601)、mutate三类filter,filebeat采集更稳定,kibana排查需注意时间范围、request_id全链路和字段类型一致性。

Workerman日志怎么输出成ELK能解析的格式?
Workerman本身不内置结构化日志能力,必须主动控制日志输出格式。直接用error_log()或file_put_contents()写纯文本,Logstash的grok解析会频繁失败——字段缺失、时间戳不统一、嵌套JSON被截断都是常见现象。
关键做法是:在自定义日志方法中统一输出JSON行格式(每条日志一行,无换行符),并确保包含@timestamp、level、message、context等基础字段。例如:
{"@timestamp":"2026-05-21T21:15:33+08:00","level":"error","message":"connection timeout","context":{"worker":"BusinessWorker","client_id":12345,"uri":"/api/order"}}
- 时间戳必须用ISO 8601格式,且带时区,否则Logstash的
datefilter会解析为1970-01-01 - 避免在
message里拼接变量,改用context承载结构化数据,方便Kibana做聚合 - 不要用
json_encode($arr, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)以外的选项,否则Logstash可能因反斜杠或中文编码报错
Logstash配置里哪些filter规则不能省?
Workerman日志走文件落地再被Filebeat采集时,Logstash端至少要配三类filter,缺一不可。少配date,所有日志都按摄入时间索引;漏掉json,grok根本没机会触发。
-
jsonfilter:必须指定source => "message",把整行JSON转成ES可索引字段 -
datefilter:匹配@timestamp字段,用match => ["@timestamp", "ISO8601"],别信文档里写的“自动识别” -
mutatefilter:删掉冗余字段如host、path(Filebeat自带),防止ES mapping膨胀;必要时用rename把level映射为log.level以兼容ECS规范
错误示例:grok { match => { "message" => "%{TIMESTAMP_ISO8601:timestamp}" }——Workerman已输出完整JSON,再用grok硬拆是重复劳动,且极易因字段顺序变动崩掉。
为什么Filebeat比Logstash直读文件更稳?
Workerman常驻进程高频写日志,Logstash用file input插件直接监听同一文件时,容易出现:文件轮转(logrotate)后丢失最后几KB、inotify事件丢失、多Worker并发写导致单行日志被截断。Filebeat的harvester机制和registry文件记录偏移量,能准确处理这些边界情况。
- Filebeat配置必须设
close_inactive: 5m,避免长连接日志文件被长期占用 - 启用
multiline.pattern: '^{ "@timestamp":'合并多行JSON(极少数场景下Workerman异常堆栈需跨行) - output别直连ES,走Logstash中转——Filebeat的filter能力弱,复杂字段提取(如从
context.uri抽path和query)必须靠Logstash的dissect或kv
Kibana里查Workerman日志最实用的三个技巧
默认配置下,Kibana搜索框输log.level: "error"能查出错误,但真正排障需要更深一层。注意几个实际卡点:
- 时间范围选“Last 15 minutes”不够——Workerman日志从产生到进Kibana有延迟,建议固定选“Last 1 hour”,再用
@timestamp字段二次过滤 - 想看某次请求全链路?给Workerman Worker加唯一
request_id到context,Kibana里用Discover页的View surrounding documents功能,按request_id上下文展开 - 聚合慢请求:用
Visualize建TSVB图表,指标选Averageofcontext.duration_ms,分组用context.uri.keyword,比单纯查message快一个数量级
真正麻烦的是日志字段类型混乱——比如context.code有时是字符串有时是数字,ES会随机选一种mapping,后续聚合就失效。上线前务必用curl -X GET "localhost:9200/logs-*/_mapping?pretty"检查,发现"type": "text"就立刻用Index Template修正。











