如何通过Serilog(含MS日志扩展)限制EF Core commandText日志大小
限制EF Core日志中CommandText的大小(Serilog + Serilog MS Logging Extensions)
方法一:自定义EF Core日志拦截器
直接通过EF Core的命令拦截器,在数据库命令执行前截断过长的CommandText,所有后续日志都会使用处理后的内容。
实现步骤:
- 创建继承自
DbCommandInterceptor的拦截类,重写同步/异步命令执行方法:
using Microsoft.EntityFrameworkCore.Diagnostics; using System.Data.Common; public class CommandTextTruncationInterceptor : DbCommandInterceptor { private readonly int _maxLength; public CommandTextTruncationInterceptor(int maxCommandTextLength) { _maxLength = maxCommandTextLength; } public override InterceptionResult<DbDataReader> CommandExecuting( DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result) { TruncateCommandText(command); return base.CommandExecuting(command, eventData, result); } public override ValueTask<InterceptionResult<DbDataReader>> CommandExecutingAsync( DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result, CancellationToken cancellationToken = default) { TruncateCommandText(command); return base.CommandExecutingAsync(command, eventData, result, cancellationToken); } private void TruncateCommandText(DbCommand command) { if (command.CommandText.Length > _maxLength) { command.CommandText = $"{command.CommandText[.._maxLength]}... [TRUNCATED]"; } } }
- 在DbContext配置中注册拦截器:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { // 这里设置你需要的最大长度,比如1000 optionsBuilder.AddInterceptors(new CommandTextTruncationInterceptor(1000)); }
方法二:Serilog层面处理日志事件
无需修改EF Core逻辑,直接在Serilog的日志事件流转中截断CommandText属性。
实现方式1:日志输出时转换
在Serilog的输出配置中添加转换逻辑:
Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(Configuration) .WriteTo.Console( outputTemplate: "{Timestamp:HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}", transform: logEvent => { const int maxLength = 1000; if (logEvent.Properties.TryGetValue("CommandText", out var prop) && prop is ScalarValue scalar && scalar.Value is string commandText) { if (commandText.Length > maxLength) { logEvent.AddOrUpdateProperty(new LogEventProperty( "CommandText", new ScalarValue($"{commandText[..maxLength]}... [TRUNCATED]"))); } } return logEvent; }) .CreateLogger();
实现方式2:自定义Enricher
创建日志增强器统一处理所有日志事件:
public class CommandTextTruncationEnricher : ILogEventEnricher { private readonly int _maxLength; public CommandTextTruncationEnricher(int maxLength) { _maxLength = maxLength; } public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { if (logEvent.Properties.TryGetValue("CommandText", out var value) && value is ScalarValue scalar && scalar.Value is string commandText) { if (commandText.Length > _maxLength) { var truncatedText = $"{commandText[.._maxLength]}... [TRUNCATED]"; logEvent.AddOrUpdateProperty(propertyFactory.CreateProperty("CommandText", truncatedText)); } } } }
然后在Serilog配置中注册:
Log.Logger = new LoggerConfiguration() .Enrich.With(new CommandTextTruncationEnricher(1000)) // 其他配置项 .CreateLogger();
注意事项
- 截断长度根据实际调试需求调整,避免丢失关键SQL片段。
- 若使用异步数据库操作,必须同时重写拦截器的同步和异步方法。
- EF Core日志中
CommandText的属性键固定为CommandText,无需额外适配。
内容的提问来源于stack exchange,提问作者yzorg
相关产品推荐
相关产品推荐

