【问题标题】:Logging exception properties记录异常属性
【发布时间】:2010-11-22 17:43:51
【问题描述】:

是否可以用 NLog 记录异常的属性?

例如,SocketException 具有 ErrorCode、HResult、NativeErrorCode 等属性,这些属性仅适用于此类异常。可以在不显式记录(即不使用Log(e.ErrorCode))的情况下记录它们并仅使用代码中的ErrorException?默认的Exception layout renderer 只是在异常上调用 ToString。

【问题讨论】:

    标签: c# .net logging nlog


    【解决方案1】:

    我不知道这是否是一个很好的主意,但是您可以编写自己的 LayoutRenderer。为了简单起见,我只写了一个继承自 ExceptionLayoutRenderer 并覆盖 Append 方法的函数。

    [LayoutRenderer("ExtendedException")]
        public class ExtendedExceptionLayoutRenderer : ExceptionLayoutRenderer
        {
            protected override void Append(System.Text.StringBuilder builder, LogEventInfo logEvent)
            {
                base.Append(builder, logEvent);
    
                var exception = logEvent.Exception;
                if (exception is SocketException)
                {
                    var sockException = (SocketException) exception;
                    builder.Append(sockException.ErrorCode).Append(" ").Append(sockException.SocketErrorCode);
                }
            }
        }
    

    SocketException 的处理不是很复杂。我确信有更好的方法,但它显示了你可以如何做到这一点。

    要激活你必须像这样调整你的配置:

    <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <extensions>
            <add assemblyFile="YourAssembly.dll"/>
        </extensions>
    
        <targets>
            <target name="console" xsi:type="Console" layout="${extendedexception} ${message}"/>
        </targets>
    
        <rules>
            <logger name="*" minlevel="Debug" writeTo="console" />
        </rules>
    </nlog>
    

    编辑

    好的,我不知道您希望为每个具有自己属性的异常提供该功能。如果只有少数其他您感兴趣,您可以添加更多 if(exception is YourExceptionType) 并调整您感兴趣的属性。 更通用的方法是使用反射来记录异常中定义的所有属性。

    [LayoutRenderer("ExtendedException")]
        public class ExtendedExceptionLayoutRenderer : ExceptionLayoutRenderer
        {
            protected override void Append(System.Text.StringBuilder builder, LogEventInfo logEvent)
            {
                var exception = logEvent.Exception;
                var type = exception.GetType();
                var properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
    
                var logEntries = new SortedDictionary<string, string>();
    
                foreach (var property in properties)
                {
                    var name = property.Name;
                    var value = property.GetValue(exception, null).ToString();
                    logEntries.Add(name, value);
                }
    
                foreach (var entry in logEntries)
                {
                    builder.AppendFormat("{0}: {1} ", entry.Key, entry.Value);
                }
    
                base.Append(builder, logEvent);
            }
        }
    

    这会将按字母顺序在异常类型上声明的每个属性添加到日志输出中。

    【讨论】:

    • 我输入的内容完全相同。如果 NLog 直接提供能力,我不知道。如果您需要(或想要)这些信息并且 NLog 没有“免费”提供,那么您必须执行 @treze 建议的操作。
    • 在这种情况下,我必须为每种具有自己属性的异常类型创建渲染器:Win32Exception、WebException、HttpException 等等。
    • @Giorgi - 您可以只使用一个使用反射的布局渲染器来做到这一点。查看我编辑的帖子。
    • 这很酷。我不知道有可能获得在当前级别声明的属性。谢谢。
    【解决方案2】:

    我不熟悉 NLog,但是是否可以在 try / catch 块中捕获异常,然后抛出您自己类型的新异常,覆盖 ToString 以在新异常类型中输出您关心的数据?

    这会在一定程度上破坏跟踪,因此您可能必须在 ToString 输出中包含来自原始异常的跟踪信息,但这可能是一个很容易解决的问题。

    我的另一个想法是扩展和覆盖 SocketException 的 ToString,但我不相信这在 C# 中是可能的。

    【讨论】:

    • 这意味着我需要为每个暴露额外属性的异常类执行此操作。 SocketException 只是其中之一。我正在寻找更一般的东西。谢谢你的回答。
    • @Giorgi - 抱歉,没听清楚。您可以通过反射来实现相同的策略,以遍历所有类型的抛出异常的所有属性......虽然这开始感觉像是一个肮脏的黑客......
    【解决方案3】:

    序列化异常并记录结果流?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-02
      相关资源
      最近更新 更多