Службы WCF, ведение журнала по вертикали


Я рассматривал ведение журнала для служб WCF (включая такие технологии, как NLog и PostSharp), но у меня есть кое-что, что я еще не решил... Я не знаю, то ли я упускаю что-то очевидное, то ли это просто невозможно.

Допустим, у меня есть уровень обслуживания WCF с 100+ точками входа вызовов веб-служб. Один из них вызывает проблему. Ниже этого уровня находится уровень бизнес-логики и уровень базы данных. То, что я хочу сделать (я думаю), это включить ведение журнала для этого вызова службы (что было бы включите идентификатор действия для корреляции), так что любые вызовы этой службы регистрируются, и любые сообщения журнала на нижних уровнях также регистрируются. Я действительно не хочу включать ведение журнала на уровне сборки для нижних уровней, потому что они будут совместно использоваться многими методами веб-службы.

Возможно ли это вообще, через существующую структуру или используя что-то вроде CorrelationManager творческим способом?

2 6

2 ответа:

В log4net можно задать свойство контекста потока, которое будет включено во все события протоколирования для потока.

public class WcfServiceClass
{
    public void ProblemServiceMethod()
    {
        using (log4net.ThreadContext.Stacks["logThisMethod"].Push("ProblemServiceMethod"))
        {
            // can also add the correlationId to the logs using this method.
            // call business logic...

        }
    }
}

Затем Создайте пользовательский аппендер, который фильтрует по нему.

public class IfContextSetFilterAppender : log4net.Appender.AppenderSkeleton
{
    protected override void Append(LoggingEvent loggingEvent)
    {
        bool logThisEntry = false;
        string serviceMethodBeingLogged;

        foreach (object p in loggingEvent.GetProperties())
        {
            System.Collections.DictionaryEntry dEntry = (System.Collections.DictionaryEntry)p;
            if (dEntry.Key == "logThisMethod")
            {
                logThisEntry = true;
                serviceMethodBeingLogged = dEntry.Value.ToString();
            }
        }

        if (!logThisEntry)
            return; // don't log it.

        // log it.
    }
}
Это очень упрощенный (но ясный) пример идеи.

Если бы я действительно строил это в таком крупномасштабном сервисе, как вы описываете, я бы:

  1. Создайте поведение конечной точки IOperationInvoker , которое захватывает имя метода и задает значение контекста log4net для всех вызовов, к которым оно применяется.

  2. (необязательно) попросите аппендер прочитать из приложения.настройте список фильтров для всех имен методов службы,которые должны быть зарегистрированы. (Если вы избирательны в том, к каким методам применяется поведение OperationInvoker, аппендеру не нужна эта сложность.)

Таким образом, у вас есть несколько вариантов управления входом в производственную службу только через конфигурацию, никогда не касаясь сервисный код.

Можно создать новый источник ведения журнала для этого конкретного вызова службы, а затем включить диагностику для его фильтрации.

  <system.diagnostics>
    <sources>
      <source name="Your.Source.Here" switchValue="Verbose">
        <listeners>
          <add name="xml" />
        </listeners>
      </source>
    </sources>
    <sharedListeners>
      <add name="xml" type="System.Diagnostics.XmlWriterTraceListener" traceOutputOptions="LogicalOperationStack" initializeData="l:\logs\N4S.MSO.ADC.Host.svclog" />
    </sharedListeners>
  </system.diagnostics>