.NET 8使用日志功能以及自定义日志提供程序
.NET 8使用日志功能以及自定义日志提供程序
日志级别
下表列出了 LogLevel 值、方便的 Log{LogLevel} 扩展方法以及建议的用法:
展开表
| LogLevel | “值” | 方法 | 描述 | 
|---|---|---|---|
| Trace | 0 | LogTrace | 包含最详细的消息。 这些消息可能包含敏感的应用数据。 这些消息默认情况下处于禁用状态,并且不应在生产中启用。 | 
| 调试 | 1 | LogDebug | 用于调试和开发。 由于量大,请在生产中小心使用。 | 
| 信息 | 2 | LogInformation | 跟踪应用的常规流。 可能具有长期值。 | 
| 警告 | 3 | LogWarning | 对于异常事件或意外事件。 通常包括不会导致应用失败的错误或情况。 | 
| 错误 | 4 | LogError | 表示无法处理的错误和异常。 这些消息表示当前操作或请求失败,而不是整个应用失败。 | 
| 严重 | 5 | LogCritical | 需要立即关注的失败。 例如数据丢失、磁盘空间不足。 | 
| 无 | 6 | 指定不应写入任何消息。 | 
一、使用log4net
1、安装需要的Nuget包
在项目中使用程序包管理器控制台安装log4net包
Install-Package log4net
如果在AspNetCore项目还需要安装 Microsoft.Extensions.Logging.Log4Net.AspNetCore
Install-Package Microsoft.Extensions.Logging.Log4Net.AspNetCore
也可以使在Nuget管理程序中,搜索 "Microsoft.Extensions.Logging.Log4Net.AspNetCore",然后点击安装。
2、代码中使用log4net日志组件
2.1、新建一个log4net.config配置文件
配置文件参考如下
<?xml version="1.0" encoding="utf-8" ?>
<!-- log4net.config -->
<log4net>
    <!--通用日志类-->
    <!--日志类的名字-->
    <logger name="Common">
        <!--定义记录的日志级别-->
        <level value="ALL" />
        <!--记录到哪个介质中去-->
        <appender-ref ref="RollingLogFileAppender" />
    </logger>
    <!--其中layout节点的配置说明:
        %m(message):输出的日志消息;
        %n(newline):换行;
		%d(datetime):输出当前语句运行的时刻;
		%r(runtime):输出程序从运行到执行到当前语句时消耗的毫秒数;
		%t(threadid):当前语句所在的线程ID ;
		%p(priority): 日志的当前日志级别;
		%c(class):当前日志对象的名称;
		%L:输出语句所在的行号;
		%F:输出语句所在的文件名;
		%-10:表示最小长度为10,如果不够,则用空格填充;-->
    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
        <!--日志路径-->
        <param name= "File" value= "Logs/"/>
        <!--多线程时采用最小锁定-->
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
        <!--是否是向文件中追加日志-->
        <param name= "AppendToFile" value= "true"/>
        <!--log保留天数-->
        <!--<param name= "MaxSizeRollBackups" value= "10"/>-->
        <!--日志文件名是否是固定不变的-->
        <param name= "StaticLogFileName" value= "false"/>
        <!--日志文件名格式为:2022-05-22.log-->
        <param name= "DatePattern" value= "yyyy-MM-dd'.log'"/>
        <!--日志根据日期滚动-->
        <param name= "RollingStyle" value= "Date"/>
        <layout type="log4net.Layout.PatternLayout">
            <param name="ConversionPattern" value="%n%d [%t] %-5p %c [%L] - %m %n" />
        </layout>
    </appender>
    <root>
        <!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) -->
        <level value="all" />
        <!--<appender-ref ref="ColoredConsoleAppender"/>-->
        <appender-ref ref="RollingLogFileAppender"/>
    </root>
</log4net>
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<configSections>
		<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
	</configSections>
	<log4net debug="false">
		<appender name="info" type="log4net.Appender.RollingFileAppender,log4net">
			<param name="File" value="log4net/info/" />
			<param name="AppendToFile" value="true" />
			<param name="MaxSizeRollBackups" value="-1"/>
			<param name="MaximumFileSize" value="5MB"/>
			<param name="RollingStyle" value="Composite" />
			<param name="DatePattern" value="yyyyMMdd\\HH".log"" />
			<param name="StaticLogFileName" value="false" />
			<layout type="log4net.Layout.PatternLayout,log4net">
				<param name="ConversionPattern" value="%n
{
    "system": "Meowv.Blog",
    "datetime": "%d",
    "description": "%m",
  "level": "%p",
    "info": "%exception"
}" />
			</layout>
			<filter type="log4net.Filter.LevelRangeFilter">
				<levelMin value="INFO" />
				<levelMax value="INFO" />
			</filter>
		</appender>
		<appender name="error" type="log4net.Appender.RollingFileAppender,log4net">
			<param name="File" value="log4net/error/" />
			<param name="AppendToFile" value="true" />
			<param name="MaxSizeRollBackups" value="-1"/>
			<param name="MaximumFileSize" value="5MB"/>
			<param name="RollingStyle" value="Composite" />
			<param name="DatePattern" value="yyyyMMdd\\HH".log"" />
			<param name="StaticLogFileName" value="false" />
			<layout type="log4net.Layout.PatternLayout,log4net">
				<param name="ConversionPattern" value="%n
{
    "system": "Meowv.Blog",
    "datetime": "%d",
    "description": "%m",
  "level": "%p",
    "info": "%exception"
}" />
			</layout>
			<filter type="log4net.Filter.LevelRangeFilter">
				<levelMin value="ERROR" />
				<levelMax value="ERROR" />
			</filter>
		</appender>
		<root>
			<level value="ALL"></level>
			<appender-ref ref="info"/>
			<appender-ref ref="error"/>
		</root>
	</log4net>
</configuration>
<?xml version="1.0" encoding="utf-8"?>
<!--log4net日志配置信息-->
<log4net>
	<!-- 控制台日志配置 -->
	<appender name="Console" type="log4net.Appender.ConsoleAppender">
		<!-- 日志输出格式 -->
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="%5level [%thread] (%file:%line) - %message%newline" />
		</layout>
	</appender>
	<!-- 文件存储日志配置 -->
	<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
		<!--目录路径,可以是相对路径或绝对路径-->
		<file value="log\" />
		<!--追加日志内容-->
		<appendToFile value="true" />
		<!--防止多线程时不能写Log,官方说线程非安全-->
		<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
		<!--可以为:Once|Size|Date|Composite-->
		<!--Composite为Size和Date的组合-->
		<rollingStyle value="Composite" />
		<!--日期的格式,每天换一个文件记录,如不设置则永远只记录一天的日志,需设置-->
		<datePattern value="yyyy-MM-dd".txt"" />
		<!--文件名,按日期生成文件夹-->
		<!--<param name="DatePattern" value="/yyyy-MM-dd/"Error.log=""""/>-->
		<!-- 保存文件数量 -->
		<!--日志最大个数,都是最新的-->
		<!--rollingStyle节点为Size时,只能有value个日志-->
		<!--rollingStyle节点为Composite时,每天有value个日志-->
		<!--最多保留的文件数,设为"-1"则不限-->
		<maxSizeRollBackups value="20" />
		<!-- 文件的编码方式 -->
		<param name="Encoding" value="UTF-8"/>
		<!-- 每个文件的大小 -->
		<!--可用的单位:KB|MB|GB-->
		<maximumFileSize value="3MB" />
		<!--置为true,当前最新日志文件名永远为file节中的名字-->
		<staticLogFileName value="false" />
		<!-- 日志输出格式 -->
		<layout type="log4net.Layout.PatternLayout">
			<!--<conversionPattern value="%level %thread %logger - %message%newline" />-->
			<param name="ConversionPattern" value="%newline %n记录时间:%date %n线程ID:[%thread] %n日志级别:%-5level %n出错类:%logger %n请求URI:%message %n异常信息:%exception%newline %n" />
		</layout>
	</appender>
	<!--SQL数据库-->
	<appender name="AdoNetAppender" type="MicroKnights.Logging.AdoNetAppender, MicroKnights.Log4NetAdoNetAppender">
		<bufferSize value="1" />
		<!-- SQL数据源-->
		<connectionType value="Microsoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient, Version=1.0.0.0,Culture=neutral,PublicKeyToken=23ec7fc2d6eaa4a5"/>
		<!-- SQL连接字符串-->
		<!--<connectionString value="Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=YMHealth;Data Source=." />-->
		<connectionString value="Integrated Security=False;Data Source=47.110.55.108;Initial Catalog=BreastHealthbat;User Id=sa;pwd=Sinoadmin@136;" />
		<!--<connectionString value="Integrated Security=False;Data Source=.;Initial Catalog=BreastHealth;User Id=sa;pwd=sasino;" />-->
		<commandText value="INSERT INTO TLog ([ThreadId],[LogLevel],[Logger],[LogMessage],[LogException],[LogDate]) VALUES  (@thread,@logLevel,@logger,@message,@exception,@logDate)" />
		<parameter>
			<parameterName value="@thread" />
			<dbType value="String" />
			<size value="5" />
			<layout type="log4net.Layout.PatternLayout">
				<conversionPattern value="%t" />
			</layout>
		</parameter>
		<parameter>
			<parameterName value="@logLevel" />
			<dbType value="String" />
			<size value="5" />
			<layout type="log4net.Layout.PatternLayout">
				<conversionPattern value="%p" />
			</layout>
		</parameter>
		<parameter>
			<parameterName value="@logger" />
			<dbType value="String" />
			<size value="3000" />
			<layout type="log4net.Layout.PatternLayout">
				<conversionPattern value="%logger" />
			</layout>
		</parameter>
		<parameter>
			<parameterName value="@message" />
			<dbType value="String" />
			<size value="3000" />
			<layout type="log4net.Layout.PatternLayout">
				<conversionPattern value="%message" />
			</layout>
		</parameter>
		<parameter>
			<parameterName value="@exception" />
			<dbType value="String" />
			<size value="3000" />
			<layout type="log4net.Layout.ExceptionLayout" />
		</parameter>
		<parameter>
			<parameterName value="@logDate" />
			<dbType value="DateTime" />
			<layout type="log4net.Layout.RawTimeStampLayout" />
		</parameter>
	</appender>
	<!--根配置-->
	<root>
		<!--日志级别:可选值: ERROR > WARN > INFO > DEBUG -->
		<level value="ERROR" />
		<!--<appender-ref ref="Console" />
		<appender-ref ref="RollingFile" />-->
		<appender-ref ref="AdoNetAppender" />
		<appender-ref ref="RollingFileAppender" />
	</root>
</log4net>
2.2、设置文件为始终复制

2.3、在控制台中使用
using log4net.Config;
using log4net;
using System.Reflection;
namespace Test.ConsoleApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var log4netRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
            XmlConfigurator.Configure(log4netRepository, new FileInfo("log4net.config"));
            var log = LogManager.GetLogger(log4netRepository.Name, "NETCorelog4net");
            log.Info("NETCorelog4net log");
            log.Info("test log");
            log.Error("error");
            log.Info("linezero");
            Console.ReadKey();
        }
    }
}
2.4、在AspNetCore项目中使用
方式一
//默认路径是根目录的log4net.config,也可以更改log4net.config路径,和名称
builder.Logging.AddLog4Net("Configs/log4net.config");
方式二
builder.Services.AddLogging(logging =>
{
    //默认的配置文件路径是在根目录,且文件名为log4net.config
    //logging.AddLog4Net();
    logging.AddLog4Net("Configs/log4net.config");
    //如果文件路径或名称有变化,需要重新设置其路径或名称
    //比如在项目根目录下创建一个名为cfg的文件夹,将log4net.config文件移入其中,并改名为log.config
    //则需要使用下面的代码来进行配置
    //logging.AddLog4Net(new Log4NetProviderOptions()
    //{
    //    Log4NetConfigFileName = "cfg/log.config",
    //    Watch = true
    //});
});
方式三(有问题,在.NET6之前的Startup类Configure方法注入有用)
//也可以使用ILoggerFactory注入log4net
//loggerFactory.AddLog4Net();
using ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
{
    builder.AddLog4Net("Configs/log4net.config");
});
参考文档:
https://www.cnblogs.com/wei325/p/16000271.html
https://github.com/huorswords/Microsoft.Extensions.Logging.Log4Net.AspNetCore
https://www.cnblogs.com/shangec/p/14666007.html
https://www.cnblogs.com/vvull/p/17967654
https://docs.meowv.com/stack/dotnetcore/log4net-in-dotnet.html
二、使用Nlog
1、控制台项目
1.1、安装如下Nuget包
Install-Package Microsoft.Extensions.Configuration.Json
Install-Package NLog
Install-Package NLog.Extensions.Logging
1.2、在控制台项目创建appsetting.json文件,文件内容如下
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}
1.3、创建nlog.config文件,并设置属性为始终复制,下面是config文件参考
<?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="Warn"
      internalLogFile="internal-nlog.txt">
  <!-- define various log targets -->
  <targets>
    <!-- write logs to file -->
    <target xsi:type="File" name="allfile" fileName="nlog-all-${shortdate}.log"
                 layout="${longdate}|${logger}|${uppercase:${level}}|${message} ${exception}" />
    <target xsi:type="File" name="ownFile-web" fileName="nlog-own-${shortdate}.log"
             layout="${longdate}|${logger}|${uppercase:${level}}|  ${message} ${exception}" />
    <target xsi:type="Null" name="blackhole" />
  </targets>
  <rules>
    <!--All logs, including from Microsoft-->
    <logger name="*" minlevel="Trace" writeTo="allfile" />
    <!--Skip Microsoft logs and so log only own logs-->
    <logger name="Microsoft.*" minlevel="Trace" writeTo="blackhole" final="true" />
    <logger name="*" minlevel="Trace" writeTo="ownFile-web" />
  </rules>
</nlog>
1.4、添加一个类Runner.cs
using Microsoft.Extensions.Logging;
namespace ConsoleDemo
{
    public class Runner
    {
        private readonly ILogger<Runner> _logger;
        public Runner(ILogger<Runner> logger)
        {
            _logger = logger;
        }
        public void DoAction(string name)
        {
            _logger.LogDebug(20, "Doing hard work! {Action}", name);
        }
    }
}
<?xml version="1.0" encoding="utf-8" ?>
<!-- XSD manual extracted from package NLog.Schema: https://www.nuget.org/packages/NLog.Schema-->
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      internalLogLevel="Info"
      internalLogFile="nlog\internal-nlog.txt">
	<!-- the targets to write to -->
	<targets>
		<!-- write logs to file -->
		<target xsi:type="File" name="logfile" fileName="nlog\console${shortdate}.log"
            layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
		<target xsi:type="Console" name="logconsole"
				layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
		<target xsi:type="Null" name="blackhole" />
	</targets>
	<!-- rules to map from logger name to target -->
	<rules>
		<logger name="*" minlevel="Trace" writeTo="logfile,logconsole" />
	</rules>
</nlog>
1.5、通过注入的方式调用。
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NLog;
using NLog.Extensions.Logging;
using System;
namespace Test.ConsoleApp
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            #region nlog
            var logger = LogManager.GetCurrentClassLogger();
            try
            {
                var config = new ConfigurationBuilder()
                .SetBasePath(System.IO.Directory.GetCurrentDirectory()) //From NuGet Package Microsoft.Extensions.Configuration.Json
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .Build();
                using var servicesProvider = new ServiceCollection()
                 .AddTransient<Runner>() // Runner is the custom class
                 .AddLogging(loggingBuilder =>
                 {
                     // configure Logging with NLog
                     loggingBuilder.ClearProviders();
                     loggingBuilder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
                     loggingBuilder.AddNLog(config);
                 }).BuildServiceProvider();
                var runner = servicesProvider.GetRequiredService<Runner>();
                runner.DoAction("Action1");
                Console.WriteLine("Press ANY key to exit");
                Console.ReadKey();
            }
            catch (Exception ex)
            {
                // NLog: catch any exception and log it.
                logger.Error(ex, "Stopped program because of exception");
                throw;
            }
            finally
            {
                LogManager.Shutdown();
            }
            Console.ReadKey();
        }
    }
}
1.6、最简单的示例
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
namespace ConsoleExample
{
    internal static class Program
    {
        private static void Main()
        {
            var logger = LoggerFactory.Create(builder => builder.AddNLog()).CreateLogger<Program>();
            logger.LogInformation("Program has started.");
            Console.ReadKey();
        }
    }
}
2、在ASP.NET CORE项目中使用NLog
2.1、在Web项目中添加包
Install-Package NLog
Install-Package NLog.Web.AspNetCore
2.2、在appsetting.json文件如下配置
{
  "Logging": {
    "LogLevel": {
      "Default": "Trace",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}
2.3、 创建 nlog.config 文件。
在项目的根目录中创建 nlog.config(全部小写)文件
创建nlog.config文件,并设置属性为始终复制,下面是config文件参考
<?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="Warn"
      internalLogFile="internal-nlog.txt">
  <!-- define various log targets -->
  <targets>
    <!-- write logs to file -->
    <target xsi:type="File" name="allfile" fileName="nlog-all-${shortdate}.log"
                 layout="${longdate}|${logger}|${uppercase:${level}}|${message} ${exception}" />
    <target xsi:type="File" name="ownFile-web" fileName="nlog-own-${shortdate}.log"
             layout="${longdate}|${logger}|${uppercase:${level}}|  ${message} ${exception}" />
    <target xsi:type="Null" name="blackhole" />
  </targets>
  <rules>
    <!--All logs, including from Microsoft-->
    <logger name="*" minlevel="Trace" writeTo="allfile" />
    <!--Skip Microsoft logs and so log only own logs-->
    <logger name="Microsoft.*" minlevel="Trace" writeTo="blackhole" final="true" />
    <logger name="*" minlevel="Trace" writeTo="ownFile-web" />
  </rules>
</nlog>
<?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="c:\temp\internal-nlog-AspNetCore.txt">
  <!-- enable asp.net core layout renderers -->
  <extensions>
    <add assembly="NLog.Web.AspNetCore"/>
  </extensions>
  <!-- the targets to write to -->
  <targets>
    <!-- File Target for all log messages with basic details -->
    <target xsi:type="File" name="allfile" fileName="c:\temp\nlog-AspNetCore-all-${shortdate}.log"
            layout="${longdate}|${event-properties:item=EventId:whenEmpty=0}|${level:uppercase=true}|${logger}|${message} ${exception:format=tostring}" />
    <!-- File Target for own log messages with extra web details using some ASP.NET core renderers -->
    <target xsi:type="File" name="ownFile-web" fileName="c:\temp\nlog-AspNetCore-own-${shortdate}.log"
            layout="${longdate}|${event-properties:item=EventId:whenEmpty=0}|${level:uppercase=true}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />
    <!--Console Target for hosting lifetime messages to improve Docker / Visual Studio startup detection -->
    <target xsi:type="Console" name="lifetimeConsole" layout="${MicrosoftConsoleLayout}" />
  </targets>
  <!-- rules to map from logger name to target -->
  <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" 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" />
  </rules>
</nlog>
上面的c:\temp可以改成nlog
2.4、program.cs代码如下
using NLog;
using NLog.Web;
// Early init of NLog to allow startup and exception logging, before host is built
var logger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
logger.Debug("init main");
try
{
    var builder = WebApplication.CreateBuilder(args);
    // Add services to the container.
    builder.Services.AddControllersWithViews();
    // NLog: Setup NLog for Dependency injection
    builder.Logging.ClearProviders();
    //如果使用Configs文件夹下的配置使用builder.Logging.AddNLog注入
    //builder.Logging.AddNLog("Configs/nlog.config");
    //如果是在根目录可以直接使用builder.Host.UseNLog();
    builder.Host.UseNLog();
    var app = builder.Build();
    // Configure the HTTP request pipeline.
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseAuthorization();
    app.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
    app.Run();
}
catch (Exception exception)
{
    // NLog: catch setup errors
    logger.Error(exception, "Stopped program because of exception");
    throw;
}
finally
{
    // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
    NLog.LogManager.Shutdown();
}
2.5、 Microsoft日志记录过滤器
使用 NLog 5.0 时,默认情况下会忽略 Microsoft 日志记录筛选器。只需确保正确配置 NLog 配置规则即可。appsettings.json
<rules>
    <logger name="System.*" finalMinLevel="Warn" />
    <logger name="Microsoft.*" finalMinLevel="Warn" />
    <logger name="Microsoft.Hosting.Lifetime*" finalMinLevel="Info" />
    <logger name="*" minlevel="Trace" writeTo="ownFile-web" />
</rules>
写入日志
在控制器中注入 ILogger:
using Microsoft.Extensions.Logging;
public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
        _logger.LogDebug(1, "NLog injected into HomeController");
    }
    public IActionResult Index()
    {
        _logger.LogInformation("Hello, this is the index!");
        return View();
    }
}
参考文档:
Getting started with .NET Core 2 Console application · NLog/NLog Wiki · GitHub
Getting started with ASP.NET Core 6 · NLog/NLog Wiki · GitHub
https://docs.meowv.com/stack/dotnetcore/nlog-in-dotnet.html
https://zhuanlan.zhihu.com/p/35469359
https://www.cjavapy.com/article/3102/
https://www.cnblogs.com/haiouxiangyun/p/15921375.html
三、使用Serlog
1、控制台项目
1.1、在项目中添加下面几个组件包
Install-Package Serilog.Extensions.Logging
Install-Package Serilog
Install-Package Serilog.Sinks.Console
Install-Package Serilog.Sinks.File
1.2、Program.cs代码参考如下
using System;
using Serilog;
class Program
{
    static async Task Main()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.Console()
            .WriteTo.File("logs/myapp.txt", rollingInterval: RollingInterval.Day)
            .CreateLogger();
//上面和下面的都可以
//           Log.Logger = new LoggerConfiguration()
//          .MinimumLevel.Information()
//          .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
//#if DEBUG
//           .MinimumLevel.Override("Xxx", LogEventLevel.Debug)
//#else
//            .MinimumLevel.Override("Xxx", LogEventLevel.Information)
//#endif
//          .Enrich.FromLogContext()
//          .WriteTo.Console()
//          .WriteTo.File(Path.Combine(Directory.GetCurrentDirectory(), "logs/logs.txt"))
//          .CreateLogger();
        Log.Information("Hello, world!");
        int a = 10, b = 0;
        try
        {
            Log.Debug("Dividing {A} by {B}", a, b);
            Console.WriteLine(a / b);
        }
        catch (Exception ex)
        {
            Log.Error(ex, "Something went wrong");
        }
        finally
        {
            await Log.CloseAndFlushAsync();
        }
    }
}
2、AspNetCore项目
2.1、在项目中添加下面几个组件包
Install-Package Serilog.AspNetCore
Install-Package Serilog.Sinks.Async
Install-Package Serilog.Sinks.File
2.2、Program.cs代码参考:
using Serilog;
Log.Logger = new LoggerConfiguration()
    .WriteTo.Console()
    .CreateLogger();
try
{
    Log.Information("Starting web application");
    var builder = WebApplication.CreateBuilder(args);
    builder.Host.UseSerilog(); // <-- Add this line
    var app = builder.Build();
    app.MapGet("/", () => "Hello World!");
    app.Run();
}
catch (Exception ex)
{
    Log.Fatal(ex, "Application terminated unexpectedly");
}
finally
{
    Log.CloseAndFlush();
}
 //Serilog.Sinks.Http
 //Serilog.Sinks.Seq
 //Log.Logger = new LoggerConfiguration()
 //            .MinimumLevel.Verbose()
 //            .Enrich.WithProperty("ApplicationContext", Program.AppName)
 //            .Enrich.FromLogContext()
 //            .WriteTo.Console()
 //            .WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
 //            .WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl)
 //            .ReadFrom.Configuration(configuration)
 //            .CreateLogger();
使用的的话直接注入ILogger就可以使用了
参考文档:
官方文档:
控制台:https://github.com/serilog/serilog/wiki/Getting-Started
web:https://github.com/serilog/serilog-aspnetcore#serilogaspnetcore---
配置:Configuration Basics · serilog/serilog Wiki · GitHub
https://docs.meowv.com/stack/dotnetcore/serilog-in-dotnet.html
https://maomi.whuanle.cn/3.2.serilog.html
https://github.com/serilog/serilog-aspnetcore
https://www.cnblogs.com/ireadme/p/14509704.html
四、自定义日志提供程序
实现自定义日志提供程序主要需要实现两个接口
1、ILogger 支持高性能结构化日志记录,输出日志的地方,其中log方法是Logger对日志消息的写入实现
2、ILoggerProvider
日志记录器提供程序,ILoggerProvider 的实现将通过其 ILoggerProvider.CreateLogger 方法创建 ILogger
需安装以下Nuget包
  <PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
  <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
  <PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="8.0.0" />
下面是官方的示例:
有很多日志记录提供程序可用于常见日志记录需求。 如果某个可用的提供程序不满足你的应用程序需要,则你可能需要实现自定义的 ILoggerProvider。 在本文中,你将学习如何实现可用于在控制台中为日志着色的自定义日志记录提供程序。
Docs Github 存储库中提供了自定义日志记录提供程序示例源代码。 有关详细信息,请参阅 GitHub:.NET Docs - 控制台自定义日志记录。
示例自定义记录器配置
此示例会使用以下配置类型为每个日志级别和事件 ID 创建不同的颜色控制台条目:
using Microsoft.Extensions.Logging;
public sealed class ColorConsoleLoggerConfiguration
{
    public int EventId { get; set; }
    public Dictionary<LogLevel, ConsoleColor> LogLevelToColorMap { get; set; } = new()
    {
        [LogLevel.Information] = ConsoleColor.Green
    };
}
前面的代码将默认级别设置为 Information,将颜色设置为 Green,而且 EventId 隐式设置为 0。
创建自定义记录器
ILogger 实现类别名称通常是日志记录源。 例如,创建记录器的类型:
C#
using Microsoft.Extensions.Logging;
public sealed class ColorConsoleLogger(
    string name,
    Func<ColorConsoleLoggerConfiguration> getCurrentConfig) : ILogger
{
    public IDisposable? BeginScope<TState>(TState state) where TState : notnull => default!;
    public bool IsEnabled(LogLevel logLevel) =>
        getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel);
    public void Log<TState>(
        LogLevel logLevel,
        EventId eventId,
        TState state,
        Exception? exception,
        Func<TState, Exception?, string> formatter)
    {
        if (!IsEnabled(logLevel))
        {
            return;
        }
        ColorConsoleLoggerConfiguration config = getCurrentConfig();
        if (config.EventId == 0 || config.EventId == eventId.Id)
        {
            ConsoleColor originalColor = Console.ForegroundColor;
            Console.ForegroundColor = config.LogLevelToColorMap[logLevel];
            Console.WriteLine($"[{eventId.Id,2}: {logLevel,-12}]");
            Console.ForegroundColor = originalColor;
            Console.Write($"     {name} - ");
            Console.ForegroundColor = config.LogLevelToColorMap[logLevel];
            Console.Write($"{formatter(state, exception)}");
            Console.ForegroundColor = originalColor;
            Console.WriteLine();
        }
    }
}
前面的代码:
- 为每个类别名称创建一个记录器实例。
- 在 IsEnabled中检查_getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel),因此每个logLevel都有一个唯一的记录器。 在此实现中,每个日志级别都需要显式配置条目才能记录。
最好是在 ILogger.Log 实现中调用 ILogger.IsEnabled,因为 Log 可由任何使用者调用,并且不能保证之前已检查过。 方法 IsEnabled 在大多数实现中应非常快。
C#
TState state,
Exception? exception,
记录器使用 name 和 Func<ColorConsoleLoggerConfiguration> 进行实例化,这将返回当前配置 - 这会处理对通过 IOptionsMonitor.OnChange 回调监视的配置值的更新。
重要
ILogger.Log 实现检查是否设置了 config.EventId 值。 未设置 config.EventId 或与确切的 logEntry.EventId 匹配时,记录器会以颜色记录。
自定义记录器提供程序
ILoggerProvider 对象负责创建记录器实例。 不需要为每个类别创建一个记录器实例,但这对于某些记录器(例如 NLog 或 log4net)来说是需要的。 借助此策略可以为每个类别选择不同的日志记录输出目标,如以下示例中所示:
C#
using System.Collections.Concurrent;
using System.Runtime.Versioning;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
[UnsupportedOSPlatform("browser")]
[ProviderAlias("ColorConsole")]
public sealed class ColorConsoleLoggerProvider : ILoggerProvider
{
    private readonly IDisposable? _onChangeToken;
    private ColorConsoleLoggerConfiguration _currentConfig;
    private readonly ConcurrentDictionary<string, ColorConsoleLogger> _loggers =
        new(StringComparer.OrdinalIgnoreCase);
    public ColorConsoleLoggerProvider(
        IOptionsMonitor<ColorConsoleLoggerConfiguration> config)
    {
        _currentConfig = config.CurrentValue;
        _onChangeToken = config.OnChange(updatedConfig => _currentConfig = updatedConfig);
    }
    public ILogger CreateLogger(string categoryName) =>
        _loggers.GetOrAdd(categoryName, name => new ColorConsoleLogger(name, GetCurrentConfig));
    private ColorConsoleLoggerConfiguration GetCurrentConfig() => _currentConfig;
    public void Dispose()
    {
        _loggers.Clear();
        _onChangeToken?.Dispose();
    }
}
在前面的代码中,CreateLogger 会为每个类别名称创建一个 ColorConsoleLogger 实例并将其存储在 ConcurrentDictionary 中。 此外,还需要 IOptionsMonitor 接口才能更新对基础 ColorConsoleLoggerConfiguration 对象的更改。
若要控制 ColorConsoleLogger 的配置,请在其提供程序上定义别名:
C#
[UnsupportedOSPlatform("browser")]
[ProviderAlias("ColorConsole")]
public sealed class ColorConsoleLoggerProvider : ILoggerProvider
ColorConsoleLoggerProvider 类定义了两个类范围的属性:
- UnsupportedOSPlatformAttribute:"browser"中不支持ColorConsoleLogger类型。
- ProviderAliasAttribute:配置节可使用 "ColorConsole"键定义选项。
可通过任何有效的配置提供程序指定配置。 请考虑使用以下 appsettings.json 文件:
JSON
{
    "Logging": {
        "ColorConsole": {
            "LogLevelToColorMap": {
                "Information": "DarkGreen",
                "Warning": "Cyan",
                "Error": "Red"
            }
        }
    }
}
这会将日志级别配置为以下值:
- LogLevel.Information: ConsoleColor.DarkGreen
- LogLevel.Warning: ConsoleColor.Cyan
- LogLevel.Error: ConsoleColor.Red
Information 日志级别设置为 DarkGreen,这将覆盖在 ColorConsoleLoggerConfiguration 对象中设置的默认值。
自定义记录器的使用和注册
根据约定,在应用程序启动例程中注册服务以进行依赖项注入。 注册在 Program 类中进行,还可能委托给 Startup 类。 本示例将直接从 Program.cs 进行注册。
若要添加自定义日志记录提供程序和相应的记录器,请从 HostingHostBuilderExtensions.ConfigureLogging(IHostBuilder, Action) 使用 ILoggingBuilder 添加 ILoggerProvider:
C#
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddColorConsoleLogger(configuration =>
{
    // Replace warning value from appsettings.json of "Cyan"
    configuration.LogLevelToColorMap[LogLevel.Warning] = ConsoleColor.DarkCyan;
    // Replace warning value from appsettings.json of "Red"
    configuration.LogLevelToColorMap[LogLevel.Error] = ConsoleColor.DarkRed;
});
using IHost host = builder.Build();
var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogDebug(1, "Does this line get hit?");    // Not logged
logger.LogInformation(3, "Nothing to see here."); // Logs in ConsoleColor.DarkGreen
logger.LogWarning(5, "Warning... that was odd."); // Logs in ConsoleColor.DarkCyan
logger.LogError(7, "Oops, there was an error.");  // Logs in ConsoleColor.DarkRed
logger.LogTrace(5, "== 120.");                    // Not logged
await host.RunAsync();
ILoggingBuilder 创建一个或多个 ILogger 实例。 框架使用 ILogger 实例记录信息。
appsettings.json 文件中的配置会替代以下值:
按照约定,ILoggingBuilder 上的扩展方法用于注册自定义提供程序:
C#
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Configuration;
public static class ColorConsoleLoggerExtensions
{
    public static ILoggingBuilder AddColorConsoleLogger(
        this ILoggingBuilder builder)
    {
        builder.AddConfiguration();
        builder.Services.TryAddEnumerable(
            ServiceDescriptor.Singleton<ILoggerProvider, ColorConsoleLoggerProvider>());
        LoggerProviderOptions.RegisterProviderOptions
            <ColorConsoleLoggerConfiguration, ColorConsoleLoggerProvider>(builder.Services);
        return builder;
    }
    public static ILoggingBuilder AddColorConsoleLogger(
        this ILoggingBuilder builder,
        Action<ColorConsoleLoggerConfiguration> configure)
    {
        builder.AddColorConsoleLogger();
        builder.Services.Configure(configure);
        return builder;
    }
}
运行此简单应用程序将把颜色输出呈现到控制台窗口,如下图所示:

自定义日志功能参考文档:
https://learn.microsoft.com/zh-cn/dotnet/core/extensions/logging-providers
在 .NET 中实现自定义日志记录提供程序 - .NET | Microsoft Learn
使用SignalR推送服务器日志
https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/logging/?view=aspnetcore-8.0
https://maomi.whuanle.cn/3.1.design_log.html
https://www.cnblogs.com/jackyfei/p/16287326.html
https://www.cnblogs.com/chenyishi/p/18068309
Microsoft.Extensions 探索 / 日志 Logger - 知乎 (zhihu.com)
.Net Core Logging模块源码阅读 - 李正浩 - 博客园 (cnblogs.com)
.NET Core下的日志(2):日志模型详解 - Artech - 博客园 (cnblogs.com)
.NET 8使用日志功能以及自定义日志提供程序的更多相关文章
- .NET/ASP.NETMVC 大型站点架构设计—迁移Model元数据设置项(自定义元数据提供程序)
		阅读目录: 1.需求背景介绍(Model元数据设置项应该与View绑定而非ViewModel) 1.1.确定问题域范围(可以使用DSL管理问题域前提是锁定领域模型) 2.迁移ViewModel设置到外 ... 
- ASP.NET Core - 配置系统之自定义配置提供程序
		4. 自定义配置提供程序 在 .NET Core 配置系统中封装一个配置提供程序关键在于提供相应的 IconfigurationSource 实现和 IConfigurationProvider 接口 ... 
- 基于.NetCore3.1系列 —— 日志记录之自定义日志组件
		一.前言 回顾:日志记录之日志核心要素揭秘 在上一篇中,我们通过学习了解在.net core 中内置的日志记录中的几大核心要素,在日志工厂记录器(ILoggerFactory)中实现将日志记录提供器( ... 
- HAproxy增加日志记录功能和自定义日志输出内容、格式
		http://blog.51cto.com/eric1/1854574 一.增加haproxy日志记录功能 1.1 由于数据分析的需要,我们必须打开haproxy日志,记录相关信息. 在配置前,我 ... 
- .NET 反向代理 YARP 自定义配置提供程序(Configuration Providers)
		介绍 基本 Yarp 示例显示从 appsettings.json 加载的代理配置.相反,代理配置可以从您选择的源以编程方式加载.您可以通过提供几个实现 IProxyConfigProvider 和 ... 
- Spring AOP 实现写事件日志功能
		什么是AOP?AOP使用场景?AOP相关概念?Spring AOP组件?如何使用Spring AOP?等等这些问题请参考博文:Spring AOP 实现原理 下面重点介绍如何写事件日志功能,把日志保存 ... 
- ELK收集Nginx自定义日志格式输出
		1.ELK收集日志的有两种常用的方式: 1.1:不修改源日志格式,简单的说就是在logstash中转通过 grok方式进行过滤处理,将原始无规则的日志转换为规则日志(Logstash自定义日志格式) ... 
- (译)Windsor入门教程---第五部分 添加日志功能
		介绍 现在我们已经有了基础的框架了,是时候添加内容了,那么我们首先应该考虑的就是在应用程序中添加日志功能.我们会使用Windsor来配置,在这一部分,你将学习Windsor之外的其他功能. L ... 
- 涨姿势:Java 分业务、分级别实现自定义日志打印
		自定义日志级别 通常的日志框架都有以下几个级别,从低到高TRACE,DEBUG,INFO,WARN,ERROR,FATAL. 默认情况,假如我们定义日志打印级别INFO,它会把大于等于INFO级别的日 ... 
- SpringBoot日志功能
		三.SpringBoot日志功能 1.日志框架 市面上的日志框架: JUL.JCL.Jboss-logging.Logback.Log4j.Log4j.SLF4J... 日志门面(日志的抽象层) 日志 ... 
随机推荐
- protobuf简单示例
			user.proto syntax = "proto3"; package demo; option go_package = "./pb"; //指定go_o ... 
- 【Python OO其二】设计模式之工厂模式(举例说明)
			工厂模式 工厂模式中的"工厂"实际上就是把类看成制造某种模板的工具(工厂),由这个类生成的实例除了本身自有的属性外,还可以通过指定的方式产出具有不同属性的同一类实例 比如:有一个面 ... 
- 【Azure 环境】记录使用Notification Hub,安卓手机收不到Push通知时的错误,Error_Code 30602 or 30608
			问题描述 使用Azure Notification Hub + Baidu 推送遇见的两次报错为: 1. {"request_id":2921358089,"error_ ... 
- STM32SPIFLASH读写
			STM32SPIFLASH读写 1.1 SPI注意事项 SPI是同步通信,即通信双方每次信息交互必会带有一问一答,这代表在正常的单核MCU(例如STM32)中很难实现软件模拟的双向SPI通信(TFT屏 ... 
- 论文《Attention is all you need》阅读笔记
			Attention is all you need Transformer模型 Model Architecture Transformer结构上和传统的翻译模型相同,拥有encoder-decode ... 
- Java      instanceof  全小写 关键字使用
			1 package com.bytezreo.duotai2; 2 3 import java.sql.Date; 4 5 /** 6 * 7 * @Description 面向对象的特征三 ---- ... 
- 如何避免MYSQL主从延迟带来的读写问题?
			在MYSQL 部署架构选型上,许多公司都会用到主从读写分离的架构,如下是一个一主一从的架构,主库master负责写入,从库slave进行读取. 但是既然是读写分离,必然会面临这样一个问题,当在主库上进 ... 
- OPPO 后端面试凉经(附详细参考答案)
			这篇文章的问题来源于一个读者之前分享的 OPPO 后端凉经,我对比较典型的一些问题进行了分类并给出了详细的参考答案.希望能对正在参加面试的朋友们能够有点帮助! Java String 为什么是不可变的 ... 
- 光感红外接近传感器AP3426调试总结
			一 概念 AP3426是一个高度集成了红外,光感和接近角的传感器.该传感器凭借着高灵敏度广泛应用在可穿戴领域.笔者在一个产品上用了这个传感器.花了一些时间来调试和熟悉这个传感器,这里就做一个总结吧. ... 
- 性能优化:编译器优化选项 -O2/-O3 究竟有多强大?
			之前的"性能优化的一般策略及方法"一文中介绍了多种性能优化的方法.根据以往的项目经验,开启编译器优化选项可能是立竿见影.成本最低.效果最好的方式了. 这么说可能还不够直观,举个真实 ... 
