Serilog.Sinks.MSSqlServer 直接支持 SQL Server,但需严格匹配表结构(如 LogEvent 必须为 nvarchar(max))、连接字符串(含 TrustServerCertificate=true)及异步配置(batchPostingLimit:50, period:2s);MySQL 需用 MySqlConnector ≥2.2.0 并设 Allow User Variables=True,Properties 字段须为 json 类型;禁用 autoCreateSqlTable 上生产,调试优先用 .WriteTo.Debug() 和单条提交定位问题。

用 Serilog.Sinks.MSSqlServer 写入 SQL Server
直接支持 SQL Server,不需要自己写 Sink。关键不是“能不能”,而是表结构和连接字符串配不配得上。
常见错误是照着文档建了表,但 LogEvent 字段类型用了 nvarchar(4000) —— 实际日志内容可能超长,必须用 nvarchar(max),否则写入时静默失败或截断。
- 安装 NuGet 包:
Serilog.Sinks.MSSqlServer(注意不是Serilog.Sinks.SqlServer,后者已弃用) - 建表语句必须用包自带的
SqlServerSink.CreateTableIfNotExists()或按其 DDL 手动建,字段名和类型不能改(比如Timestamp必须是datetimeoffset) - 连接字符串需含
TrustServerCertificate=true(本地开发)或正确配置证书(生产),否则SqlException: A connection was successfully established...后立刻断开 - 推荐启用异步写入:
batchPostingLimit: 50和period: TimeSpan.FromSeconds(2),避免主线程卡在日志 IO 上
MySQL 需要自己适配 Serilog.Sinks.MySQL
官方没提供 MySQL Sink,社区包 Serilog.Sinks.MySQL 维护较弱,容易在 .NET 6+ 出现 MySqlException: Unable to connect to any of the specified MySQL hosts —— 实际是驱动版本不匹配。
更稳的做法是用 Serilog.Sinks.Async + 自定义 ITextFormatter 输出 JSON,再由后台服务消费写入 MySQL;但若坚持直连,务必确认:
- 项目引用
MySqlConnector(非 Oracle 官方驱动),且版本 ≥ 2.2.0(支持 .NET 6+ 的async/await日志批量提交) - MySQL 表中
Properties字段必须为json类型(MySQL 5.7+),不能用text,否则INSERT会因 JSON 校验失败而跳过整条日志 -
connectionString中必须显式指定Allow User Variables=True,否则参数化写入时报错Parameter '@p0' must be defined
日志字段映射与性能陷阱
Serilog 默认把整个 LogEvent 序列化进 MessageTemplate 和 Properties 字段,但 SQL Server 的 Properties 如果设成 varchar(max),写入时会触发 LOB 锁,高并发下极易阻塞。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
解决思路不是“加大字段”,而是控制写入内容:
- 用
Filter.ByExcluding(logEvent => logEvent.Properties.ContainsKey("SourceContext"))剔除冗余属性 - 对敏感字段(如
ConnectionId、UserName)做白名单提取,用Enrich.WithProperty()预置,避免全量Properties入库 - 禁止在
WriteTo.MSSqlServer()中开启autoCreateSqlTable: true上生产环境——DDL 操作会锁库,且无法定制索引
调试写入失败最有效的三件事
日志写不进数据库,90% 不是代码问题,而是权限、网络或 Sink 内部吞错。
- 加
.WriteTo.Debug(),看控制台是否输出SQL Server sink error: ...—— 这比查数据库日志快十倍 - 临时把
batchPostingLimit改成1,让每条日志单独提交,方便定位是某条日志内容(如含不可序列化对象)导致整批失败 - 用 SQL Server Profiler 或 MySQL
general_log抓真实发出的INSERT语句,确认是连接超时、字段溢出,还是权限拒绝(比如缺少INSERT权限而非SELECT)
别信“配置完就能用”,Serilog 数据库 Sink 的脆弱点都在边界条件里:时间戳时区、JSON 嵌套深度、连接池耗尽、字段长度硬编码。上线前一定用含异常堆栈、含字典属性、含中文消息的真实日志压测十分钟。










