Quero usar um nlogger em meu aplicativo, talvez no futuro precise mudar o sistema de registro. Então, eu quero usar uma fachada de registro.
Você conhece alguma recomendação para os exemplos existentes de como escrevê-los? Ou apenas me dê um link para algumas das melhores práticas nesta área.
Respostas:
Eu costumava usar fachadas de registro, como Common.Logging (até mesmo para ocultar minha própria biblioteca CuttingEdge.Logging ), mas hoje em dia eu uso o padrão de injeção de dependência e isso me permite ocultar registradores atrás de minha própria abstração (simples) que adere a ambos Dependency Princípio de Inversão e o Princípio de Segregação de Interface(ISP) porque tem um membro e porque a interface é definida pela minha aplicação; não é uma biblioteca externa. Minimizar o conhecimento que as partes centrais de seu aplicativo têm sobre a existência de bibliotecas externas, melhor; mesmo se você não tiver a intenção de substituir sua biblioteca de registro. A forte dependência da biblioteca externa torna mais difícil testar seu código e complica seu aplicativo com uma API que nunca foi projetada especificamente para seu aplicativo.
É assim que a abstração costuma se parecer em meus aplicativos:
Opcionalmente, essa abstração pode ser estendida com alguns métodos de extensão simples (permitindo que a interface permaneça estreita e continue aderindo ao ISP). Isso torna o código para os consumidores desta interface muito mais simples:
Uma vez que a interface contém apenas um único método, você pode facilmente criar uma
ILogger
implementação que faz proxy para log4net , Serilog , Microsoft.Extensions.Logging , NLog ou qualquer outra biblioteca de registro e configurar seu contêiner de DI para injetá-lo em classes que têm umILogger
em seus construtor.Observe que ter métodos de extensão estáticos no topo de uma interface com um único método é bastante diferente de ter uma interface com muitos membros. Os métodos de extensão são apenas métodos auxiliares que criam uma
LogEntry
mensagem e a passam pelo único método naILogger
interface. Os métodos de extensão tornam-se parte do código do consumidor; não faz parte da abstração. Isso não só permite que os métodos de extensão evoluam sem a necessidade de alterar a abstração, os métodos de extensão e oLogEntry
construtores são sempre executados quando a abstração do registrador é usada, mesmo quando esse registrador é fragmentado / simulado. Isso dá mais certeza sobre a exatidão das chamadas para o logger durante a execução em um conjunto de testes. A interface de um membro torna o teste muito mais fácil também; Ter uma abstração com muitos membros torna difícil criar implementações (como mocks, adaptadores e decoradores).Quando você faz isso, dificilmente há necessidade de alguma abstração estática que as fachadas de registro (ou qualquer outra biblioteca) podem oferecer.
fonte
Usei o pequeno interface wrapper + adaptador de https://github.com/uhaciogullari/NLog.Interface, que também está disponível via NuGet :
fonte
A partir de agora, a melhor aposta é usar o pacote Microsoft.Extensions.Logging ( como apontado por Julian ). A maior parte da estrutura de registro pode ser usada com isso.
Definir sua própria interface, conforme explicado na resposta de Steven, é adequado para casos simples, mas deixa escapar algumas coisas que considero importantes:
IsEnabled(LogLevel)
você pode desejar, por motivos de desempenho, mais uma vezVocê provavelmente pode implementar tudo isso em sua própria abstração, mas nesse ponto você estará reinventando a roda.
fonte
Geralmente eu prefiro criar uma interface como
e no tempo de execução injeto uma classe concreta que é implementada a partir dessa interface.
fonte
LogWarning
eLogCritical
métodos e todos os seus sobrecargas. Ao fazer isso, você violará o Princípio de Segregação de Interface . Prefira definir aILogger
interface com um únicoLog
método.LogEntry
e, portanto, uma dependência deLoggingEventType
. AILogger
implementação deve lidar com issoLoggingEventTypes
, provavelmentecase/switch
, que é um cheiro de código . Por que esconder aLoggingEventTypes
dependência? A implementação deve lidar com os níveis de registro de qualquer maneira , portanto, seria melhor explicitar sobre o que uma implementação deve fazer, em vez de ocultá-la atrás de um único método com um argumento geral.ICommand
que tem umHandle
que leva umobject
. As implementações devem sercase/switch
sobre os tipos possíveis para cumprir o contrato da interface. Isso não é o ideal. Não tem uma abstração que esconde uma dependência que deve ser tratada de qualquer maneira. Em vez disso, tenha uma interface que declara claramente o que é esperado: "Espero que todos os loggers lidem com avisos, erros, fatais, etc". Isso é preferível a "Espero que todos os registradores lidem com mensagens que incluem avisos, erros, fatais, etc."LoggingEventType
devem ser chamadosLoggingEventLevel
porque os tipos são classes e devem ser codificados como tal em OOP. Para mim, não há diferença entre não usar um método de interface e não usar oenum
valor correspondente . Em vez dissoErrorLoggger : ILogger
, use ,InformationLogger : ILogger
onde cada logger define seu próprio nível. Em seguida, o DI precisa injetar os loggers necessários, provavelmente por meio de uma chave (enum), mas essa chave não faz mais parte da interface. (Você agora está SÓLIDO).Uma ótima solução para este problema surgiu na forma do projeto LibLog .
LibLog é uma abstração de registro com suporte embutido para os principais registradores, incluindo Serilog, NLog, Log4net e Enterprise logger. Ele é instalado por meio do gerenciador de pacotes NuGet em uma biblioteca de destino como um arquivo de origem (.cs) em vez de uma referência .dll. Essa abordagem permite que a abstração de registro seja incluída sem forçar a biblioteca a assumir uma dependência externa. Ele também permite que um autor de biblioteca inclua o log sem forçar o aplicativo de consumo a fornecer explicitamente um logger para a biblioteca. O LibLog usa reflexão para descobrir qual registrador de concreto está em uso e conectar-se a ele sem qualquer código de fiação explícito no (s) projeto (s) da biblioteca.
Portanto, o LibLog é uma ótima solução para registro em projetos de biblioteca. Basta fazer referência e configurar um logger concreto (Serilog for the win) em seu aplicativo ou serviço principal e adicionar LibLog às suas bibliotecas!
fonte
Em vez de escrever sua própria fachada, você pode usar Castle Logging Services ou Simple Logging Façade .
Ambos incluem adaptadores para NLog e Log4net.
fonte
Desde 2015, você também pode usar o registro do .NET Core se estiver criando aplicativos do .NET Core.
O pacote para o NLog se conectar é:
fonte