Как вывести контекстный класс, используя log4net как сервис?

#dependency-injection #log4net #structuremap

#внедрение зависимостей #log4net #structuremap

Вопрос:

Я использую Log4Net как сервис, который внедряется в другие сервисы с помощью StructureMap.

Как мне убедиться, что файл журнала включает контекст вызывающего класса сервиса (имя класса и / или поток), который выполняет вызовы log4net?

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

Редактировать:

Код регистрации:

   ObjectFactory.Initialize(x =>
    {           
        x.For<ILog>().AlwaysUnique().Use(s => s.ParentType == null ? 
            LogManager.GetLogger(s.BuildStack.Current.ConcreteType) : 
            LogManager.GetLogger(s.ParentType));

    });
  

Уровень сервиса:

 public class LoggerService : ILoggerService
    {
        private readonly ILog log;

        public LoggerService(ILog logger)
        {            
            log = logger;
            log.Info("Logger started {0}".With(logger.Logger.Name));
        }       

        public void Info(string message)
        {
            log.Info(message);
        }
}
  

При протоколировании я по-прежнему всегда получаю LoggerService в качестве контекста, поэтому я никогда не увижу, что на самом деле вызвало регистратор. Похоже, что он работает некорректно. Я чувствую, что здесь я чего-то не понимаю…

Правка 2: Я добавил сюда ссылку на вставку для консольного приложения:

http://pastie.org/1897389

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

Комментарии:

1. Кажется, вы абстрагировали регистратор до уровня выше того, что я обычно делаю, но попробуйте это для ObjectFactory. Вместо этого инициализируйте: замените [LogManager. getLogger(s.ParentType)] с помощью [LogManager. getLogger(s.ParentType. UnderlyingSystemType.Name ))]

2. @Bryan — Я пробовал использовать s.root. Конкретный тип. Назовите вместо этого и настройте app.config на использование %logger для вывода имени регистратора. Хотя это не дает мне имя регистратора SubActionService (см. Мою ссылку ниже). UnderlyingSystemType всегда LoggerService, что не помогает.

3. Попробуйте использовать точку останова внутри [x.Для<ILog>(). AlwaysUnique(). Используйте] лямбда-выражение, изучите в окне просмотра значение [s.ParentType] и перейдите к значению, которое вы ищете. Это то, что я использовал при использовании вашего исходного кода для просмотра родительского типа внедренного класса.

Ответ №1:

Возможно, вы захотите взглянуть на Castle Dynamic proxy, чтобы решить эту проблему с помощью AOP. В группе Google Structure Map есть пример его использования со Structure Map.

У Ayende есть пример ведения журнала на основе AOP с использованием Log4Net и Windsor.

Комментарии:

1. Спасибо за ссылки. Есть ли какой-либо способ использовать StructureMap, поскольку это то, что мое приложение в настоящее время использует для DI?

2. Да, взгляните на пример, на который я ссылался, используя StructureMap: bit.ly/mmAsN5 (он использует более старый синтаксис для SM, но принцип тот же). По сути, вы используете EnrichWith и оборачиваете экземпляры, которые хотите регистрировать, с помощью DynamicProxy и реализуете перехватчик ведения журнала. Перехватчик в примере регистрируется на консоли, но вы могли бы переключить его на Log4Net.

Ответ №2:

Я использую StructureMap во многих кодах, которые я генерирую, и у меня есть реестр StructureMap, который я использую для подключения регистратора к контексту класса, в который он внедряется.

Для справки, я использую версию StructureMap 2.6.2, но должно подойти и 2.5 , где используется новый формат .For<>().Use<>() .

 public class CommonsRegistry : Registry
{
  public CommonsRegistry()
  {
    For<ILogger>().AlwaysUnique().Use(s => s.ParentType == null ? new Log4NetLogger(s.BuildStack.Current.ConcreteType) : new Log4NetLogger(s.ParentType.UnderlyingSystemType.Name));
    XmlConfigurator.ConfigureAndWatch(new FileInfo(Path.Combine(Path.GetDirectoryName(Assembly.GetAssembly(GetType()).Location), "Log.config")));
  }
}
  

Что делает этот реестр, так это для того, чтобы везде, где внедряется ILogger, использовать класс, в который он внедряется, где регистрируются сообщения журнала / context of.

*Кроме того, во второй строке (XmlConfigurator.ConfigureAndWatch) — это место, где я говорю Log4Net получать информацию о протоколировании из файла «Log.config» вместо файла конфигурации приложения, вам это может понравиться, а может и не понравиться, и его можно опустить.

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

 ObjectFactory.Initialize(x =>
{
  x.AddRegistry<CommonsRegistry>();
  ...
}
  

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

 class foo
{
  private readonly ILogger _log;

  public foo(ILogger log)
  {
    _log = log;
  }
}
  

Теперь сообщения регистрируются как контекст / класс «foo».

Комментарии:

1. Привет, как это соотносится с функцией обогащения из первого предложения? Я пытаюсь взвесить плюсы / минусы для обоих вариантов. Хотя выглядит неплохо!

2. В документации enrich говорится «EnrichWith() — Регистрирует функцию, которая выполняется для нового объекта после создания и дает вам возможность возвращать объект, отличный от исходного объекта», где моя функция реестра находится во время создания регистратора, установите соответствующий контекст (родительский класс foo в моем примере).

3. @jaffa — как говорит @Bryan, EnrichWith заменяет объект новым объектом. В случае ведения журнала с использованием DynamicProxy вы бы создали класс-оболочку вокруг целевого объекта, который выполняет ведение журнала. Преимущество использования AOP заключается в том, что вам не нужно добавлять код ведения журнала в каждое место, куда вы хотите войти, он будет перехвачен во время выполнения и автоматически зарегистрирован. Смотрите сообщение Ayendes для некоторого дальнейшего объяснения.

4. Обновлена процедура CommonsRegistry.