Isso pode estar relacionado a Pass ILogger ou ILoggerFactory para construtores no AspNet Core? , entretanto, trata-se especificamente do Design da Biblioteca , não de como o aplicativo real que usa essas bibliotecas implementa seu registro.
Estou escrevendo uma biblioteca .net Standard 2.0 que será instalada via Nuget e para permitir que as pessoas que usam essa biblioteca obtenham algumas informações de depuração, estou dependendo do Microsoft.Extensions.Logging.Abstractions para permitir que um Logger padronizado seja injetado.
No entanto, estou vendo várias interfaces e o código de amostra na web às vezes usa ILoggerFactory
e cria um logger no ctor da classe. Há também o ILoggerProvider
que parece uma versão somente leitura do Factory, mas as implementações podem ou não implementar ambas as interfaces, então eu teria que escolher. (Factory parece mais comum que Provider).
Alguns códigos que eu vi usam a ILogger
interface não genérica e podem até compartilhar uma instância do mesmo registrador, e alguns pegam um ILogger<T>
em seu ctor e esperam que o contêiner de DI suporte tipos genéricos abertos ou registro explícito de cada ILogger<T>
variação minha biblioteca usa.
No momento, eu realmente acho que ILogger<T>
é a abordagem certa, e talvez um ctor que não aceita esse argumento e apenas passa um Logger Nulo. Dessa forma, se nenhum registro for necessário, nenhum será usado. No entanto, alguns contêineres de DI escolhem o maior ctor e, portanto, falhariam de qualquer maneira.
Estou curioso para saber o que devo fazer aqui para criar o mínimo de dor de cabeça para os usuários e, ao mesmo tempo, permitir o suporte de registro adequado, se desejado.
Todos esses são válidos, exceto para
ILoggerProvider
.ILogger
eILogger<T>
são o que você deve usar para registrar. Para obter umILogger
, você usa umILoggerFactory
.ILogger<T>
é um atalho para obter um logger para uma categoria específica (atalho para o tipo como a categoria).Quando você usa o
ILogger
para fazer o log, cada registradoILoggerProvider
tem a chance de lidar com essa mensagem de log. Não é realmente válido para consumir código chamarILoggerProvider
diretamente para o .fonte
ILoggerFactory
seria uma ótima maneira de conectar o DI para consumidores por ter apenas 1 dependência ( "Apenas me dê uma fábrica e eu criarei meus próprios loggers" ), mas evitaria o uso de um logger existente ( a menos que o consumidor use algum invólucro). Usar umILogger
- genérico ou não - permite que o consumidor me dê um registrador que ele preparou especialmente, mas torna a configuração de DI potencialmente muito mais complexa (a menos que um contêiner de DI que suporte Open Generics seja usado). Isso soa correto? Nesse caso, acho que vou com a fábrica.ILogger<T>
, vou pegar umILogger<MyClass>
ou mesmo apenas emILogger
vez disso - dessa forma, o usuário pode conectá-lo com apenas um único registro, e sem exigir genéricos abertos em seu contêiner DI. Inclinando-se para o não genéricoILogger
, mas experimentará muito no fim de semana.O
ILogger<T>
foi o real que é feito para o DI. O ILogger veio para ajudar a implementar o padrão de fábrica com muito mais facilidade, em vez de você escrever por conta própria toda a DI e lógica de fábrica, que foi uma das decisões mais inteligentes no núcleo do asp.net.Você pode escolher entre:
ILogger<T>
se você precisa usar padrões de fábrica e DI em seu código ou pode usar oILogger
, para implementar o registro simples sem necessidade de DI.visto que, o The
ILoggerProvider
é apenas uma ponte para lidar com cada uma das mensagens do log registrado. Não há necessidade de utilizá-lo, pois não tem efeito em nada que você deva intervir no código, ele escuta o ILoggerProvider registrado e trata as mensagens. É sobre isso.fonte
this ILogger
.Atendo-me à pergunta, acredito que
ILogger<T>
seja a opção certa, considerando o lado negativo de outras opções:ILoggerFactory
força seu usuário a ceder o controle da fábrica mutável do logger global para sua biblioteca de classes. Além disso, ao aceitarILoggerFactory
sua classe, agora você pode escrever no log com qualquer nome de categoria arbitrário comCreateLogger
método. EmboraILoggerFactory
geralmente esteja disponível como um singleton no contêiner de DI, eu, como usuário, duvido do motivo de qualquer biblioteca precisar usá-lo.ILoggerProvider.CreateLogger
pareça, não se destina a injeção. É usadoILoggerFactory.AddProvider
para que a fábrica possa criar agregadosILogger
que gravam em váriosILogger
criados a partir de cada provedor registrado. Isso fica claro quando você inspeciona a implementação deLoggerFactory.CreateLogger
ILogger
também parece o caminho a seguir, mas é impossível com o .NET Core DI. Na verdade, esse parece ser o motivo pelo qual eles precisaram fornecerILogger<T>
em primeiro lugar.Afinal, não temos escolha melhor do
ILogger<T>
que escolher entre essas classes.Outra abordagem seria injetar algo mais que envolvesse o não genérico
ILogger
, que neste caso deveria ser um não genérico. A ideia é que, ao envolvê-lo com sua própria classe, você assume o controle total de como o usuário pode configurá-lo.fonte
A abordagem padrão deve ser
ILogger<T>
. Isso significa que no log os logs da classe específica estarão claramente visíveis porque incluirão o nome completo da classe como contexto. Por exemplo, se o nome completo da sua classe for,MyLibrary.MyClass
você obterá isso nas entradas de registro criadas por esta classe. Por exemplo:Você deve usar o
ILoggerFactory
se quiser especificar seu próprio contexto. Por exemplo, todos os logs de sua biblioteca têm o mesmo contexto de log em vez de todas as classes. Por exemplo:E então o log ficará assim:
Se você fizer isso em todas as classes, o contexto será apenas MyLibrary para todas as classes. Imagino que você gostaria de fazer isso para uma biblioteca se não quiser expor a estrutura de classe interna nos logs.
Quanto ao registro opcional. Acho que você deve sempre exigir o ILogger ou ILoggerFactory no construtor e deixar para o consumidor da biblioteca desligá-lo ou fornecer um Logger que não faz nada na injeção de dependência se não quiser fazer o log. É muito fácil desligar o registro para um contexto específico na configuração. Por exemplo:
fonte
Para um projeto de biblioteca, uma boa abordagem seria:
1. Não force os consumidores a injetar logger em suas classes. Simplesmente crie outro ctor passando NullLoggerFactory.
2. Limite o número de categorias que você usa ao criar registradores para permitir que os consumidores configurem a filtragem de registros facilmente.
this._loggerFactory.CreateLogger(Consts.CategoryName)
fonte