preface
Recently, when developing programs with Asp.net Core
Because of time, we don't pay too much attention to the log function
They are directly recorded with the system ILogger, and then when viewing the log, first look at the log on the command line
There is no problem in the development stage, but after the system goes online
You can't always read the log on the command line. Always output the log to a convenient place to view
start
Directly reference NLog.Web.AspNetCore components
Then write the nlog.config file and put it in the root directory of the program
<?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true" internalLogLevel="Info" internalLogFile="${basedir}\..\Log\${date:format=yyyyMM}\WMSAPI-internal.txt"> <extensions> <add assembly="NLog.Web.AspNetCore"/> </extensions> <!-- Defines the variable current application name --> <variable name="AppName" value="WMSAPI" /> <!-- Log output destination --> <targets> <!-- Log to file(currency) --> <target xsi:type="File" name="allfile" fileName="${basedir}\..\Log\${date:format=yyyyMM}\${var:AppName}-all-${shortdate}.txt" encoding="UTF-8" archiveFileName="${basedir}\..\Log\${date:format=yyyyMM}\${var:AppName}-all-${shortdate}.{#}.txt" archiveAboveSize="10485760" layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" /> <!-- Output log to file (Asp.Net Core) --> <target xsi:type="File" name="ownFile-web" fileName="${basedir}\..\Log\${date:format=yyyyMM}\${var:AppName}-own-${shortdate}.txt" encoding="UTF-8" archiveFileName="${basedir}\..\Log\${date:format=yyyyMM}\${var:AppName}-own-${shortdate}.{#}.txt" archiveAboveSize="10485760" layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}|${callsite}| body: ${aspnet-request-posted-body}" /> <!--Output log to console --> <target xsi:type="Console" name="lifetimeConsole" layout="${level:truncate=4:tolower=true}: ${logger}[0]${newline} ${message}${exception:format=tostring}" /> <!--Output log to database --> <target xsi:type="Database" name="database" dbProvider="MySqlConnector.MySqlConnection, MySqlConnector"> <connectionString>${configsetting:item=ConnectionStrings.GDbContext}</connectionString> <install-command ignoreFailures="true"> <text> <!-- NOTE: call LogManager.Configuration.Install(new InstallationContext()); to execute this query. --> CREATE TABLE IF NOT EXISTS `Sys_Log${date:format=yyyyMMdd}` ( `Id` bigint NOT NULL AUTO_INCREMENT, `CreateTime` datetime NOT NULL, `AppName` varchar(50) NOT NULL, `Level` varchar(50) NOT NULL, `Logger` varchar(1024) NULL DEFAULT NULL, `Msg` text NULL, `Exception` text NULL, `UserId` varchar(50) NULL DEFAULT NULL, `Url` varchar(1024) NULL DEFAULT NULL, `IP` varchar(255) NULL DEFAULT NULL, PRIMARY KEY (`Id`) USING BTREE ); </text> </install-command> <commandText> INSERT INTO `Sys_Log${date:format=yyyyMMdd}`(`CreateTime`, `AppName`, `Level`, `Logger`, `Msg`, `Exception`, `UserId`, `Url`, `IP`) VALUES (@CreateTime, @AppName, @Level, @Logger, @Msg, @Exception, @UserId, @Url, @IP); </commandText> <parameter name="@CreateTime" layout="${longdate}" /> <parameter name="@AppName" layout="${var:AppName}" /> <parameter name="@Level" layout="${level}" /> <parameter name="@Logger" layout="${logger}" allowDbNull="true" /> <parameter name="@Msg" layout="${message}" allowDbNull="true" /> <parameter name="@Exception" layout="${exception:format=tostring}" allowDbNull="true" /> <parameter name="@UserId" layout="${aspnet-user-claim:userId}" allowDbNull="true" /> <parameter name="@Url" layout="${aspnet-request-url}" allowDbNull="true" /> <parameter name="@IP" layout="${aspnet-request-ip}" allowDbNull="true" /> </target> </targets> <!-- Log output rules --> <rules> <!--All logs, including from Microsoft--> <!--<logger name="*" minlevel="Trace" writeTo="allfile" />--> <!--Output hosting lifetime messages to console target for faster startup detection --> <logger name="Microsoft.Hosting.Lifetime" minlevel="Info" writeTo="lifetimeConsole, ownFile-web, database" final="true" /> <logger name="Microsoft.EntityFrameworkCore.Model.Validation" maxlevel="Error" final="true" /> <!--Skip non-critical Microsoft logs and so log only own logs (BlackHole) --> <logger name="Microsoft.*" maxlevel="Info" final="true" /> <logger name="System.Net.Http.*" maxlevel="Info" final="true" /> <logger name="*" minlevel="Trace" writeTo="ownFile-web, database" /> </rules> </nlog>
You can see that we have defined four output targets. The first two are files, one is the console and the other is the database
Output to file basic definition
fileName: output file name
The archiveFileName and archiveAboveSize parameters are used when the file exceeds the size of archiveAboveSize
Split the file, and then the split file name is defined with archiveFileName
layout is the content of the log file, and the content closed with ${} is the parameter provided by NLog
For details, please refer to
https://nlog-project.org/config/?tab=layout-renderers
<target xsi:type="File" name="ownFile-web" fileName="${basedir}\..\Log\${date:format=yyyyMM}\${var:AppName}-own-${shortdate}.txt" encoding="UTF-8" archiveFileName="${basedir}\..\Log\WMSAPI-own-${shortdate}.{#}.txt" archiveAboveSize="10485760" layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}|${callsite}| body: ${aspnet-request-posted-body}" />
Output to database basic definition
dbProvider: using database components
connectionString: connection string
Install command: install script (use this to automatically create tables)
commandText: script to insert log into data table
parameter: insert the parameters of the script
<target xsi:type="Database" name="database" dbProvider="MySqlConnector.MySqlConnection, MySqlConnector"> <connectionString>${configsetting:item=ConnectionStrings.GDbContext}</connectionString> <install-command ignoreFailures="true"> <text> <!-- NOTE: call LogManager.Configuration.Install(new InstallationContext()); to execute this query. --> CREATE TABLE IF NOT EXISTS `Sys_Log${date:format=yyyyMMdd}` ( `Id` bigint NOT NULL AUTO_INCREMENT, `CreateTime` datetime NOT NULL, `AppName` varchar(50) NOT NULL, `Level` varchar(50) NOT NULL, `Logger` varchar(1024) NULL DEFAULT NULL, `Msg` text NULL, `Exception` text NULL, `UserId` varchar(50) NULL DEFAULT NULL, `Url` varchar(1024) NULL DEFAULT NULL, `IP` varchar(255) NULL DEFAULT NULL, PRIMARY KEY (`Id`) USING BTREE ); </text> </install-command> <commandText> INSERT INTO `Sys_Log${date:format=yyyyMMdd}`(`CreateTime`, `AppName`, `Level`, `Logger`, `Msg`, `Exception`, `UserId`, `Url`, `IP`) VALUES (@CreateTime, @AppName, @Level, @Logger, @Msg, @Exception, @UserId, @Url, @IP); </commandText> <parameter name="@CreateTime" layout="${longdate}" /> <parameter name="@AppName" layout="${var:AppName}" /> <parameter name="@Level" layout="${level}" /> <parameter name="@Logger" layout="${logger}" allowDbNull="true" /> <parameter name="@Msg" layout="${message}" allowDbNull="true" /> <parameter name="@Exception" layout="${exception:format=tostring}" allowDbNull="true" /> <parameter name="@UserId" layout="${aspnet-user-claim:userId}" allowDbNull="true" /> <parameter name="@Url" layout="${aspnet-request-url}" allowDbNull="true" /> <parameter name="@IP" layout="${aspnet-request-ip}" allowDbNull="true" /> </target>
You can see the SQL script for creating tables written by install command here
The table name is Sys_Log${date:format=yyyyMMdd}, so the table name we created is sys_ Log20211103 (formatted according to daytime)
However, NLog will not automatically run the table creation script for us. We need to call it in the code
LogManager.Configuration.Install(new InstallationContext());
Using this method, he will run the script in install command.
Because we divide the table by day, it's equivalent to running it once a day
LogManager.Configuration.Install(new InstallationContext());
So I wrote a regular HostedService. To automatically run the Install method of NLog every day
public class LogHostedService : IHostedService, IAsyncDisposable { private Timer RunTimer { get; set; } public Task StartAsync(CancellationToken cancellationToken) { LogManager.Configuration.Install(new NLog.Config.InstallationContext());//Execute once after startup this.RunTimer = new Timer(LogInstall, null, DateTime.Now.AddDays(1).Date - DateTime.Now, TimeSpan.FromDays(1)); return Task.CompletedTask; } public void LogInstall(object state) { LogManager.Configuration.Install(new NLog.Config.InstallationContext());//Execute once every day at 0:00 } public Task StopAsync(CancellationToken cancellationToken) { this.RunTimer?.Change(Timeout.Infinite, 0); return Task.CompletedTask; } public ValueTask DisposeAsync() { return this.RunTimer.DisposeAsync(); } }
In this way, the log table of the day will be created at system startup and at 0:00 every day
Then our insert statement INSERT INTO Sys_Log${date:format=yyyyMMdd}
It will be automatically inserted into the daily log table
Code enable NLog
We use UseNLog() in the Program.cs file to enable NLog components
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }) .UseNLog();
Then enable HostedService in Startup.cs to regularly create daily log tables
public void ConfigureServices(IServiceCollection services) { services.AddHostedService<LogHostedService>();//Automatically create log table every day }