Serilog 发送日志到 Logstash 应该用哪个 Sink?

推荐 Serilog.Sinks.Network 的 TCP sink 配合 JSON 格式化器发送到 Logstash 的 tcp 输入;也可用 HTTP sink 或先写文件再由采集器转发。本文给出配置示例。

最佳实践
Serilog 发送日志到 Logstash 应该用哪个 Sink?封面

推荐方案:用 Serilog.Sinks.Network 包的 TCP sink,搭配 JSON 格式化器,把结构化日志直接发到 Logstash 的 tcp 输入端口——网络直发省去文件中转,TCP 比 UDP 可靠;如果对投递可靠性要求高,更稳妥的做法是写本地 JSON 文件,由采集代理转发。

方案一:TCP 直发

安装包:

dotnet add package Serilog.Sinks.Network
dotnet add package Serilog.Sinks.Console

配置 Serilog:

using Serilog;
using Serilog.Sinks.Network;

Log.Logger = new LoggerConfiguration()
    .WriteTo.Console()
    .WriteTo.TCPSink("tcp://logstash-host:5044", new Serilog.Formatting.Json.JsonFormatter())
    .CreateLogger();

Log.Information("用户 {UserId} 登录成功", 42);

Logstash 侧对应输入:

input {
  tcp {
    port => 5044
    codec => json_lines
  }
}

JsonFormatter 保留结构化字段(如 Properties.UserId);Logstash 还需配置输出和匹配的字段映射,JSON 格式本身不保证已写入 ES。5044 在此是 TCP input,不能同时作为同地址的 Beats input。

方案二:写文件 + 采集转发(生产更稳)

.WriteTo.File(new Serilog.Formatting.Json.JsonFormatter(),
    "logs/app-.json", rollingInterval: RollingInterval.Day)

需安装 Serilog.Sinks.File。应用写本地文件,采集代理(如 Filebeat)负责转发与重试;文件保留期、磁盘容量、轮转及主机故障仍影响可靠性,不能保证不丢日志。

常见坑

  1. UDP 会丢包:内网低负载可用,跨网络务必 TCP。
  2. 换行分隔:Logstash 用 json_lines codec 时,每条 JSON 必须以换行结尾,示例 JsonFormatter 会输出换行;自定义 formatter 需自行保证分隔。
  3. 断连缓冲:所核对的 Network sink 实现已有内存队列及重连,队列满时会丢弃旧事件;具体行为应核对所用版本,额外 Async 包装不等于持久缓冲。

若后端使用观测云,也可以保留 Serilog 的文件输出,由 DataKit读取日志。先针对实际 formatter 配置字段解析,并发送一条含异常堆栈的样本,确认没有被拆成多条记录,再考虑替换现有 Sink。

常见问题(FAQ)

Q:Serilog 有专门的 Logstash sink 吗?
A:社区有 Serilog.Sinks.Logstash(HTTP/UDP),需核对具体包版本的维护情况、协议和重试语义;Network TCP + json_lines 是另一种选择。

Q:Logstash 端收到的是一行多个 JSON 粘在一起怎么办?
A:TCP 是字节流,应让每条 JSON 以换行分隔,再匹配 json_lines;若发送端没有分隔,仅换 codec 不能补出事件边界。

Q:想保留 Serilog 的消息模板属性怎么办?
A:用 JsonFormatter(或 CompactJsonFormatter 输出 CLEF 格式),JsonFormatter 将属性放在 Properties 对象内;CompactJsonFormatter 将普通属性放在顶层,需按实际格式解析。

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台