Каков наилучший шаблон для использования одного Log4net-регистратора во многих сборках в решении?
У меня есть решение, состоящее из основного приложения winforms, с соответствующими внутренне написанными библиотеками библиотеки классов, из которых я хочу зарегистрироваться. Это ведение журнала должно выполняться одним и тем же журналом, независимо от того, вызывает ли этот основной клиент UI или связанные с ним DLL. Разумеется, библиотеки DLL могут использоваться другими приложениями, которые имеют разные регистраторы в других решениях, но в этих обстоятельствах будет иметь другую конфигурацию log4net и, возможно, совсем другой набор приложений.
Один из подходов заключался бы в создании Singleton в основном приложении и входе в него из журнала, однако, поскольку log4net является его собственным singleton, на который можно ссылаться, поскольку мы передаем одну и ту же строку (или тип) на log4net.LogManager.GetLogger
, мы будет регистрироваться в одном месте (в моем случае я хочу использовать RollingFileAppender).
Это работает. Однако, учитывая, что DLL будет иметь несколько классов, это означало бы, что каждый экземпляр класса или статический класс, из которого мы хотим регистрировать, потребует: i) аргумента, определяющего имя регистратора (для того, чтобы войти в тот же пункт назначения) и ii) в каждой точке входа необходимо вызвать log4net.LogManager.GetLogger(loggerName)
.
Каков наилучший образец для использования здесь? Будет ли правильный подход состоять в создании экземпляра singleton в каждой сборке? Меня беспокоит то, что нам все равно нужно передать имя регистратора в каждую точку входа для dll, что кажется излишним. Чтобы избежать перехода в имя регистратора, я мог бы предположить, что он всегда равен System.Reflection.Assembly.GetCallingAssembly().GetName().Name
.
Если это слишком сложно для log4net, существуют ли другие более простые решения, такие как блок регистрации предприятия?
Или наилучшим решением является подход с аспектным программированием (AOP)?
Ссылка на анти-шаблонный подход для синглтона здесь.
Ответы
Ответ 1
Почти год спустя, но я думал, что буду участвовать в любом случае!
Основываясь на вашем комментарии к сообщению Carl, я думаю, что, возможно, вы неправильно поняли, как работает log4net. Да, имя журнала определяет идентификатор журнала. Да, у регистратора может быть много приложений. НО, многие регистраторы также могут писать в SAME appender. Таким образом, вы можете настроить регистраторы "A" , "B" и "C" для всего журнала в файл "X". Вы можете получить регистраторы следующим образом:
ILog logger_a = LogManager.GetLogger("A");
ILog logger_b = LogManager.GetLogger("B");
ILog logger_c = LogManager.GetLogger("C");
Теперь, если вы зарегистрируетесь с любым из этих регистраторов, они все могут перейти в одно и то же место (файл "X" ), если вы настроили их таким образом.
Преимущество НЕ использовать одно и то же имя регистратора во всем приложении - это то, что вы можете контролировать уровень ведения журнала в разных местах приложения через файл конфигурации. Итак, если код, использующий регистраторы "A" и "B" , работает нормально, но код, использующий регистратор "C", имеет проблему, вы можете отключить "A" и "B" и включить "C" полностью. Таким образом, у вас меньше информации, необходимой для поиска, чтобы найти вашу проблему.
Большинство людей (или, по крайней мере, большинство примеров log4net) фактически создают экземпляр статического регистратора для CLASS, названный для этого класса (я не помню точный синтаксис, но легко найти примеры). Это дает вам очень высокий уровень детализации для управления журналом.
В вашем файле app.config вы можете управлять всеми регистраторами на одном уровне, настраивая один журнал, называемый "*", или вы можете настроить определенные регистраторы (используя полное имя), или вы даже можете настроить часть полное имя. Например, вы могли бы легко сделать все классы в пространстве имен ABC log на уровне "info", все классы в пространстве имен DEF регистрировались на уровне "ошибка", а все классы в пространстве имен GHI вообще не регистрировались. И все эти регистраторы могут регистрироваться в одном месте (например, файл X).
Возможно, было слишком поздно, чтобы помочь, но, возможно, не...
Ответ 2
Сначала вы должны создать класс-оболочку (чтобы отделить приложение от поставщика регистрации).
Этот класс-оболочка может принимать идентификатор журнала. Если вы используете контейнер IoC, вы можете просто ввести имя регистратора или существующий предварительно сконфигурированный экземпляр.
Если вы используете Unity (другие контейнеры похожи), вы можете сделать что-то вроде
// During application initialization
IUnityContainer myContainer = new UnityContainer();
LoggingService concreteLoggingService = new LoggingService( "logID" );
myContainer.RegisterInstance<ILoggingService>( concreteLoggingService );
// This would be injected, so you wouldn't see this, but it here for consistency
ILoggingService loggingService = myContainer.Resolve<ILoggingService>();
loggingService.LogMessage( "message" );
Теперь это предполагает, что у вас есть контейнер IoC. Вы также можете создать локатор службы:
// During application initialization
ServiceLocator.Register<ILoggingService>( new LoggingService( "logID" ) );
// Retrieved as needed
ILoggingService loggingServce = LoggingServiceLocator.Locate<ILoggingService>();
loggingService.LogMessage( "message" );
Во втором случае вам нужно написать весь сантехнический код. С контейнером IoC вы получаете это из коробки.
Ответ 3
Я думаю, вы могли бы иметь имя logger в своем app.config.
Могу ли я спросить, почему loggerName должно быть одинаковым для всего приложения?
Ответ 4
Мы следовали за подходом к использованию log4net, подобным этому.
Мы используем log4net как в основных сборках приложений, так и в библиотеке классов. Мы написали вокруг него класс-оболочку, так что все журналирование появляется с одинаковой конфигурацией везде, где мы называем это, а также чтобы убедиться, что он один. Этот класс-оболочка вызывается везде в нашем приложении.
В результате библиотеки классов и основное приложение все выходят в тот же файл журнала с той же конфигурацией, что и мы хотели. Это то, чего вы пытались достичь?
Ответ 5
Как реализовать собственный TraceListener, чтобы вы могли просто использовать Trace.Write во всем приложении?
Ответ 6
Я никогда не видел другого, значимого шаблона использования, чем это для log4net:
В дополнение к любому классу, который нуждается в регистрации, выполните:
private static ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
В слоях хоста AssemblyInfo.cs выполните:
[assembly: log4net.Config.XmlConfigurator]
В старте хоста либо выполняйте программную настройку добавлений и т.д., либо используйте обычную конфигурацию app.config.
Конец истории. Нет оберток. Нет вывода из вышесказанного.
Каждый и любой другой шаблон использования, с которым я столкнулся, состоит в том, чтобы обходить не совсем понимающие приставки log4net, включая некоторые/все ответы здесь.