in ASP. NET 4.X, we typically use log4net, NLog, and so on to log logs, but when we reference some third-party class libraries that use different log frameworks, it's a bit confusing. The log system is built into ASP. NET core, and provides a unified log interface, and the ASP. The log interface is used to record logs, regardless of the specific implementation of the log, so that it can be configured in our application in a uniform way. And can be well integrated with the third-party log framework.
Register Log Service
ASP. NET Core uses dependency injection to better standardize our code. To use the log system, you first need to register and configure:
public void ConfigureServices(IServiceCollection services) { services.AddLogging(builder => { builder .AddConfiguration(loggingConfiguration.GetSection("Logging")) .AddFilter("Microsoft", LogLevel.Warning) .AddConsole(); });}
As above, through AddLogging
, the log system is registered to the DI system, but the AddConfiguration
global configuration of the log system, AddFilter
is a few configuration of the log filter, and finally AddConsole
added a Console log provider (log Output to a console).
Record log
When we need to log, we just need to inject through the constructor function ILogger<T>
:
PublicClassTodocontroller:controller{PrivateReadOnly Itodorepository _todorepository;PrivateReadOnly ILogger _logger;Publictodocontroller (itodorepository todorepository, ILogger< todocontroller> logger) {_todorepository = todorepository; _logger = logger;} [HttpGet] public iactionresult GetById ( Span class= "Hljs-params" >string ID) {_logger. Loginformation (Loggingevents.get_item, "Getting ITEM {ID}", id); var item = _todorepository.find (ID); if (item = = null) {_logger. Logwarning (Loggingevents.get_item_notfound, "GetById ({ID}) not FOUND", ID); return NotFound (); } return new objectresult (item);}}
ILogger<T>
The T
categories that represent journaling are very useful when we look at the logs, which are described later in this article.
Sample log Output
Using the example code above, when we run through the console, the access http://localhost:5000/api/todo/0
will see the following log output:
info:microsoft.aspnetcore.hosting.internal.webhost[1] Request starting HTTP/1.1 GET http://localhost:5000/api/todo/invalididinfo:microsoft.aspnetcore.mvc.internal.controlleractioninvoker[1] Executing action method TodoApi.Controllers.TodoController.GetById (TODOAPI) with arguments (invalidid)-Modelstate I S Validinfo:todoapi.controllers.todocontroller[1002] Getting item Invalididwarn: Todoapi.controllers.todocontroller[4000] GetById (invalidid) not FOUND info:microsoft.aspnetcore.mvc.statuscoderesult[1] Executing Httpstatuscoderesult, setting HTTP status code 404info: Microsoft.aspnetcore.mvc.internal.controlleractioninvoker[2] Executed action TodoApi.Controllers.TodoController.GetById (TODOAPI) in 243.2636msinfo:microsoft.aspnetcore.hosting.internal.webhost[ 2] Request finished in 628.9188ms Span class= "Hljs-number" >404
If we visit http://localhost:55070/api/todo/0
, we will see:
Microsoft.AspNetCore.Hosting.Internal.Webhost:Information:request starting HTTP/1.1 GET http://localhost:55070/api/todo/invalididmicrosoft.aspnetcore.mvc.internal.Controlleractioninvoker:Information:executing action Method TodoApi.Controllers.TodoController.GetById (TODOAPI) with arguments (Invalidid)- Modelstate is validtodoapi.controllers.Todocontroller:information:getting item invalididtodoapi.controllers. todocontroller:warning:getbyid (Invalidid) not FOUNDMICROSOFT.ASPNETCORE.MVC. statuscoderesult:information:executing HttpStatusCodeResult , setting HTTP status code 404microsoft.aspnetcore.mvc.internal. Controlleractioninvoker:information:executed action TodoApi.Controllers.TodoController.GetById (TODOAPI) in 12.5003msmicrosoft.aspnetcore.hosting.internal. webhost:information:request finished in 19.0913ms 404
In this example, we can see that we have logged the log of the ASP. NET Core framework itself, which is a feature that can be implemented by a unified logging framework.
Log category
Each logger that we create specifies a category. It can be any string, but the contract uses the fully qualified name of the Write class, such as "TodoApi.Controllers.TodoController". If you want to explicitly specify the kind of log, you can use ILoggerFactory
the CreateLogger
method in:
public class TodoController : Controller{ private readonly ILogger _logger; public TodoController(ILoggerFactory logger) { _logger = logger.CreateLogger("TodoApi.Controllers.TodoController"); }}
However, most of the time, we still use it ILogger<T>
more conveniently:
public class TodoController : Controller{ private readonly ILogger _logger; public TodoController(ILogger<TodoController> logger) { _logger = logger; }}
This is equivalent to T
invoking the method with the full qualified name of the type CreateLogger
.
Log level
When we log, we need to specify the level of the log, which is very useful for our filtering logs, such as in a test environment where we want to provide very detailed log information, including some sensitive information, but in a production environment, we want to log only serious errors, simply by AddFilter
Configure the filter level for the log.
The ASP. NET Core Logging system provides six log levels by increasing the importance or severity of the order as follows:
Trace is used to record the most verbose log messages and is typically used only for development phase debugging issues. These messages may contain sensitive application data and therefore should not be used in production environments. The default should be disabled.
Debug This message is useful in the short term during the development phase. They contain information that may be useful for debugging, but have no long-term value. This is the most verbose log by default.
Information This message is used to track the general flow of the application. In contrast to Verbose level messages, these logs should have some long-term value.
Warning Use the warning level when an application has an error or other process exception or unexpected event that does not cause the program to stop for future investigation. Handle warning level exceptions in a common place.
Error logging is required when the application stops working due to certain failures. These messages should indicate the current activity or operation (such as the current HTTP request), rather than the application-wide failure.
Critical log at the critical level should be logged when an application or system crashes, encounters a catastrophic failure, and needs immediate attention. such as data loss, insufficient disk space, and so on.
Log Event ID
Each time we write a log, we can specify an event ID:
PublicClassloggingevents{PublicConstint get_item =1002; public const int GET_ITEM_ NOTFOUND = 4000;} public iactionresult GetById ( Span class= "Hljs-params" >string ID) {_logger. Loginformation (Loggingevents.get_item, "Getting ITEM {ID}", id); var item = _todorepository.find (ID); if (item = = null) {_logger. Logwarning (Loggingevents.get_item_notfound, "GetById ({ID}) not FOUND", ID); return NotFound (); } return new objectresult (item);}
Event ID is an integer that can associate a set of log events together. Similar to the log category, but more granular. And its output depends on the log provider, Console provider output format, followed by the log category and wrapped in a pair of brackets:
info: TodoApi.Controllers.TodoController[1002] Getting item invalididwarn: TodoApi.Controllers.TodoController[4000] GetById(invalidid) NOT FOUND
Log formatted string
Each time a log is logged, a text message is provided, and in this message string we can use the named placeholder:
public IActionResult GetById(string id){ _logger.LogInformation(LoggingEvents.GET_ITEM, "Getting item {ID}", id); var item = _todoRepository.Find(id); if (item == null) { _logger.LogWarning(LoggingEvents.GET_ITEM_NOTFOUND, "GetById({ID}) NOT FOUND", id); return NotFound(); } return new ObjectResult(item);}
But the order of the placeholders determines which parameter to use, not its name, as in the following example:
string p1 = "parm1";string p2 = "parm2";_logger.LogInformation("Parameter values: {p2}, {p1}", p1, p2);
The output is:
Parameter values: parm1, parm2
What's the point of doing that?
The log framework uses this message format to enable the log provider to implement a semantic log, also known as a structured log. Because the parameter itself is passed to the log system, not just the formatted string, the log provider can store the value of the parameter as a field in a separate store. For example, if you use Azure Table Storage, we can use the following methods to log logs:
_logger.LogInformation("Getting item {ID} at {RequestTime}", id, DateTime.Now);
Each Azure Table can have ID
and RequestTime
attributes, which simplifies querying the log data, and you can find RequestTime
all the logs in a specified range without having to spend the cost of parsing text messages.
Filter filters
Filters allow you to choose whether to output or ignore depending on the level and category of the log. We can specify different filters for different log providers, as shown in the following code, which allows the Console provider to ignore warning
logs below the level, while the Debug provider ignores TodoApi
the category's logs.
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory){ loggerFactory .AddConsole(LogLevel.Warning) .AddDebug((category, logLevel) => (category.Contains("TodoApi") && logLevel >= LogLevel.Trace));}
We can also specify a global filter for all log providers, as in the following example, we ignore lower-level logs for log categories that start with "Microsoft" and "System" Warning
:
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory){ loggerFactory .AddFilter("Microsoft", LogLevel.Warning) .AddFilter("System", LogLevel.Warning) .AddFilter("SampleApp.Program", LogLevel.Debug) .AddDebug();}
Scope
We can put a set of logical operations in an ordered scope and append the scope 's identity to all the logs in the range. For example, we can handle transactions so that each operation log within a transaction contains the ID of the transaction.
Use Ilgger.beginscope<tstate>
method to create a Scope and return a IDisposable
Type, when we Dispose
, this Scope is finished, ideal for use with using
How to :
public IActionResult GetById(string id){ TodoItem item; using (_logger.BeginScope("Message attached to logs created in the using block")) { _logger.LogInformation(LoggingEvents.GET_ITEM, "Getting item {ID}", id); item = _todoRepository.Find(id); if (item == null) { _logger.LogWarning(LoggingEvents.GET_ITEM_NOTFOUND, "GetById({ID}) NOT FOUND", id); return NotFound(); } } return new ObjectResult(item);}
Each log will include the Scope information:
info: TodoApi.Controllers.TodoController[1002] => RequestId:0HKV9C49II9CK RequestPath:/api/todo/0 => TodoApi.Controllers.TodoController.GetById (TodoApi) => Message attached to logs created in the using block Getting item 0warn: TodoApi.Controllers.TodoController[4000] => RequestId:0HKV9C49II9CK RequestPath:/api/todo/0 => TodoApi.Controllers.TodoController.GetById (TodoApi) => Message attached to logs created in the using block GetById(0) NOT FOUND
Summarize
ASP. NET Core provides a unified logging framework that can be easily Startup
configured through classes, flexibly integrates with third-party log frameworks, and is used in applications using dependency injection. This article summarizes the overall Logging system, in the next chapter, will analyze the Logging in the configuration of the source code.
Refer to Microsoft Official documentation: Introduction to Logging in ASP.
Rainy Night Dim original Link: https://www.cnblogs.com/RainingNight/p/asp-net-core-logging-introduction.html
ASP. NET Core Source Learning Logging