Логгирование операций

Данное руководство устарело. Актуальное руководство: Руководство по Entity Framework Core 7

Последнее обновление: 17.11.2020

Для контроля операций, которые выполняет контекст данных, мы можем использовать логгирование. Entity Framework Core поддерживает логгирование, причем мы мжем воспользоваться как встроенными возможностями, так и создать и встроить свою инфраструктуру логгирования. Рассмотрим оба варианта и начнем со встроенных возможностей.

Метод LogTo

В EntityFramework Core 5.0 было существенно упрощено логгирование. В частности, был добавлен LogTo(), который позволяет логгировать информацию. Он применяется при конфигурации класса контекста данных.

Например, выведем всю информацию об операциях с базой данных на консоль. Допустим, у нас будут следующая модель:

public class User
{
	public int Id { get; set; }
	public string Name { get; set; }
	public int Age { get; set; }
}

И следующий класс контекста данных:

using Microsoft.EntityFrameworkCore;

namespace HelloApp
{
    public class ApplicationContext : DbContext
    {
        public DbSet<User> Users { get; set; }
        public ApplicationContext()
        {
            Database.EnsureDeleted();
            Database.EnsureCreated();
        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=helloappdb;Trusted_Connection=True;");
            optionsBuilder.LogTo(System.Console.WriteLine);
        }
    }
}

В методе OnConfiguring() у передаваемого в качестве параметра объекта DbContextOptionsBuilder вызывается метод LogTo(), в который передается делегат Action<string> - то есть некоторое действие, которое принимает один параметр типа string и и ничего не возвращает. Именно такое действие представляет традиционный метод Console.WriteLine(), который выводит строку на консоль. И поскольку класс Console расположен в пространстве имен System, то прописываем System.Console.WriteLine.

Для тестирования пусть у нас определена следующая программа:

using Microsoft.EntityFrameworkCore.Infrastructure;
using System;
using System.Linq;
using Microsoft.Extensions.Logging;

namespace HelloApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            using (ApplicationContext db = new ApplicationContext())
            {
                User user1 = new User { Name = "Tom", Age = 33 };
                User user2 = new User { Name = "Alice", Age = 26 };
                
                db.Users.Add(user1);
                db.Users.Add(user2);
                db.SaveChanges();

                var users = db.Users.ToList();
                Console.WriteLine("Данные после добавления:");
                foreach (User u in users)
                {
                    Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}");
                }
            }
            Console.Read();
        }
    }
}

И при запуске приложения на консоль будет выведена детальная информация по всем операциям:

Метод LogTo в Entity Framework Core 5.0

Подобным образом можно логгировать в другие места. Например, логгирование в окно отладки (что в программе производится с помощью метода Debug.WriteLine()):

optionsBuilder.LogTo(message => System.Diagnostics.Debug.WriteLine(message));
Метод LogTo и Debug.WriteLine в Entity Framework Core 5.0

Другим распространенным способом логгирования является вывод в файл:

using Microsoft.EntityFrameworkCore;
using System.IO;
using System.Threading.Tasks;

namespace HelloApp
{
    public class ApplicationContext : DbContext
    {
        private readonly StreamWriter logStream = new StreamWriter("mylog.txt", true);
        public DbSet<User> Users { get; set; }
        public ApplicationContext()
        {
            Database.EnsureDeleted();
            Database.EnsureCreated();
        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=helloappdb;Trusted_Connection=True;");
            optionsBuilder.LogTo(logStream.WriteLine);
        }
        public override void Dispose()
        {
            base.Dispose();
            logStream.Dispose();
        }

        public override async ValueTask DisposeAsync()
        {
            await base.DisposeAsync();
            await logStream.DisposeAsync();
        }
    }
}

Собственно для записи в файл используется объект класса StreamWriter из пространства имен System.IO. Его метод logStream.WriteLine, который пищет в файл строку, передается в метод LogTo(). Для закрытия и утилизации файлового потока StreamWriter в классе контекста переопределены методы Dispose/DisposeAsync, в которых вызывается метод Dispose/DisposeAsync объекта StreamWriter. В итоге при выполнении программы в папке приложения появится файл лога mylog.txt.

Настройка логгирования

Уровень логгирования

Метод LogTo() имеет ряд перегруженных версий, которые принимают разное количество параметров. Так, мы можем передать в LogTo уровень логгирования в виде одного из значений перечисления LogLevel:

  • Trace: используется для вывода наиболее детализированных сообщений. Подобные сообщения могут нести важную информацию о приложении и его строении, поэтому данный уровень лучше использовать при разработке, но никак не при публикации

  • Debug: для вывода информации, которая может быть полезной в процессе разработки и отладки приложения

  • Information: уровень сообщений, позволяющий просто отследить поток выполнения приложения

  • Warning: используется для вывода сообщений о неожиданных событиях, например, ошибках, которые не влияют не останавливают выполнение приложения, но в то же время должны быть иследованы

  • Error: для вывода информации об ошибках и исключениях, которые возникли при текущей операции и которые не могут быть обработаны

  • Critical: уровень критических ошибок, которые требуют немедленной реакции - ошибками операционной системы, потерей данных в бд, переполнение памяти диска и т.д.

  • None: вывод информации в лог не применяется

По умолчанию EntityFramework Core использует значение Debug, но можно указать какое-нибудь другое значение:

optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information);

Конкретизация сообщений

Каждое сообщение в логе ассоциировано с определенным идентификатором события. По сути идентификаторы представляют тип возникающих событий. Например, специфические для провайдера SQL Server сообщения описываются классом SqlServerEventId. Сообщения более общего характера, описывются классом CoreEventId, а сообщения, связанные с выполнением запросов, - класом RelationalEventId. Поскольку каждый класс идентификатора имеет довольно много полей, которые представляют опеделенное сообщение, я не буду подробно расписывать все эти поля. Посмотрим на простом примере, как мы можем конкретизировать сообщения - например, нам надо вывести только выполняемые команды SQL. В этом случае мы можем воспользоваться RelationalEventId и его переменной CommandExecuted, которая представляет окончание выполнения команды:

optionsBuilder.LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuted});
сообщения и события в логгировании в EntityFramework Core 5

Категории сообщений

Другим способом фильтрации сообщений представляет использование категорий, которые представлены классом DbLoggerCategory и который позволяет задать нужные категории логгирования:

  • Database.Command: категория для выполняемых команд, позволяет получить выполняемый код SQL

  • Database.Connection : категория для операций подключения к БД

  • Database.Transaction : категория для транзакций с бд

  • Migration: категория для миграций

  • Model: категория для действий, совершаемых при привязке модели

  • Query: категория для запросов за исключением тех, что генерируют исполняемый код SQL

  • Scaffolding: категория для действий, выполняемых в поцессе обратного инжиниринга (то есть когда по базе данных генерируются классы и класс контекста)

  • Update: категория для сообщений вызова DbContext.SaveChanges()

  • Infrastructure: категория для всех остальных сообщений

Например, выведем в лог информацию только об исполняемых командах:

optionsBuilder.LogTo(Console.WriteLine, new[] { DbLoggerCategory.Database.Command.Name });
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850