Это может быть несколько связано с передачей ILogger или ILoggerFactory конструкторам в AspNet Core? Однако речь идет именно о дизайне библиотеки , а не о том, как реальное приложение, использующее эти библиотеки, реализует ведение журнала.
Я пишу библиотеку .net Standard 2.0, которая будет установлена через Nuget, и чтобы люди, использующие эту библиотеку, могли получать некоторую отладочную информацию, я полагаюсь на Microsoft.Extensions.Logging.Abstractions, чтобы разрешить внедрение стандартизированного регистратора.
Однако я вижу несколько интерфейсов, а пример кода в Интернете иногда использует ILoggerFactory
и создает регистратор в ctor класса. Также есть ILoggerProvider
версия Factory, доступная только для чтения, но реализации могут реализовывать или не реализовывать оба интерфейса, поэтому мне пришлось бы выбирать. (Factory кажется более распространенным, чем Provider).
Некоторый код, который я видел, использует неуниверсальный ILogger
интерфейс и может даже совместно использовать один экземпляр одного и того же регистратора, а некоторые берут ILogger<T>
в своем ctor и ожидают, что контейнер DI будет поддерживать открытые общие типы или явную регистрацию каждого ILogger<T>
варианта моей библиотеки использует.
Прямо сейчас я думаю, что ILogger<T>
это правильный подход, и, возможно, оператор, который не принимает этот аргумент и вместо этого просто передает Null Logger. Таким образом, если журналирование не требуется, оно не используется. Однако некоторые контейнеры DI выбирают самый большой ctor и, таким образом, все равно не работают.
Мне любопытно, что я должен делать здесь, чтобы создать наименьшую головную боль для пользователей, при этом обеспечивая при желании надлежащую поддержку ведения журнала.
Все они действительны, кроме
ILoggerProvider
.ILogger
иILogger<T>
это то, что вы должны использовать для ведения журнала. Чтобы получить файлILogger
, используйте расширениеILoggerFactory
.ILogger<T>
- это ярлык для получения регистратора для определенной категории (ярлык для типа как категории).Когда вы используете
ILogger
для ведения журнала, каждый зарегистрированныйILoggerProvider
получает возможность обработать это сообщение журнала. На самом деле недопустимо для использования кодаILoggerProvider
напрямую вызывать .источник
ILoggerFactory
было бы отличным простым способом подключить DI для потребителей, имея только одну зависимость ( «Просто дайте мне Factory, и я создам свои собственные регистраторы» ), но предотвратит использование существующего регистратора ( если потребитель не использует какую-то оболочку). ВзятиеILogger
- общего или нет - позволяет потребителю предоставить мне специально подготовленный регистратор, но делает настройку DI потенциально намного более сложной (если не используется контейнер DI, поддерживающий Open Generics). Это звучит правильно? В таком случае, думаю, я пойду с завода.ILogger<T>
, я возьмуILogger<MyClass>
или даже простоILogger
вместо этого - таким образом, пользователь может подключить его с помощью только одной регистрации и без необходимости открытия дженериков в своем контейнере DI. Склоняюсь к не-универсальномуILogger
, но много экспериментирую в выходные.Это
ILogger<T>
был тот самый, который сделан для DI. ILogger появился для того, чтобы упростить реализацию фабричного паттерна, вместо того, чтобы вы писали самостоятельно всю логику DI и Factory, что было одним из самых умных решений в ядре asp.net.Вы можете выбирать между:
ILogger<T>
если вам необходимо использовать в коде шаблоны factory и DI, или вы можете использоватьILogger
, для реализации простого ведения журнала без необходимости DI.учитывая это,
ILoggerProvider
это просто мост для обработки каждого зарегистрированного сообщения журнала. Нет необходимости использовать его, так как он не влияет на то, что вы должны вмешивать в код. Он прослушивает зарегистрированный ILoggerProvider и обрабатывает сообщения. Вот и все.источник
this ILogger
.Придерживаясь вопроса, я считаю,
ILogger<T>
что это правильный вариант, учитывая обратную сторону других вариантов:ILoggerFactory
заставляет вашего пользователя передать управление изменяемой фабрикой глобального регистратора вашей библиотеке классов. Более того, принявILoggerFactory
ваш класс, вы можете писать в журнал с любым произвольным именем категории с помощьюCreateLogger
метода. ХотяILoggerFactory
обычно он доступен как синглтон в контейнере DI, я, как пользователь, сомневаюсь, зачем какой-либо библиотеке его использовать.ILoggerProvider.CreateLogger
выглядит так, он не предназначен для инъекций. Он используется,ILoggerFactory.AddProvider
чтобы фабрика могла создавать агрегированные данные,ILogger
которые записываются в несколькоILogger
созданных от каждого зарегистрированного провайдера. Это становится ясно, когда вы проверяете реализациюLoggerFactory.CreateLogger
ILogger
тоже выглядит приемлемым, но с .NET Core DI это невозможно. Это действительно похоже на причину, по которой они должны были предоставитьILogger<T>
в первую очередь.В конце концов, у нас нет лучшего выбора, чем
ILogger<T>
если бы мы выбирали из этих классов.Другой подход заключался бы во внедрении чего-то еще, что обертывает неуниверсальный
ILogger
, который в данном случае не должен быть универсальным. Идея состоит в том, что, обернув его своим собственным классом, вы полностью контролируете, как пользователь может его настроить.источник
Подход по умолчанию должен быть
ILogger<T>
. Это означает, что в журнале будут четко видны журналы конкретного класса, поскольку они будут включать полное имя класса в качестве контекста. Например, если у вашего класса полное имя,MyLibrary.MyClass
вы получите его в записях журнала, созданных этим классом. Например:Вы должны использовать,
ILoggerFactory
если хотите указать свой собственный контекст. Например, все журналы из вашей библиотеки имеют одинаковый контекст журнала вместо каждого класса. Например:И тогда журнал будет выглядеть так:
Если вы сделаете это во всех классах, тогда контекстом будет просто MyLibrary для всех классов. Я полагаю, вы захотите сделать это для библиотеки, если вы не хотите раскрывать внутреннюю структуру классов в журналах.
По поводу необязательного ведения журнала. Я думаю, вам всегда следует требовать ILogger или ILoggerFactory в конструкторе и оставлять его потребителю библиотеки, чтобы отключить его или предоставить Logger, который ничего не делает при внедрении зависимостей, если они не хотят вести журнал. Очень легко отключить ведение журнала для определенного контекста в конфигурации. Например:
источник
Для дизайна библиотеки хорошим подходом будет:
1. Не заставляйте потребителей внедрять логгер в ваши классы. Просто создайте еще один ctor, передав NullLoggerFactory.
2. Ограничьте количество категорий, которые вы используете при создании регистраторов, чтобы потребители могли легко настраивать фильтрацию журналов.
this._loggerFactory.CreateLogger(Consts.CategoryName)
источник