Получение HttpContext в пользовательской цели NLog

Я могу упустить что-то основное здесь, но можно ли получить HttpContext.Current в пользовательском событии NLog?

Я пытаюсь дать каждому запросу уникальный 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);
    }
}

person MattW    schedule 23.02.2014    source источник


Ответы (3)


В настоящее время легче получить контекст HTTP в цели NLog (работает для ASP.NET и ASP.NET Core).

  1. Установите NLog.Web (ASP.NET) или NLog.Web.AspNetCore (ASP.NET Core)
  2. Для ядра ASP.NET следуйте ASP. NET Core — настройка NLog
  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 (Core): https://nlog-project.org/config/?tab=layout-renderers&search=aspnet

person Julian    schedule 29.11.2019

Эта статья о работе с HttpContext.Current может помочь. Ключевым моментом для вас может быть то, что при передаче управления из одного потока в другой HttpContext.Current в новом потоке может быть нулевым.

Вот еще один вопрос/ответ отсюда на SO, который описывает HttpContext.Current имеет значение null в контексте веб-службы. В принятом ответе предлагается включить совместимость с ASP.Net в файле web.config.

Я не знаю ни один из них поможет, но они могли бы. Я нашел их, погуглив «HttpContext.Current is null», что дало довольно много совпадений. Я очень мало занимался разработкой ASP.NET, поэтому не могу комментировать HttpContext.Current, исходя из своего личного опыта.

Учитывая ваш вариант использования, я бы посоветовал вам изучить System.Diagnostics.CorrelationManager.ActivityId.

Одна приятная особенность ActivityId заключается в том, что он «перетекает» из родительских потоков в дочерние потоки (включая потоки пула потоков). Я думаю, что это хорошо работает с задачами и параллельными операциями. Хорошо работает, что означает, что ActivityId, установленный в родительском потоке, имеет ожидаемое значение в дочернем потоке.

Для ActivityId нет LayoutRenderer, но его достаточно легко написать. См. пример (написанный для NLog 1.0) здесь:

Наиболее полезные конфигурации NLog

Я почти уверен, что материал "EstimatedBufferSize" больше не нужен, поэтому, вероятно, сработает что-то вроде:

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

Если вы пойдете по этому пути, вы можете рассмотреть возможность добавления свойства Format в ActivityIdLayoutRenderer, чтобы позволить вам указать формат guid. Смотрите этот ответ (от меня). Он содержит много полезной информации о работе с гидами.

NewGuid vs System.Guid.NewGuid().ToString(D);< /а>

См. этот исходный файл (в git-репозитории NLog) для примера того, как вы можете реализовать и использовать такое свойство Format:

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

person wageoghe    schedule 24.02.2014

Если ваша настраиваемая цель должна захватывать одно (или несколько) контекстно-зависимых значений, я рекомендую, чтобы ваша цель наследовалась от 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/< /а>

person Rolf Kristensen    schedule 29.11.2019