You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取ILogger.Log格式化输出以用于其他目标场景?

如何在遵循ILogger格式化规范的同时,直接获取格式化后的日志消息用于UI展示?

业界普遍推荐让ILogger自行格式化日志消息,而非传入预格式化字符串,CA2254规则会对这种不当用法提出警告。但在UI应用中,经常需要同时把日志消息输出到日志系统和UI(比如错误弹窗),这时开发者很容易写出违反规范的代码:

string message = $"Exception while doing a thing. Code={ex.Code}, {ex.Message}";
_logger.LogError(message);
Dialog.Open(Icon.Error, message);

除了重复编写格式化逻辑的方式外,有没有简洁的方法,既能以符合ILogger要求的方式定义消息,又能在调用日志方法的同一上下文直接获取格式化后的结果?注意:这里不是指通过监听日志流再导入UI列表的方式,比如能否实现类似以下代码的效果——既保持日志的正常效率,又能直接拿到格式化后的内容:

LogMessage message = new(LogLevel.Error, "Exception while doing a thing. Code={exCode}, {exMessage}", ex.Code, ex.Message);
_logger.Log(message);
Dialog.Open(Icon.Error, message.ToString());

方法1:自定义LogMessage类并复用ILogger格式化逻辑

自己实现一个LogMessage类,内部复用.NET官方的日志格式化逻辑,既符合ILogger规范,又能直接获取格式化后的字符串:

public class LogMessage
{
    public LogLevel Level { get; }
    public string MessageTemplate { get; }
    public object[] Args { get; }

    public LogMessage(LogLevel level, string messageTemplate, params object[] args)
    {
        Level = level;
        MessageTemplate = messageTemplate;
        Args = args;
    }

    public override string ToString()
    {
        // 复用官方格式化逻辑,保证和ILogger输出完全一致
        return LoggerMessageFormatter.Format(MessageTemplate, Args);
    }
}

// 扩展ILogger,支持直接传入LogMessage
public static class LoggerExtensions
{
    public static void Log(this ILogger logger, LogMessage logMessage)
    {
        logger.Log(logMessage.Level, logMessage.MessageTemplate, logMessage.Args);
    }
}

使用方式完全符合你的预期:

var message = new LogMessage(LogLevel.Error, "Exception while doing a thing. Code={exCode}, {exMessage}", ex.Code, ex.Message);
_logger.Log(message);
Dialog.Open(Icon.Error, message.ToString());

方法2:用扩展方法同时完成日志记录和返回格式化消息

如果不想额外定义类,可以写一个轻量的扩展方法,在记录日志的同时直接返回格式化后的内容:

public static class LoggerUiExtensions
{
    public static string LogAndGetFormattedMessage(this ILogger logger, LogLevel level, string messageTemplate, params object[] args)
    {
        var formattedMessage = LoggerMessageFormatter.Format(messageTemplate, args);
        logger.Log(level, messageTemplate, args);
        return formattedMessage;
    }
}

使用时更简洁:

var formattedMsg = _logger.LogAndGetFormattedMessage(LogLevel.Error, "Exception while doing a thing. Code={exCode}, {exMessage}", ex.Code, ex.Message);
Dialog.Open(Icon.Error, formattedMsg);

方法3:强类型委托实现(极致性能)

如果追求最高性能,可以使用LoggerMessage.Define预编译日志委托,同时封装格式化逻辑:

public static class ErrorLogMessages
{
    private static readonly Action<ILogger, int, string, Exception> _operationFailed =
        LoggerMessage.Define<int, string>(LogLevel.Error, new EventId(1, "OperationFailed"), 
            "Exception while doing a thing. Code={ExCode}, {ExMessage}");

    public static string LogOperationFailed(ILogger logger, int exCode, string exMessage, Exception ex)
    {
        _operationFailed(logger, exCode, exMessage, ex);
        return LoggerMessageFormatter.Format("Exception while doing a thing. Code={ExCode}, {ExMessage}", exCode, exMessage);
    }
}

使用方式:

var formattedMsg = ErrorLogMessages.LogOperationFailed(_logger, ex.Code, ex.Message, ex);
Dialog.Open(Icon.Error, formattedMsg);

关键注意事项

  • 所有方法都复用了官方的LoggerMessageFormatter.Format,确保格式化结果和ILogger输出完全一致,避免自定义格式化带来的差异。
  • 绝对不要手动实现格式化逻辑,否则会违反CA2254规则的初衷——ILogger需要原始模板和参数来生成结构化日志,预格式化会丢失这些元数据。

内容的提问来源于stack exchange,提问作者Hamish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 11:47:15