在自定义NLog目标中检索HttpContext

问题描述 投票:5回答:2

我可能在这里缺少一些基本知识-但是否可以在自定义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);
    }
}
c# logging nlog httpcontext
2个回答
0
投票

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

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

我不知道这两种方法都会有所帮助,但它们可能会有所帮助。我通过谷歌搜索“ HttpContext.Current为null”找到了它们,这产生了很多匹配。我很少进行ASP.NET开发,因此我无法根据自己的个人经验对HttpContext.Current进行评论。

鉴于您的用例,建议您研究System.Diagnostics.CorrelationManager.ActivityId

ActivityId的一个不错的功能是它从父线程“流”到子线程(包括线程池线程)。我认为它可以与“任务”和“并行”操作配合使用。运行良好,意味着在父线程中设置的ActivityId在子线程中具有预期值。

没有ActivityId的LayoutRenderer,但是编写一个很容易。在此处查看示例(针对NLog 1.0编写):

Most useful NLog configurations

我很确定不再需要“ EstimatedBufferSize”的东西,所以类似的东西可能会起作用:

[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");

请参见此源文件(在NLog的git存储库中,以获取有关如何实现和使用这种Format属性的示例:

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


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;获得请求

示例:

[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


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/

© www.soinside.com 2019 - 2024. All rights reserved.