Как стать автором
Обновить

Логирование всех запросов к Базе данных в Asp.Net Boilerplate 4.3 .Net Core 2.1

Время на прочтение4 мин
Количество просмотров5.3K
Часто в проекте возникает непонятная ошибка для которой необходимо максимальное логирование всех запросов к Базе данных. Статья поможет тем, кто пишет (развертывает на сервере) один из своих первых проектов на Asp.Net Boilerplate.

Статья написана для новичков в технологии Asp.Net Boilerplate, у которых возникла любая странная ошибка, связанная с Базой данных. При использовании PostgreSQL это может быть, например, первый проект. Мотивацией к написанию статьи стало то, что решение данного вопроса не так-то просто найти в Интернете даже на английском, не говоря о том, что найденные решения не полностью отвечают на все вопросы по данной проблеме.

Версия продукта: Asp.Net Boilerplate 4.3, .NET Core 2.1

В случае выполнения данных шагов: В вашем основном лог-файле вы увидите залогированными абсолютно все запросы к Базе данных.

Шаг 1


Необходимо создать логгер. На платформе Boilerplate уже есть настроенный внутренний логгер. Это может быть Log4Net в стандартной комплектации. С ним не нужно производить никаких манипуляций. Вместо этого достаточно создать класс логгера, который зарегистрировать, как обработчик всех лог-сообщений от Базы данных.

Шаг 1.1


Проект *.EntityFrameworkCore. Здесь нам нужно создать 2 класса. С одной стороны логгер, который будет делать только одно — выводить в системный лог все сообщения от БД. Назовем его MyLogger. И провайдер этого логгера, который будет создавать MyLogger. Провайдер назовем MyLoggerProvider.

Создаем один файл со следующим кодом (один файл для упрощения, хотя, конечно, в каждом файле должно быть по одному классу):

public class MyLoggerProvider : ILoggerProvider
{
	private Castle.Core.Logging.ILogger _logger;

	public MyLoggerProvider(Castle.Core.Logging.ILogger logger)
	{
		_logger = logger;
	}

	public ILogger CreateLogger(string categoryName)
	{
		return new MyLogger(_logger);
	}

	public void Dispose()
	{

	}
}

public class MyLogger : ILogger
{
	private Castle.Core.Logging.ILogger _logger;

	public MyLogger(Castle.Core.Logging.ILogger logger)
	{
		_logger = logger;
	}

	public IDisposable BeginScope<TState>(TState state)
	{
		return null;
	}

	public bool IsEnabled(LogLevel logLevel)
	{
		return true;
	}

	public void Log<TState>(LogLevel logLevel, EventId eventId,
		TState state, Exception exception, Func<TState, Exception, string> formatter)
	{
		if (IsEnabled(logLevel))
		{
			var msg = formatter(state, exception);

			_logger.Info("DB-REQUEST: " + msg);
		}
	}
}

Если присмотреться, то видно, как в параметры MyLoggerProvider, а потом в MyLogger пробрасывается некоторый другой логгер. Получается уже третий! Суть в том, что именно этот третий это класс уровня инфраструктуры логирования, который должен быть получен из недр Boilerplate с помощью которого и будет осуществляться сохранение сообщений в журнале. См. далее.

Шаг 2


В рамках того же проекта *.EntityFrameworkCore идем в файл *DbContextConfigurer.cs и в обоих методах Configure() делаем следующие изменения:

2.1) Добавляем параметр loggerfactory типа LoggerFactory

2.2) В тело метода добавляем две строки:

builder.UseLoggerFactory(loggerFactory);
builder.EnableSensitiveDataLogging(true);

Смысл UseLoggerFactory — включить использование loggerFactory, которая передается в параметрах для логирования Базы данных. Очень важно помнить, что здесь мы включаем логирование Базы данных.

Смысл EnableSensitiveDataLogging — включить логирование не только запросов к БД, но в данных запросах еще и фиксировать все данные. Без данной настройки вы не сможете увидеть в запросах данные — они будут заменены на вопросительные знаки.

Шаг 3


В рамках того же проекта *.EntityFrameworkCore идем в файл *DbContextFactory.cs.

3.1) Добавляем новый метод:

private LoggerFactory GetDbLoggerFactory()
{
	return new LoggerFactory(new[] { new MyLoggerProvider(NullLogger.Instance) });
}

3.2) В методе CreateDbContext():
Т.к. мы ранее добавили в обе реализации Configure() новый параметр, то здесь должна выводиться ошибка. Настало время указать этот новый параметр — прописываем через запятую GetDbLoggerFactory(). Т.е. значение нового параметра loggerFactory должно возвращаться новым методом из п. 3.1.

Шаг 4


В рамках того же проекта *.EntityFrameworkCore идем в файл *EntityFrameworkModule.cs.

4.1) Добавляем новый метод:

private LoggerFactory GetDbLoggerFactory()
{
	return new LoggerFactory(new[] { new MyLoggerProvider(Logger) });
}

4.2) В методе PreInitialize():

Т.к. мы ранее добавили в обе реализации Configure() новый параметр, то здесь также должна выводиться ошибка. Указываем новый параметр аналогично п. 3.2 — прописываем через запятую GetDbLoggerFactory(). Т.е. значение нового параметра loggerFactory должно возвращаться новым методом из п. 4.1.

Результат


В основном лог файле (по умолчанию Logs.txt) вы увидите все запросы, предваряемые последовательностью символов «DB-REQUEST» (именно по ней и можно искать данные записи в журнале).

Общее понимание решения


Итак, теперь объясню, что мы сделали. Объяснение вынесено в конец статьи, т.к. часто читателям интересно начать уже делать что-то конкретное.

В классе *DbContextFactory, а также *EntityFrameworkModule мы создаем нашу LoggerFactory, в параметрах которой указываем созданный MyLoggerProvider. Но в качестве инфраструктурного класса, который будет непосредственно осуществлять логирование в первом случае (*DbContextFactory) мы передаем заглушку NullLogger.Instance, чтобы записей не было. Во втором случае (*EntityFrameworkModule) мы передаем логгер, который уже есть в Abp-модуле. Это поле Logger. Оно уже проинициализировано и с его помощью можно логировать. Соответственно, наш MyLogger сможет делать записи в файл Logs.txt с помощью данного класса.

Вся логика заключается в том, что данная фабрика loggerFactory устанавливается в качестве лог-фабрики для процессов работы с Базой данных. Как только нужен логгер — он создается фабрикой. И это наш MyLogger, который, в свою очередь, логирует все что приходит в Logs.txt (или в тот источник, в который настроен вывод ваших основных логов).

Как видите — не все так просто и уровни абстракций иногда вымораживают, особенно новичков! Задавайте ваши вопросы в комментариях.

Примечание:

— Решение создано для того чтобы включить логгер, понять в чем ошибка и выключить. Оно не рассчитано на долговременное использование.
Теги:
Хабы:
Всего голосов 11: ↑9 и ↓2+7
Комментарии0

Публикации