我可能会遗漏一些基本的东西 - 但是可以在自定义的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);
}
}
答案 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)
AspNetLayoutRendererBase
(命名空间NLog.Web.LayoutRenderers
)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
答案 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/