Log4net logger, определенный в базовом классе

Я хочу построить свой логгер log4net в моем базовом классе контроллера MVC следующим образом:

protected static readonly ILog Log = LogManager.GetLogger(typeof(AuthorizedController));

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

Что было бы хорошим KISS, DRY и эффективным способом сделать это?

Ответ 1

Я не уверен, насколько дорогой вызов LogManager.GetLogger(), но я подозреваю, что в системе log4net есть некоторая умная кэширование и/или ленивая инициализация, которая позволяет запрашивать экземпляры для быстрого извлечения. В конце концов, нет причин, по которым вызов LogManager.GetLogger() дважды с тем же параметром типа возвращал бы другой экземпляр.

Тем не менее, возможно, заменяя поле следующим свойством.

protected ILog Logger
{
    get { return LogManager.GetLogger(GetType()); }
}

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

Ответ 2

Я сделал что-то подобное, используя NInject в качестве контейнера IoC, но, полагаю, вы можете воспользоваться идеей для использования с вашим собственным контейнером, В основном я вставляю ILog в конструктор запрашивающих типов, но вместо привязки к экземпляру привязываю его к провайдеру.

  kernel.Bind<ILog>().ToProvider<MyProvider>();

public object Create(IContext context)
{
    return LogManager.GetLogger(context.Request.Target.Member.DeclaringType);
}

чтобы каждый тип получал регистратор, который является тем же самым, что и GetLogger(GetType()) в конструкторе.

Ответ 3

Наличие статического регистратора (или статических экземпляров в целом) является плохой практикой. Это может легко привести к нежелательной связи между несвязанными компонентами.

Вам следует рассмотреть возможность добавления в игру зависимости Injection/Inverse of Control. Попросите регистратора ввести в ctor класса. Большинство фреймворков позволяет вам определять разные реализации в разных контекстах.

Мы используем Castle Windsor в наших продуктах

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

Ответ 4

Как предложил Стив Гуиди - используйте GetType для создания регистратора для конкретного экземпляра типа. Вы можете сохранить ссылку на экземпляр регистратора, который вызывает вызов LogManager.GetLogger в поле поддержки:

    private ILog _log;
    protected ILog Log => _log ?? (_log = LogManager.GetLogger(GetType()));