Logging all database queries in Asp.Net Boilerplate 4.3 .Net Core 2.1

Often in the project there is an incomprehensible error for which the maximum logging of all queries to the Database is necessary . The article will help those who write (deploy on the server) one of their first projects on the Asp.Net Boilerplate .

This article is written for those new to Asp.Net Boilerplate technology who have experienced any strange error related to the Database. When using PostgreSQL, this may be, for example, the first project. The motivation for writing the article was that the solution to this question is not so easy to find on the Internet, even in English, not to mention the fact that the solutions found do not fully answer all the questions on this problem.

Product Version: Asp.Net Boilerplate 4.3, .NET Core 2.1 If You Follow These

Steps: In your main log-file you will see all requests to the Database are logged in.

Step 1


You must create a logger. There is already a configured internal logger on the Boilerplate platform. It can be Log4Net as standard. There is no need to make any manipulations with him. Instead, it’s enough to create a logger class that you register as the processor of all log messages from the Database.

Step 1.1


Project * .EntityFrameworkCore. Here we need to create 2 classes. On the one hand, a logger that will do only one thing is to output all messages from the database to the system log. Let's call it MyLogger. And the provider of this logger that will create MyLogger. The provider is called MyLoggerProvider.

We create one file with the following code (one file for simplification, although, of course, each file should have one class):

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 state)
	{
		return null;
	}
	public bool IsEnabled(LogLevel logLevel)
	{
		return true;
	}
	public void Log(LogLevel logLevel, EventId eventId,
		TState state, Exception exception, Func formatter)
	{
		if (IsEnabled(logLevel))
		{
			var msg = formatter(state, exception);
			_logger.Info("DB-REQUEST: " + msg);
		}
	}
}

If you look closely, you can see how some other logger is forwarded to MyLoggerProvider, and then to MyLogger. It turns out already the third! The bottom line is that this third one is the class of the logging infrastructure level, which must be obtained from the bowels of the Boilerplate with the help of which the messages will be saved in the log. See below.

Step 2


Within the framework of the same * .EntityFrameworkCore project, go to the * DbContextConfigurer.cs file and make the following changes in both Configure () methods:

2.1) Add a loggerfactory parameter of type LoggerFactory

2.2) Add two lines to the method body:

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

The meaning of UseLoggerFactory is to enable the use of loggerFactory, which is passed in the parameters for logging the Database. It is very important to remember that here we enable database logging.

The meaning of EnableSensitiveDataLogging is to enable logging of not only database queries, but also record all data in these queries. Without this setting, you will not be able to see the data in the queries - they will be replaced by question marks.

Step 3


Within the framework of the same * .EntityFrameworkCore project, we go to the * DbContextFactory.cs file.

3.1) Add a new method:

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

3.2) In the CreateDbContext () method:
Because Since we previously added a new parameter to both Configure () implementations, an error should be displayed here. It is time to specify this new parameter - we register GetDbLoggerFactory () with a comma. Those. the value of the new loggerFactory parameter shall be returned by the new method from clause 3.1.

Step 4


Within the framework of the same * .EntityFrameworkCore project, we go to the * EntityFrameworkModule.cs file.

4.1) Add a new method:

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

4.2) In the PreInitialize () method:

Because Since we previously added a new parameter to both Configure () implementations, an error should also be displayed here. We specify a new parameter similarly to Section 3.2 - we register GetDbLoggerFactory () with a comma. Those. the value of the new loggerFactory parameter shall be returned by the new method from clause 4.1.

Result


In the main log file (by default Logs.txt) you will see all the queries preceded by the DB-REQUEST character sequence (it is from this that you can search for data in the log).

General understanding of the solution


So, now I will explain what we have done. An explanation is given at the end of the article, because often readers are interested in starting to do something specific already.

In the class * DbContextFactory, as well as * EntityFrameworkModule, we create our LoggerFactory, in the parameters of which we indicate the created MyLoggerProvider. But as an infrastructure class that will directly log in the first case (* DbContextFactory), we pass the NullLogger.Instance stub so that there are no entries. In the second case (* EntityFrameworkModule) we pass the logger, which is already in the Abp-module. This is the Logger field. It is already initialized and can be logged with it. Accordingly, our MyLogger will be able to write to the Logs.txt file using this class.

The whole logic is that this loggerFactory factory is installed as a log factory for working with the Database. As soon as a logger is needed, it is created by the factory. And this is our MyLogger, which, in turn, logs everything that comes to Logs.txt (or the source to which the output of your main logs is configured).

As you can see, not everything is so simple and the levels of abstractions sometimes freeze, especially for beginners! Ask your questions in the comments.

Note:

- The solution was created to turn on the logger, to understand what the error is and to turn it off. It is not designed for long-term use.

Also popular now: