Usando Microsoft.Extensions.Logging no EF Core

Microsoft.Extensions.Logging é um mecanismo de registro em log extensível com provedores de plug-in para muitos sistemas de registro em log comuns. Plug-ins fornecidos pela Microsoft (por exemplo, Microsoft.Extensions.Logging.Console) e plug-ins de terceiros (por exemplo, Serilog.Extensions.Logging) estão disponíveis como pacotes NuGet.

O Entity Framework Core (EF Core) integra-se totalmente ao Microsoft.Extensions.Logging. No entanto, considere o uso de log simples para uma maneira mais simples de registrar em log, especialmente para aplicativos que não usam injeção de dependência.

Aplicativos do ASP.NET Core

Microsoft.Extensions.Logging é usado por padrão em aplicativos ASP.NET Core. Chamar AddDbContext ou AddDbContextPool faz com que o EF Core use automaticamente a configuração de log configurada por meio do mecanismo de ASP.NET regular.

Outros tipos de aplicação

Outros tipos de aplicativo podem usar o GenericHost para obter os mesmos padrões de injeção de dependência usados no ASP.NET Core. AddDbContext ou AddDbContextPool podem ser usados como em aplicativos ASP.NET Core.

Microsoft.Extensions.Logging também pode ser usado para aplicativos que não usam injeção de dependência, embora log simples possa ser mais fácil de configurar.

Microsoft.Extensions.Logging requer a criação de um LoggerFactory. Essa fábrica deve ser armazenada como uma instância estática/global em algum lugar e usada sempre que um DbContext for criado. Por exemplo, é comum armazenar a fábrica do registrador como uma propriedade estática no DbContext.

public static readonly ILoggerFactory MyLoggerFactory
    = LoggerFactory.Create(builder => { builder.AddConsole(); });

Essa instância singleton/global deve ser registrada no EF Core no DbContextOptionsBuilder. Por exemplo:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseLoggerFactory(MyLoggerFactory)
        .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFLogging;Trusted_Connection=True;ConnectRetryCount=0");

Obtendo mensagens detalhadas

Dica

OnConfiguring ainda é chamado quando AddDbContext é usado ou uma instância DbContextOptions é passada para o construtor DbContext. Isso o torna o local ideal para aplicar a configuração de contexto, independentemente de como o DbContext é construído.

Dados Confidenciais

Por padrão, o EF Core não incluirá os valores de nenhum dado em mensagens de exceção. Isso ocorre porque esses dados podem ser confidenciais e podem ser revelados no uso de produção se uma exceção não for tratada.

No entanto, conhecer valores de dados, especialmente para chaves, pode ser muito útil ao depurar. Isso pode ser habilitado no EF Core chamando EnableSensitiveDataLogging(). Por exemplo:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.EnableSensitiveDataLogging();

Exceções de consulta detalhadas

Por motivos de desempenho, o EF Core não encapsula cada chamada para ler um valor do provedor de banco de dados em um bloco try-catch. No entanto, isso às vezes resulta em exceções difíceis de diagnosticar, especialmente quando o banco de dados retorna um NULL quando não permitido pelo modelo.

Ativar EnableDetailedErrors fará com que o EF introduza esses blocos try-catch e, assim, forneça erros mais detalhados. Por exemplo:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.EnableDetailedErrors();

Configuração para mensagens específicas

A API do EF Core ConfigureWarnings permite que os aplicativos alterem o que acontece quando um evento específico é encontrado. Isso pode ser usado para:

  • Alterar o nível de log no qual o evento é registrado
  • Ignorar o registro do evento completamente
  • Lançar uma exceção quando o evento ocorrer

Alterando o nível de log de um evento

Às vezes, pode ser útil alterar o nível de log predefinido de um evento. Por exemplo, isso pode ser usado para promover dois eventos adicionais de LogLevel.Debug a LogLevel.Information:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .ConfigureWarnings(
            b => b.Log(
                (RelationalEventId.ConnectionOpened, LogLevel.Information),
                (RelationalEventId.ConnectionClosed, LogLevel.Information)));

Suprimir o registro em log de um evento

De maneira semelhante, um evento individual pode ser suprimido do registro em log. Isso é particularmente útil para ignorar um aviso que foi revisado e compreendido. Por exemplo:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .ConfigureWarnings(b => b.Ignore(CoreEventId.DetachedLazyLoadingWarning));

Lançar para um evento

Finalmente, o EF Core pode ser configurado para ser lançado para um determinado evento. Isso é particularmente útil para transformar um aviso em um erro. (Na verdade, esse era o propósito original do método ConfigureWarnings, por isso o nome.) Por exemplo:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .ConfigureWarnings(b => b.Throw(RelationalEventId.QueryPossibleUnintendedUseOfEqualsWarning));

Filtragem e outras configurações

Consulte Efetuando login no .NET para obter orientação sobre filtragem de log e outras configurações.

Os eventos de log do EF Core são definidos em um dos:

  • CoreEventId para eventos comuns a todos os provedores de banco de dados EF Core
  • RelationalEventId para eventos comuns a todos os provedores de banco de dados relacional
  • Uma classe semelhante para eventos específicos do provedor de banco de dados atual. Por exemplo, SqlServerEventId para o provedor do SQL Server.

Essas definições contêm as IDs de evento, o nível de log e a categoria de cada evento, conforme usado por Microsoft.Extensions.Logging.