Logstash无法解析带前置逗号的message字段JSON日志问题
问题根因
- 两种过滤方案失效的核心原因有两个:一是
message字段为数组类型,不符合JSON过滤器要求的字符串类型输入规则;二是数组内存储的日志字符串开头存在多余逗号,、末尾存在回车符\r,即使通过split过滤器将数组拆分为单个字符串,首尾的非法字符也会导致JSON语法校验不通过,解析失败。 - 多余逗号的来源是Serilog Http Sink的默认批量发送逻辑:该Sink默认使用数组批量格式化器,将多条日志用逗号拼接为JSON数组后批量推送,若Logstash输入侧未配置对应数组格式的解码规则,会出现拆包错误,拿到半截的数组内容,残留开头的逗号分隔符。
解决方案
方案1:Logstash侧清洗修复(无需改动日志发送端)
按顺序配置过滤器,先处理数组类型、清理首尾非法字符,再做JSON解析,配置如下:
filter { if [message] { # 将数组类型的message合并为字符串 mutate { join => { "message" => "" } } # 正则清理:移除开头所有非{的非法字符(逗号、空格、换行等),移除末尾所有非}的非法字符(回车、换行、空格等) mutate { gsub => [ "message", "^[^{]+", "", "message", "[^}]+$", "" ] } # 解析清理完成的合法JSON字符串 json { source => "message" remove_field => ["message"] # 可选配置,解析后移除冗余的原始message字段 } } }
该配置会自动忽略首尾的非法字符,直接提取中间合法的JSON结构完成解析,兼容当前存在格式问题的日志输入。
方案2:收发端配置对齐(根因解决,无额外清洗开销)
从日志发送环节避免生成带多余分隔符的内容,不需要在Logstash侧做额外字符串清洗,长期运行更稳定:
- 修改Serilog日志发送配置,将Http Sink的批量格式化规则改为按换行分隔单条日志,修正后的代码如下:
using Elastic.CommonSchema.Serilog; using Serilog; using Serilog.Sinks.Http.BatchFormatters; var builder = WebApplication.CreateBuilder(args); builder.Host .UseSerilog((ctx, lc) => lc .WriteTo.Http( textFormatter: new EcsTextFormatter(), requestUri: "http://localhost:5000", queueLimitBytes: null, // 指定按换行分隔批量日志,单条日志为独立合法JSON batchFormatter: new DefaultBatchFormatter("\n") ) .Enrich.FromLogContext() ); var app = builder.Build(); app.MapGet("/", (Serilog.ILogger logger) => { logger.Error("this is an error"); return "logged an error"; }); app.Run("http://localhost:3000");
- 修改Logstash接收端配置,使用
json_lines编码匹配换行分隔的日志格式,示例input配置:
input { http { port => 5000 codec => json_lines } }
配置完成后Logstash会直接按行解析到完整的ECS格式日志,不需要额外配置split、字符串替换等清洗规则。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

