Как использовать log4net с инъекцией зависимостей


Я пытаюсь выяснить, что такое правильная скороговорка и использование log4net с каркасом инъекции зависимостей.

Log4Net использует интерфейс ILog, но требует, чтобы я позвонил

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

в каждом классе или методе, где мне нужно войти информация. Это, кажется, идет вразрез с принципами МОК и связывает меня с использованием 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);
    }
}
4 75

4 ответа:

Я думаю, что вы не видите леса за деревьями здесь. ILog и LogManager-это легкий фасад почти 1: 1, эквивалентный Apache commons-logging, и фактически не связывает ваш код с остальной частью log4net.

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

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

Что касается включения контекстного состояния в каждое сообщение журнала, вам нужно добавить глобальный чья собственность ToString() решает то, что вы ищете. Например, для текущего размера кучи:

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

затем подключить его во время запуска:

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

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

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

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

другой способ сделать это - подключить последовательность регистрации контейнера интерфейса log4net ILog следующим образом: (используя замок в ASP.NET контекст ниже в качестве примера)

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

и просто конструктор-inject ILog всякий раз, когда вам это нужно.