¿Esto puede estar algo relacionado con Pass ILogger o ILoggerFactory a los constructores en AspNet Core? , sin embargo, se trata específicamente de Diseño de bibliotecas , no de cómo la aplicación real que usa esas bibliotecas implementa su registro.
Estoy escribiendo una biblioteca .net Standard 2.0 que se instalará a través de Nuget, y para permitir que las personas que usan esa biblioteca obtengan información de depuración, dependo de Microsoft.Extensions.Logging.Abstractions para permitir que se inyecte un registrador estandarizado.
Sin embargo, veo múltiples interfaces, y el código de muestra en la web a veces usa ILoggerFactory
y crea un registrador en el ctor de la clase. También hay lo ILoggerProvider
que parece una versión de solo lectura de Factory, pero las implementaciones pueden o no implementar ambas interfaces, por lo que tendría que elegir. (Factory parece más común que Provider).
Algunos códigos que he visto usan la ILogger
interfaz no genérica e incluso pueden compartir una instancia del mismo registrador, y algunos toman un ILogger<T>
en su ctor y esperan que el contenedor DI admita tipos genéricos abiertos o registro explícito de todas y cada una de las ILogger<T>
variaciones de mi biblioteca usos.
En este momento, creo que ILogger<T>
es el enfoque correcto, y tal vez un ctor que no toma ese argumento y simplemente pasa un Null Logger en su lugar. De esa forma, si no se necesita registro, no se utiliza ninguno. Sin embargo, algunos contenedores DI recogen el ctor más grande y, por lo tanto, fallarían de todos modos.
Tengo curiosidad por saber qué se supone que debo hacer aquí para crear la menor cantidad de dolor de cabeza para los usuarios, y al mismo tiempo permitir el soporte de registro adecuado si lo desea.
Esos son todos válidos excepto
ILoggerProvider
.ILogger
yILogger<T>
son lo que se supone que debes usar para iniciar sesión. Para obtener unILogger
, usa unILoggerFactory
.ILogger<T>
es un atajo para obtener un registrador para una categoría en particular (atajo para el tipo como la categoría).Cuando usa
ILogger
para realizar el registro, cada registradoILoggerProvider
tiene la oportunidad de manejar ese mensaje de registro. Realmente no es válido para consumir código para llamarILoggerProvider
directamente al.fuente
ILoggerFactory
sería excelente como una manera fácil de conectar DI para los consumidores con solo tener 1 dependencia ( "Solo dame una fábrica y crearé mis propios registradores" ), pero evitaría el uso de un registrador existente ( a menos que el consumidor utilice algún envoltorio). Tomar unILogger
, genérico o no, le permite al consumidor darme un registrador que prepararon especialmente, pero hace que la configuración de DI sea potencialmente mucho más compleja (a menos que se use un contenedor DI que admita Open Generics). ¿Eso suena correcto? En ese caso, creo que iré con la fábrica.ILogger<T>
, tomaré unILogger<MyClass>
o incluso solo en suILogger
lugar; de esa manera, el usuario puede conectarlo con un solo registro y sin requerir genéricos abiertos en su contenedor DI. Se inclina por lo no genéricoILogger
, pero experimentará mucho durante el fin de semana.El
ILogger<T>
fue el real que está hecho para DI. El ILogger vino para ayudar a implementar el patrón de fábrica mucho más fácilmente, en lugar de que usted escriba por su cuenta toda la lógica DI y Factory, esa fue una de las decisiones más inteligentes en el núcleo de asp.net.Puede elegir entre:
ILogger<T>
si necesita usar patrones de fábrica y DI en su código o podría usarILogger
, para implementar un registro simple sin necesidad de DI.dado eso, The
ILoggerProvider
es solo un puente para manejar cada uno de los mensajes del registro registrado. No es necesario usarlo, ya que no afecta nada que deba intervenir en el código, escucha el ILoggerProvider registrado y maneja los mensajes. Eso es todo.fuente
this ILogger
.Siguiendo la pregunta, creo que
ILogger<T>
es la opción correcta, considerando las desventajas de otras opciones:ILoggerFactory
fuerza a su usuario a ceder el control de la fábrica de registradores global mutable a su biblioteca de clases. Además, al aceptarILoggerFactory
su clase, ahora puede escribir en el registro con cualquier nombre de categoría arbitrario con elCreateLogger
método. Si bienILoggerFactory
generalmente está disponible como singleton en el contenedor DI, yo, como usuario, dudaría de por qué cualquier biblioteca necesitaría usarlo.ILoggerProvider.CreateLogger
parece, no está diseñado para inyectarse. Se utilizaILoggerFactory.AddProvider
para que la fábrica pueda crear agregadosILogger
que escriban en variosILogger
creados a partir de cada proveedor registrado. Esto queda claro cuando inspecciona la implementación deLoggerFactory.CreateLogger
ILogger
también parece el camino a seguir, pero es imposible con .NET Core DI. En realidad, esto suena como la razón por la que necesitaban proporcionarILogger<T>
en primer lugar.Entonces, después de todo, no tenemos mejor opción que
ILogger<T>
si tuviéramos que elegir entre esas clases.Otro enfoque sería inyectar algo más que no sea genérico
ILogger
, que en este caso debería ser no genérico. La idea es que al envolverlo con su propia clase, tome el control total de cómo el usuario podría configurarlo.fuente
El enfoque predeterminado está destinado a ser
ILogger<T>
. Esto significa que en el registro, los registros de la clase específica serán claramente visibles porque incluirán el nombre completo de la clase como contexto. Por ejemplo, si el nombre completo de su clase esMyLibrary.MyClass
, lo obtendrá en las entradas de registro creadas por esta clase. Por ejemplo:Debe usar el
ILoggerFactory
si desea especificar su propio contexto. Por ejemplo, que todos los registros de su biblioteca tienen el mismo contexto de registro en lugar de todas las clases. Por ejemplo:Y luego el registro se verá así:
Si hace eso en todas las clases, el contexto será solo MyLibrary para todas las clases. Me imagino que querría hacer eso para una biblioteca si no desea exponer la estructura de clases interna en los registros.
Respecto a la tala opcional. Creo que siempre debe requerir ILogger o ILoggerFactory en el constructor y dejar que el consumidor de la biblioteca lo desactive o proporcione un Logger que no haga nada en la inyección de dependencia si no quiere el registro. Es muy fácil desactivar el registro para un contexto específico en la configuración. Por ejemplo:
fuente
Para el diseño de bibliotecas, un buen enfoque sería:
1. No obligue a los consumidores a inyectar logger en sus clases. Simplemente cree otro ctor pasando NullLoggerFactory.
2. Limite el número de categorías que utiliza cuando crea registradores para permitir que los consumidores configuren el filtrado de registros fácilmente.
this._loggerFactory.CreateLogger(Consts.CategoryName)
fuente