在自定义NLog目标中检索HttpContext

时间:2014-02-23 18:12:54

标签: logging nlog httpcontext

我可能会遗漏一些基本的东西 - 但是可以在自定义的NLog事件中检索HttpContext.Current吗?

我试图给每个请求一个唯一的Guid,以便我可以将记录消息与单个事件相关联(即,将单个请求的每个日志事件联系在一起)。所以,我想将这个Guid存储在HttpContext.Current.Items中,然后在NLog目标中检索它并将其包含在日志消息中。

这是我想要访问HttpContext.Current的示例目标:

[Target("AzureTableTarget")]
public class AzureTableTarget : TargetWithLayout
{

    public AzureTableTarget()
    {
        _appSettings = IoCResolver.Get<IAppSettings>();
    }

    protected override void Write(LogEventInfo logEvent)
    {
        var correlationId = HttpContext.Current; //This is always null

        var batchOperation = new TableBatchOperation();
        CxLogEventBuilder.Build(_appSettings, logEvent).ForEach(batchOperation.Insert);
        _loggingTable.ExecuteBatchAsync(batchOperation);
    }
}

3 个答案:

答案 0 :(得分:0)

这篇关于Working with HttpContext.Current的文章可能有所帮助。对你而言,关键可能是当控制从一个线程传递到另一个线程时,新线程中的HttpContext.Current可以为null。

这是SO上的另一个question/answer,它描述了HttpContext.Current在Web服务的上下文中为null。接受的答案建议在web.config文件中启用ASP.Net兼容性。

我不知道其中任何一个会有所帮助,但他们可能会这样做。我通过谷歌搜索找到了#34; HttpContext.Current为null&#34;,它产生了相当多的点击量。我做了很少的ASP.NET开发,所以我无法根据自己的亲身经验对HttpContext.Current发表评论。

根据您的使用案例,我建议您查看System.Diagnostics.CorrelationManager.ActivityId

ActivityId的一个很好的功能是它已经流动了#34;从父线程到子线程(包括线程池线程)。我认为它适用于任务和并行操作。运行良好意味着在父线程中设置的ActivityId在子线程中具有期望值。

ActivityId没有LayoutRenderer,但写一个就足够了。在这里查看一个示例(针对NLog 1.0编写):

Most useful NLog configurations

我非常确定&#34; EstimatedBufferSize&#34;不再需要东西,所以类似的东西可能会起作用:

[LayoutRenderer("ActivityId")]
class ActivityIdLayoutRenderer : LayoutRenderer
{
  protected override void Append(StringBuilder builder, LogEventInfo logEvent)
  {
    builder.Append(Trace.CorrelationManager.ActivityId);
  }
}

如果你走这条路线,你可以考虑将一个Format属性添加到ActivityIdLayoutRenderer,以允许你指定guid格式。看到这个答案(来自我)。它包含许多有关使用guid的有用信息。

NewGuid vs System.Guid.NewGuid().ToString("D");

有关如何实现和使用此类Format属性的示例,请参阅此源文件(在NLog&#git存储库中):

https://github.com/NLog/NLog/blob/master/src/NLog/LayoutRenderers/GuidLayoutRenderer.cs

答案 1 :(得分:0)

如今,在NLog目标中检索HTTP上下文更加容易(适用于ASP.NET和ASP.NET Core)

  1. 安装NLog.Web(ASP.NET)或NLog.Web.AspNetCore(ASP.NET Core)软件包
  2. 对于ASP.NET核心,请遵循ASP.NET Core - NLog setup
  3. 继承自AspNetLayoutRendererBase(命名空间NLog.Web.LayoutRenderers
  4. 通过致电var context = HttpContextAccessor.HttpContext;
  5. 来获取请求

示例:

[LayoutRenderer("aspnet-sessionid")]
[ThreadSafe]
public class AspNetSessionIdLayoutRenderer : AspNetLayoutRendererBase
{
    protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
    {
        var context = HttpContextAccessor.HttpContext;
        var contextSession = context?.Session();
        if (contextSession == null)
        {
             InternalLogger.Debug("HttpContext Session Lookup returned null");
             return;
        }

        builder.Append(contextSession.SessionID); // ASP.NET Core: contextSession.Id
    }
}

PS:目前有许多针对ASP.NET(核心)的预定义渲染器:https://nlog-project.org/config/?tab=layout-renderers&search=aspnet

答案 2 :(得分:0)

如果您的自定义目标应该捕获一个(或多个)特定于上下文的值,那么我建议您的目标继承自TargetWithContext(或AsyncTaskTarget)。

它可以设置和捕获contextproperty个项目。可以分配布局以捕获上下文细节的位置。可以从HttpContext轻松获得可能的上下文细节的示例:

https://nlog-project.org/config/?tab=layout-renderers&search=package:nlog.web.aspnetcore

有关编写自定义目标的更多详细信息:

https://github.com/NLog/NLog/wiki/How-to-write-a-custom-target-for-structured-logging

https://github.com/NLog/NLog/wiki/How-to-write-a-custom-async-target

顺便说一句。已经存在一个很好地继承自AsyncTaskTarget的自定义目标:

https://www.nuget.org/packages/NLog.Extensions.AzureCosmosTable/