.NET日志简单包装器(适配Serilog/NLog)完整工作示例求助
.NET 日志包装器完整实现(适配器模式)
我给你整理了一个直接可运行的日志包装器方案,用适配器模式把Serilog、NLog这些第三方日志框架适配到统一的抽象接口上,业务代码完全不用关心底层用的是哪个日志库,后续切换或者新增框架也非常方便。
1. 定义统一的日志抽象接口
首先我们先定义一个通用的ILogger接口,包含常用的日志级别方法:
public interface ILogger { void Debug(string message, params object[] args); void Info(string message, params object[] args); void Warn(string message, params object[] args); void Error(string message, params object[] args); void Error(Exception ex, string message, params object[] args); void Fatal(string message, params object[] args); void Fatal(Exception ex, string message, params object[] args); }
2. 适配器基类(可选,减少重复代码)
为了避免每个适配器都重复实现接口方法,我们可以写一个抽象基类:
public abstract class LoggerAdapterBase : ILogger { public abstract void Debug(string message, params object[] args); public abstract void Info(string message, params object[] args); public abstract void Warn(string message, params object[] args); public abstract void Error(string message, params object[] args); public abstract void Error(Exception ex, string message, params object[] args); public abstract void Fatal(string message, params object[] args); public abstract void Fatal(Exception ex, string message, params object[] args); }
3. 实现Serilog适配器
这个适配器把我们的ILogger接口方法映射到Serilog的日志方法:
using Serilog; public class SerilogLoggerAdapter : LoggerAdapterBase { private readonly Serilog.ILogger _logger; // 支持传入自定义Serilog实例,默认用全局Log.Logger public SerilogLoggerAdapter(Serilog.ILogger logger = null) { _logger = logger ?? Log.Logger; } public override void Debug(string message, params object[] args) => _logger.Debug(message, args); public override void Info(string message, params object[] args) => _logger.Information(message, args); public override void Warn(string message, params object[] args) => _logger.Warning(message, args); public override void Error(string message, params object[] args) => _logger.Error(message, args); public override void Error(Exception ex, string message, params object[] args) => _logger.Error(ex, message, args); public override void Fatal(string message, params object[] args) => _logger.Fatal(message, args); public override void Fatal(Exception ex, string message, params object[] args) => _logger.Fatal(ex, message, args); }
4. 实现NLog适配器
同理,写NLog的适配器:
using NLog; public class NLogLoggerAdapter : LoggerAdapterBase { private readonly NLog.ILogger _logger; // 支持传入自定义NLog实例,默认用当前类的日志实例 public NLogLoggerAdapter(NLog.ILogger logger = null) { _logger = logger ?? LogManager.GetCurrentClassLogger(); } public override void Debug(string message, params object[] args) => _logger.Debug(message, args); public override void Info(string message, params object[] args) => _logger.Info(message, args); public override void Warn(string message, params object[] args) => _logger.Warn(message, args); public override void Error(string message, params object[] args) => _logger.Error(message, args); public override void Error(Exception ex, string message, params object[] args) => _logger.Error(ex, message, args); public override void Fatal(string message, params object[] args) => _logger.Fatal(message, args); public override void Fatal(Exception ex, string message, params object[] args) => _logger.Fatal(ex, message, args); }
5. 日志包装器(可选,统一处理逻辑)
如果需要给所有日志加统一前缀、过滤或者其他全局处理,可以写一个包装器类:
public class LogWrapper : ILogger { private readonly ILogger _logger; // 注入具体的适配器实例 public LogWrapper(ILogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } // 示例:给所有日志添加应用前缀 private string FormatMessage(string message) { return $"[MyApplication] {message}"; } public void Debug(string message, params object[] args) => _logger.Debug(FormatMessage(message), args); public void Info(string message, params object[] args) => _logger.Info(FormatMessage(message), args); public void Warn(string message, params object[] args) => _logger.Warn(FormatMessage(message), args); public void Error(string message, params object[] args) => _logger.Error(FormatMessage(message), args); public void Error(Exception ex, string message, params object[] args) => _logger.Error(ex, FormatMessage(message), args); public void Fatal(string message, params object[] args) => _logger.Fatal(FormatMessage(message), args); public void Fatal(Exception ex, string message, params object[] args) => _logger.Fatal(ex, FormatMessage(message), args); }
6. 完整使用示例
首先安装对应的NuGet包:
- 对于Serilog:
Install-Package Serilog和Install-Package Serilog.Sinks.Console - 对于NLog:
Install-Package NLog和Install-Package NLog.Config
然后在Program.cs里测试:
using System; class Program { static void Main(string[] args) { // 测试Serilog Console.WriteLine("=== 使用Serilog日志 ==="); ConfigureSerilog(); var serilogAdapter = new SerilogLoggerAdapter(); var logger = new LogWrapper(serilogAdapter); TestLogger(logger); Console.WriteLine("\n=== 切换到NLog日志 ==="); // 测试NLog ConfigureNLog(); var nlogAdapter = new NLogLoggerAdapter(); logger = new LogWrapper(nlogAdapter); TestLogger(logger); } // 配置Serilog private static void ConfigureSerilog() { Serilog.Log.Logger = new Serilog.LoggerConfiguration() .MinimumLevel.Debug() .WriteTo.Console() .CreateLogger(); } // 配置NLog(也可以用NLog.config文件) private static void ConfigureNLog() { var config = new NLog.Config.LoggingConfiguration(); var consoleTarget = new NLog.Targets.ConsoleTarget("console") { Layout = "${date:format=HH:mm:ss} ${level} ${message}" }; config.AddRule(NLog.LogLevel.Debug, NLog.LogLevel.Fatal, consoleTarget); NLog.LogManager.Configuration = config; } // 测试日志方法 private static void TestLogger(ILogger logger) { logger.Debug("这是一条Debug级别的日志"); logger.Info("这是一条Info级别的日志"); logger.Warn("这是一条Warn级别的日志"); try { throw new InvalidOperationException("模拟业务异常"); } catch (Exception ex) { logger.Error(ex, "执行操作时发生错误"); } logger.Fatal("这是一条Fatal级别的日志"); } }
方案优势
- 解耦业务与日志框架:业务代码只依赖
ILogger接口,完全不用关心底层用的是Serilog还是NLog - 扩展性强:新增其他日志框架(比如log4net)只需要写对应的适配器类,不用修改任何业务代码
- 统一处理逻辑:通过
LogWrapper可以轻松添加全局日志处理,比如前缀、上下文信息、日志过滤等
内容的提问来源于stack exchange,提问作者Renugopal
相关产品推荐
相关产品推荐

