自定义在NLog中何时捕获堆栈跟踪

3

我正在编写一个自定义的NLog目标,继承自TargetWithLayout,我希望根据特定的日志事件,可选择地写入堆栈跟踪。我已经定义了一个嵌套布局,类似于这样(语法可能不正确):

Layout layout = "${when:${event-properties:StackTraceEnabled}==true:${stacktrace}}";

而且我会创建类似这样的事件:

var logEventInfo = new NLog.LogEventInfo(NLog.LogLevel.Error, "Test", "Test")
{
    Properties =
    {
        { "StackTraceEnabled", true },
    }
};

然而,这样做不起作用,似乎违背了 NLog 的设计。从我所了解的很少信息来看,NLog 会根据其注册的目标评估 GetStackTraceUsage(),然后要么始终生成堆栈跟踪,要么从不生成。这是正确的吗?在事件级别上是否有自定义堆栈跟踪生成的方法?

这是一个性能问题还是渲染问题?因为后者应该可以工作 - 它被捕获了,但当 StackTraceEnabled == false 时不应该被渲染。 - Julian
这是一个性能考虑。我每秒记录成千上万次的info级别事件,而我只想捕获一小部分的堆栈跟踪。 - Þórir Sachie
2个回答

1
一个解决方案是使用两个目标实例,然后仅使用记录器名称来控制它是否应该使用配置为写入 StackTrace 的目标。
<logger name="StackTraceEnabled" writeTo="target1_stacktrace" final="true">
<logger name="*" writeTo="target2_default" />

现在,NLog仅基于Logger名称决定是否应包括StackTrace。它查找与Logger名称匹配的所有日志记录规则,如果其中一个包含具有stacktrace的目标,则将进行捕获(与规则是否具有条件过滤器无关)

很容易修复NLog,使其在尝试捕获StackTrace之前也检查过滤器条件(允许对除Logger名称以外的其他内容进行过滤器优化)。


0
确认接受的答案所述:如果任何NLog目标需要堆栈跟踪以获取任何消息(无论过滤器如何),并且NLog.LoggerImpl.Write内部方法会捕获堆栈跟踪,而且如果LogEventInfo实例尚未具有堆栈跟踪。根据LoggerImpl.cs的说明:
internal static class LoggerImpl
{
    internal static void Write([NotNull] Type loggerType, TargetWithFilterChain targets, LogEventInfo logEvent, LogFactory factory)
    {
        if (targets == null)
            return;

        StackTraceUsage stu = targets.GetStackTraceUsage();
        if (stu != StackTraceUsage.None && !logEvent.HasStackTrace)
        {
            var stackTrace = new StackTrace(StackTraceSkipMethods, stu == StackTraceUsage.WithSource);
            var stackFrames = stackTrace.GetFrames();
            int? firstUserFrame = FindCallingMethodOnStackTrace(stackFrames, loggerType);
            int? firstLegacyUserFrame = firstUserFrame.HasValue ? SkipToUserStackFrameLegacy(stackFrames, firstUserFrame.Value) : (int?)null;
            logEvent.GetCallSiteInformationInternal().SetStackTrace(stackTrace, firstUserFrame ?? 0, firstLegacyUserFrame);
        }

        // ...
    }
}

上述方法将避免捕获实际的堆栈跟踪,即使只是一个占位符,如果已经明确设置了。因此,显式地将堆栈跟踪设置为占位符是防止NLog为这些特定日志条目生成堆栈跟踪的最简单方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接