Як використовувати log4net із ін’єкцією залежностей


78

Я намагаюся зрозуміти, яким правильним є шаблон і використання log4net у рамках інжекції залежностей.

Log4Net використовує інтерфейс ILog, але вимагає від мене зателефонувати

LogManager.GetLogger(Reflection.MethodBase.GetCurrentMethod().DeclaringType)

у кожному класі або методі, де мені потрібно реєструвати інформацію. Здається, це суперечить принципам IoC і змушує мене використовувати Log4Net.

Чи я повинен якось вкласти десь інший шар абстракції?

Крім того, мені потрібно реєструвати власні властивості, такі як поточне ім’я користувача, як це:

log4net.ThreadContext.Properties["userName"] = ApplicationCache.CurrentUserName;

Як я можу інкапсулювати це, щоб мені не потрібно було пам'ятати, щоб це робити щоразу, і при цьому підтримувати поточний метод, який реєструється. мені робити щось подібне або мені зовсім не вистачає позначки?

public static class Logger
{
    public static void LogException(Type declaringType, string message, Exception ex)
    {
        log4net.ThreadContext.Properties["userName"] = ApplicationCache.CurrentUserName;
        ILog log = LogManager.GetLogger(declaringType);
        log.Error(message, ex);
    }
}

1
Більш цікаве питання - який DI-контейнер ви використовували?
CodeMonkeyKing

Відповіді:


61

Я думаю, ти не бачиш тут лісу за деревами. ILog та LogManager - це легкий фасад майже 1: 1, еквівалентний спільному реєструванню Apache, і насправді не поєднує ваш код із залишком log4net.

<rant>
Я також виявив, що майже завжди, коли хтось створює обгортку MyCompanyLogger навколо log4net, він погано пропускає суть, або втратить важливі та корисні можливості фреймворку, викине корисну інформацію, втратить збільшення продуктивності, навіть використовуючи спрощений інтерфейс ILog, або все вищезазначене. Іншими словами, обтікання log4net, щоб уникнути зв’язку з ним, є анти-шаблоном .
</rant>

Якщо вам потрібно ввести його, зробіть примірник реєстратора доступним через властивість, щоб увімкнути ін’єкцію, але створіть екземпляр за замовчуванням старомодним способом.

Що стосується включення контекстного стану в кожне повідомлення журналу, вам потрібно додати глобальну властивість, ToString()розв’язання якої ви шукаєте. Як приклад, для поточного розміру купи:

public class TotalMemoryProperty
{
    public override string ToString()
    {
        return GC.GetTotalMemory(false).ToString();
    }
}

Потім підключіть його під час запуску:

GlobalContext.Properties["TotalMemory"] = new TotalMemoryProperty();

7
Ваша сказка тут далеко від бази. Цей хлопець запитував про те, як ввести екземпляр ILog у його об’єкти, що знаходяться всередині контейнера. Є багато причин для цього.
CodeMonkeyKing

1
@CodeMonkeyKing: Рант був спрямований на запропонований ним підхід створення рівня абстракції між log4net та його кодом, і особливо на зразковому блоці коду в кінці запитання.
Джеффрі Хантін,

4
@JeffreyHantin Це може бути анти-шаблоном на вашу думку, але я виявив, що існує стільки думок, скільки є інженерів, що пишуть код. Моя думка, звичайно :)
CodeMonkeyKing

1
Я розумію, що це стара публікація, але не могли б ви пояснити, чому така обгортка "погана"? ILog та LogManager перебувають у просторі імен log4net, і, використовуючи ці типи у всьому коді, це не пов’язує мене з log4net? Чого мені тут не вистачає?
Ендрю Стівенс,

1
Обгортання log4net - чудова практика. Проблема полягає не в обгортанні бібліотеки, а в тому, що вона працює погано.
Ден,

2

Як я це зробив, це створив свій власний інтерфейс, і клас реалізував той інтерфейс, який використовував Log4Net, і ввів цей клас. Таким чином, ви не прив'язані до Log4Net ... ви можете просто створити інший клас для нового реєстратора та ввести цей клас.


2

Якщо ви дійсно стурбовані наявністю декількох реєстраторів, ви завжди можете оголосити глобальний реєстратор і зателефонувати для всіх ваших потреб ведення журналу. Недоліком цього є те, що ви втрачаєте вбудовану здатність ідентифікувати клас, з якого видано журнал, але ви також можете внести своє власне повідомлення в журнал для ідентифікації класу.

Це залежить від того, наскільки надійним ви хочете, щоб журналювання було. Ви також можете просто поставити реєстратор в основний клас і дозволити всім обробленим виняткам піднятися до нього для реєстрації.


Але, звичайно, ви зазвичай хочете реєструвати не лише винятки?
UpTheCreek,

Ви пропонуєте тут шаблон Singleton? Я сподіваюся, що не.
Nate Zaugg

2

Іншим способом зробити це буде підключення послідовності реєстрації контейнерів інтерфейсу log4net ILog, як це: (використовуючи Castle в контексті ASP.NET нижче як приклад)

container.Register(Component.For<ILog>().LifeStyle
    .PerWebRequest.UsingFactoryMethod(() => LogManager.GetLogger(
    MethodBase.GetCurrentMethod().DeclaringType)));

і просто конструктор-ін'єктуйте ILog, коли вам це потрібно.


Я думаю, це працює краще, коли ви отримуєте правильний реєстратор для побудованого класу реалізації:Component.For<ILog>().UsingFactoryMethod((kernel, model, cc) => LogManager.GetLogger(cc.Handler.ComponentModel.Implementation))
Позначте
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.