serilog writeto.file() 默认使用 plaintextformatter 输出纯文本日志,导致 elk 无法解析结构化字段;必须配置 jsonformatter(rendermessage: true) 输出单行 json(json lines)格式,确保每条日志为合法、无换行、无缩进的 json 对象,才能被 filebeat 正确解析并提升字段。

Serilog 默认不输出 JSON 格式,必须显式配置 JsonFormatter 或使用 Serilog.Formatting.Json 包,否则 ELK 无法正确解析字段。
为什么 WriteTo.File() 默认输出不是 JSON?
Serilog 的 WriteTo.File() 默认用的是 PlainTextFormatter,日志是纯文本,类似:[10:23:41 INF] User logged in: id=123
这种格式在 Kibana 里只能当一个 message 字符串,所有结构化字段(如 UserId、Level、Timestamp)全丢了。
要让 ELK 能按字段搜索、聚合、过滤,必须让每条日志是一行合法 JSON(即 “JSON Lines” 格式)。
- 安装必需包:
Serilog+Serilog.Sinks.File+Serilog.Formatting.Json - 配置时必须传入
new JsonFormatter(renderMessage: true),否则message字段不会展开为字符串 -
renderMessage: true是关键——它把模板消息(如"User {Id} logged in")渲染成实际值并写入message字段,否则该字段为空或只是模板
如何配置 Serilog 输出标准 JSON Lines 到文件?
ELK 的 Logstash/Filebeat 默认按行读取日志,所以必须确保每条日志严格为一行 JSON,不能换行、不能缩进。
正确配置示例:
Log.Logger = new LoggerConfiguration()
.WriteTo.File(
new JsonFormatter(renderMessage: true),
"logs/log-.json",
rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 7)
.CreateLogger();
-
JsonFormatter构造函数不加参数 →renderMessage默认为false,会导致message字段缺失内容 - 文件后缀用
.json更利于 Filebeat 自动识别类型,但非强制;关键是内容为 JSON Lines - 不要用
outputTemplate配合PlainTextFormatter“模拟” JSON——那是字符串拼接,字段名/值没转义,JSON 解析会失败
对接 Filebeat 时,processors 还需额外处理吗?
如果 Serilog 输出的是标准 JSON Lines(每行一个对象),Filebeat 可直接用 json.keys_under_root: true 提升字段,无需 Grok 解析。
推荐 Filebeat 配置片段:
filebeat.inputs:
- type: filestream
paths:
- /var/log/myapp/*.json
parsers:
- json:
keys_under_root: true
overwrite_keys: true
add_error_key: true
-
keys_under_root: true把 JSON 顶层字段(如timestamp、level、message)直接提升为事件字段,不用写json.timestamp -
overwrite_keys: true避免字段冲突(比如日志里有host,和 Filebeat 自带的host.name冲突) - 别开
json.message_key:Serilog 的message已是字符串,不需要再从某个子字段提取
常见 JSON 解析失败的错误现象和定位方法
在 Kibana 发现日志全进 message 字段、字段为空、或报 json parse error,大概率是以下原因:
- 日志文件里混入了非 JSON 行(比如程序启动时的 Console.WriteLine、ANSI 控制字符、空行)→ 用
head -n 20 logs/log-20240501.json | jq .检查前 20 行是否都可解析 -
JsonFormatter未传参 → 查看任意一行,确认是否存在"message": "xxx"字段,而不是"message": null或压根没有message - 日志中含非法 Unicode(如 Windows 控制台截断的宽字符)→ 在
LoggerConfiguration()中加.MinimumLevel.Verbose()并临时输出到控制台,观察原始内容 - Filebeat 启动后没 reload 配置 → 执行
filebeat test config && filebeat test output验证连通性
JSON 日志的脆弱点在于“一错全崩”:单个格式错误会阻断后续所有行的解析。最稳妥的做法是先本地生成小文件,用 jq -s '.' xxx.json 全量验证合法性,再上生产。










