如何用Serilog优雅记录.NET 4.6.2 WPF中方法启动及参数值?
优雅实现WPF中Serilog的方法启动日志记录
你这个需求很常见,咱们可以利用Serilog的结构化日志特性,结合C#的语法糖来实现一个简洁又好用的方法。我给你梳理两种方案,既能满足你手动传方法名的需求,还能优化成自动获取方法名的版本,让调用更省心。
第一步:调整SerilogHelper为单例模式
因为你要调用静态的StartingMethod,咱们先把原来的SerilogHelper改成单例,确保Logger只初始化一次,同时静态方法能稳定访问到日志实例:
public class SerilogHelper { // 用Lazy实现线程安全的单例 private static readonly Lazy<SerilogHelper> _instance = new Lazy<SerilogHelper>(() => new SerilogHelper()); public static SerilogHelper Instance => _instance.Value; public ILogger Logger { get; } private SerilogHelper() { Logger = CreateLogger(); } private ILogger CreateLogger() { // 你的原有初始化代码完全保留 string levelString = Properties.Settings.Default.SerilogLevel; SerilogLevel level = (SerilogLevel)Enum.Parse(typeof(SerilogLevel), levelString); var levelSwitch = new LoggingLevelSwitch(); levelSwitch.MinimumLevel = (Serilog.Events.LogEventLevel)level; string acName = Properties.Settings.Default.LoggingAccountName; string acKey = Properties.Settings.Default.LoggingAccountKey; var creds = new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(acName, acKey); var azureAccount = new Microsoft.WindowsAzure.Storage.CloudStorageAccount(creds, true); return new LoggerConfiguration() .MinimumLevel.ControlledBy(levelSwitch) .WriteTo.File("log.txt", rollOnFileSizeLimit: true) .WriteTo.AzureTableStorage(azureAccount) .CreateLogger(); } // 保留你原来的WriteString方法 public void WriteString(string content) { Logger.Debug(content); } }
第二步:实现方法启动日志方法
方案1:手动传方法名和参数(完全匹配你的调用示例)
新增一个静态方法,支持手动传入方法名和任意参数,利用Serilog的@符号序列化参数对象,让日志以结构化形式展示:
public static void StartingMethod(string methodName, object parameters = null) { if (parameters == null) { Instance.Logger.Debug("Method starting: {MethodName}", methodName); } else { // 使用@Parameters让Serilog完整序列化参数对象,保留键值结构 Instance.Logger.Debug("Method starting: {MethodName}. Parameters: {@Parameters}", methodName, parameters); } }
调用方式非常灵活:
// 无参数的方法 SerilogHelper.StartingMethod("MyEmptyMethod"); // 带参数的方法,用匿名对象传递(推荐,能保留参数名) SerilogHelper.StartingMethod("MyDataProcessingMethod", new { UserId = 123, InputFilePath = @"C:\data.txt", IsAsync = true });
如果你习惯用params数组传参数,也可以加个重载:
public static void StartingMethod(string methodName, params object[] parameters) { var paramDict = parameters.Select((p, index) => new { Index = index, Value = p }) .ToDictionary(x => $"Param{x.Index}", x => x.Value); Instance.Logger.Debug("Method starting: {MethodName}. Parameters: {@Parameters}", methodName, paramDict); }
调用示例:
SerilogHelper.StartingMethod("MyCalculationMethod", 100, 200, "Addition");
方案2:自动获取方法名(更优雅,避免手动输入错误)
利用[CallerMemberName]特性,让方法自动获取调用方的方法名,不用手动传字符串,减少出错概率:
using System.Runtime.CompilerServices; // 需要引用这个命名空间 public static void StartingMethod(object parameters = null, [CallerMemberName] string methodName = null) { if (parameters == null) { Instance.Logger.Debug("Method starting: {MethodName}", methodName); } else { Instance.Logger.Debug("Method starting: {MethodName}. Parameters: {@Parameters}", methodName, parameters); } }
调用时更简洁,直接在目标方法里写:
public void ProcessUserData(int userId, string username) { // 自动获取方法名"ProcessUserData",无需手动输入 SerilogHelper.StartingMethod(new { userId, username }); // 你的业务代码... }
为什么这么实现?
- 结构化日志:Serilog的
@符号会把参数对象序列化成可读的键值结构,不管是本地日志文件还是Azure Table Storage,都能清晰看到每个参数的具体值,方便排查问题。 - 灵活性:支持无参数、匿名对象、params数组三种调用方式,适配不同场景。
- 性能优化:用Lazy实现单例,确保Logger只初始化一次,避免重复创建资源。
内容的提问来源于stack exchange,提问作者Rob Bowman




