Это интересный подход, однако, как представляется, он страдает от недостатка, заключающегося в том, что все вводимые логгеры (или один внедренный синглтон) будут одинаковым экземпляром (или будут иметь одинаковое имя, причем имя является имя класса NLogLoggingService. Это означает, что вы не можете очень легко контролировать степень детализации ведения журнала (т. е. включить ведение журнала на уровень «Информация» в одном классе и «Предупредить» в другом классе). Также, если вы решите использовать форматирование сайта вызова токены, в коде приложения вы всегда получите сайт вызова для вызова регистратора NLog, а не сайт вызова.
Вот сокращенная версия логгера, который был связан:
[Export(Services.Logging.LoggingService, typeof(ILoggingService))]
class NLogLoggingService : ILoggingService
{
Logger log; public NLogLoggingService()
{
log = LogManager.GetCurrentClassLogger();
}
public void Debug(object message)
{
log.Debug(message);
}
public void DebugWithFormat(string format, params object[] args)
{
if (args.Length == 0)
{
log.Debug(format);
}
else
{
Debug(string.Format(format, args));
}
}
public bool IsDebugEnabled
{
get
{
return log.IsDebugEnabled;
}
}
}
В конструкторе LogManager.GetCurrentClassLogger()
используется для получения регистратора NLog. GetCurrentClassLogger будет возвращать регистратор NLog, который «по имени» основан на «текущем» типе, который в данном случае является NLogLoggingService. Итак, чтобы настроить NLog в файле app.config, вы будете настраивать на основе того, что регистратор называется «SoapBox.Core.NLogLoggingService». Как правило, в коде, который использует NLog (или log4net) напрямую, каждый класс получает свой собственный логгер с уникальным именем, например:
namespace MyNamespace
{
public class MyClass1
{
private static readonly Logger logger LogManager.GetCurrentClassLogger();
public void DoSomeWork()
{
logger.Info("Logging from inside MyClass1.DoSomeWork");
}
}
public class MyClass2
{
private static readonly Logger logger LogManager.GetCurrentClassLogger();
public void DoSomeWork()
{
logger.Info("Logging from inside MyClass2.DoSomeWork");
}
}
}
Теперь ведение журнала для MyClass1 и MyClass2 контролируется индивидуально. Вы можете настроить разные уровни для каждого класса, отправить их разным целям или полностью отключить один или оба. В качестве альтернативы, из-за концепции иерархий логгеров как в log4net, так и в NLog, вы можете одновременно контролировать логирование в обоих классах, настроив «регистратор» для пространства имен (в данном случае MyNamespace) или любое пространство имен «предков». Если для полностью определенного имени типа не настроен регистратор, то структура ведения журналов, по сути, перемещается вверх по иерархии, рассматривая имя строки с разделителями-точками и удаляя последний фрагмент и проверяя, настроен ли этот регистратор. Таким образом, в этом случае мы запрашиваем средства ведения журнала для MyNamespace.MyClass1 и MyNamespace.MyClass2. Я мог бы настроить файл app.config, чтобы иметь журнал MyNamespace в «info» и записывать в целевой файл (appender в log4net-speak). Если бы я это сделал, то оба регистратора, которые я запрашивал через свои полные имена, унаследовали бы конфигурацию MyNamespace.
С предложенным способом внедрения NLog через MEF у вас будет только один экземпляр регистратора, поэтому вы не можете настроить каждый класс для ведения журнала по-разному. Кроме того, как я упоминал ранее, если вы решите регистрировать информацию сайта вызовов, вы всегда получите «SoapBox.Core.NLogLoggingService» для класса и «Debug» (или DebugWithFormat, или Info, или InfoWithFormat и т. Д.) Для метода.
Это, похоже, проблема с успешной инъекцией логгеров из log4net и NLog. Вы можете увидеть вопрос , который я задавал об этой самой проблеме пару месяцев назад.
В конечном итоге мне удалось выяснить, каким образом некоторые платформы внедрения зависимостей могут успешно внедрять log4net и NLog-логгеры, специфичные для создаваемого класса (т. Е. Если DI-инфраструктура создает экземпляр MyClass, который, в свою очередь, зависит от интерфейса ILogger, то MyClass получит регистратор, который по сути эквивалентен тому, что произошло бы, если бы MyClass запросил сам регистратор через API LogManager.GetCurrentClassLogger). Обычно «распознаватели» в структурах DI / IoC получают текущий контекст (содержащий, помимо прочего, тип создаваемого в данный момент объекта). Когда этот тип доступен, становится просто сделать так, чтобы специфичный для каркаса ведения журнала распознаватель получил этот тип и передал его в структуру ведения журнала, чтобы создать регистратор, подходящий для этого типа.
Чтобы максимально использовать возможности NLog (и log4net), вы действительно хотели бы сообщить MEF, что ваш класс зависит от "ILogger", но также и от того, что экземпляр "ILogger" вставляется в ваш класс должен зависеть от типа вашего класса.
Я не знаю, как легко будет добиться этого с помощью MEF.В качестве альтернативы, вы можете обернуть статический LogManager NLog в ILogManager и вставить его.Это будет отличаться от обычной парадигмы «впрыскивать ILogger».
Подводя итог: если вы впрыснете NLog через MEF таким образом, вы действительно сможете войти в систему с помощью NLog, но у вас будет только один по имени loggerSoapBox.Core.NLogLoggingService).Это означает, что вы не сможете управлять с какой-либо степенью детализации - ни для уровней / вкл / выкл, ни для вывода (NLog Target / log4net Appender)
У меня нет хорошего ответа на то, что делатьчто касается внедрения NLog через MEF и сохранения гранулярности / гибкости, которую дает вам «raw» NLog.
Я могу сказать, что мы решили использовать Common.Logging для .NET для абстрагированияструктура ведения журнала, но мы решили НЕ внедрять ведение журнала.Вместо этого мы будем использовать статический LogManager (как предусмотрено Common.Logging) для раздачи регистраторов.