You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用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

火山引擎 最新活动