Каков наилучший способ использования одного и того же регистратора Log4net для множества сборок в решении? - PullRequest
15 голосов
/ 11 ноября 2009

У меня есть решение, состоящее из основного приложения winforms, с соответствующими внутренне написанными библиотеками библиотек классов, из которых я хочу войти. Это ведение журнала должно выполняться одним и тем же регистратором, независимо от того, вызывает ли это основной клиент UI или связанный DLL. Конечно, библиотеки DLL могут использоваться другими приложениями, которые имеют другие регистраторы в других решениях, но в этих обстоятельствах будет иметь другую конфигурацию log4net и, возможно, совсем другой набор приложений.

Один из подходов состоит в том, чтобы создать синглтон в основном приложении и вести из него журнал, однако, поскольку log4net является его собственным синглтоном, на него можно ссылаться, пока мы передаем одну и ту же строку (или тип) * 1003 будет входить в тот же пункт назначения (в моем случае я хочу использовать RollingFileAppender).

Это работает. Однако, учитывая, что DLL будет иметь несколько классов, это будет означать, что для каждого экземпляра класса или статического класса, из которого мы хотим вести журнал, потребуется i) аргумент, определяющий имя регистратора (для входа в тот же пункт назначения) и ii) на каждую точку входа нужно будет позвонить log4net.LogManager.GetLogger(loggerName).

Какую модель лучше использовать здесь? Правильный ли подход заключается в создании одиночного экземпляра в каждой сборке? Меня беспокоит то, что нам все равно нужно будет передать имя регистратора каждой точке входа для DLL, что выглядит как перебор. Чтобы не передавать имя регистратора, я могу предположить, что оно всегда равно System.Reflection.Assembly.GetCallingAssembly().GetName().Name.

Если это слишком сложно для log4net, есть ли другие более простые решения, такие как Enterprise Logging Block? Или лучшее решение - это аспектно-ориентированное программирование (АОП)?

Ссылка на анти-шаблонный подход для синглтона здесь .

Ответы [ 6 ]

19 голосов
/ 28 октября 2010

Почти год спустя, но я думал, что все равно внесу свой вклад!

Исходя из вашего комментария к сообщению Карла, я думаю, что, возможно, вы неправильно поняли, как работает log4net. Да, имя регистратора действительно идентифицирует регистратор. Да, у регистратора может быть много дополнений. НО, многие регистраторы также могут писать в тот же 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» и включить « С "весь путь вверх. Таким образом, у вас будет меньше информации, чтобы найти свою проблему.

Большинство людей (или, по крайней мере, большинство примеров log4net) фактически создают экземпляр статического регистратора для каждого КЛАССА, названного для этого класса (точный синтаксис я не помню, но примеры легко найти). Это дает вам очень высокий уровень детализации для управления вашим журналом.

В своем файле app.config вы можете управлять всеми регистраторами на одном уровне, настроив один регистратор с именем "*", или вы можете настроить определенные регистраторы (используя полное имя типа), или вы можете даже настроить часть полное имя типа. Например, вы могли бы очень легко сделать так, чтобы все классы в пространстве имен ABC регистрировались на уровне «info», все классы в пространстве имен DEF регистрировались на уровне «error», а все классы в пространстве имен GHI вообще не регистрировались. И все эти регистраторы могут регистрироваться в одном и том же месте назначения (например, в файле X).

Возможно, было слишком поздно, чтобы помочь, но, возможно, нет ...

3 голосов
/ 11 ноября 2009

Во-первых, вы должны создать класс-оболочку (чтобы отделить ваше приложение от провайдера журналов).

Этот класс-оболочка может принимать идентификатор регистратора. Если вы используете контейнер 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's 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 вы получаете это из коробки.

1 голос
/ 02 января 2013

Я никогда не видел другого, значимого шаблона использования, чем этот для log4net:

Вдобавок к любому классу, который требует регистрации, выполните:

private static ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

В слоях хоста AssemblyInfo.cs выполните:

[assembly: log4net.Config.XmlConfigurator]

При запуске хоста либо выполните программную настройку appenders и т. Д., Либо используйте обычную конфигурацию app.config.

Конец истории. Нет обертки. Нет выводов из вышеизложенного.

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

1 голос
/ 11 ноября 2009

Полагаю, у вас может быть loggerName в вашем app.config.

Могу ли я спросить, почему имя loggerName должно быть одинаковым для всего приложения?

0 голосов
/ 11 ноября 2009

Как насчет реализации собственного TraceListener , чтобы вы могли просто использовать Trace.Write в своем приложении?

0 голосов
/ 11 ноября 2009

Мы следовали подходу к использованию log4net, аналогичному этому.

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

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

...