.NET Core 日志系统日志有: 调试日志,跟踪日志,诊断日志,事件日志; 为了整合第三方日志和.Net core 自身日志框架的整合 还有一个 统一日志编程模型的框架: ILogger 接口 ILoggerFactory,ILoggerProvider(日志提供程序不同渠道的)

1 调试日志

Debuger静态类,: Debugger.Log(0,null,"这是一条Debug消息!");

 Debug.WriteLine(""); 这个类型所有的方法都是通过条件编译的情况得 必须要在Debug模式下才有效

2 跟踪日志

使用得是观察者模式/发布订阅模式

public static class Sample02
    {
        public static void Run()
        {
            // 发布订阅模式,这里只是设置发布者                   
            var source = new TraceSource("Trace", SourceLevels.All);
            var eventTypes = (TraceEventType[])Enum.GetValues(typeof(TraceEventType));
            var eventId = 1;
            foreach (var traceEventType in eventTypes)
            {
                source.TraceEvent(traceEventType, eventId++,$"这是一条{traceEventType}消息");
            }

            Console.Read();
        }
    }
public static class Sample03
    {
        public static void Run()
        {
            //跟踪控制台的监听器
            var source = new TraceSource("Trace", SourceLevels.Warning);
            source.Listeners.Add(new ConsoleTraceListener());
            var eventTypes = (TraceEventType[])Enum.GetValues(typeof(TraceEventType));
            var eventId = 1;
            foreach (var traceEventType in eventTypes)
            {
                source.TraceEvent(traceEventType, eventId++,$"这是一条{traceEventType}消息");
            }

            Console.Read();
        }
    }
public static class Sample04
    {
        public static void Run()
        {      
            using var fileStream = File.OpenWrite("log.txt");
            var source = new TraceSource("Trace", SourceLevels.Warning);
            source.Listeners.Add(new ConsoleTraceListener());
            //文本内容的跟踪监听器
            source.Listeners.Add(new TextWriterTraceListener(fileStream));
            var eventTypes = (TraceEventType[])Enum.GetValues(typeof(TraceEventType));
            var eventId = 1;
            foreach (var traceEventType in eventTypes)
            {
                source.TraceEvent(traceEventType, eventId++,$"这是一条{traceEventType}消息");
                //强制把缓冲器的清除
                source.Flush();
            }
        }
    }
public static class Sample05
    {
        public static void Run()
        {
            const string filename = "log1.csv";
            File.AppendAllText(filename,$"SourceName,EventType,EventId,Message,N/A,ProcessId,N/A,ThreadId,DateTime,{Environment.NewLine}" );//格式是固定的 后面的是换行符

            using var fileStream = new FileStream(filename,FileMode.Append);
            //对跟踪的信息进行格式化,或者分割,csv的监听
            var listener = new DelimitedListTraceListener(fileStream)
            {
                Delimiter = ",",
                TraceOutputOptions = TraceOptions.DateTime | TraceOptions.ProcessId | TraceOptions.ThreadId
            };

            var source = new TraceSource("AppTrace", SourceLevels.All);
            source.Listeners.Add(new ConsoleTraceListener());
            source.Listeners.Add(listener);
    
            source.TraceEvent(TraceEventType.Information,1,$"这是一条{TraceEventType.Information}消息");
            source.Flush();


        }
    }

3 诊断日志:

可以使用包Microsoft.Extensions.DiagnosticAdapter

public static class Sample08
    {
        public class Observer<T> : IObserver<T>
        {
            private readonly Action<T> _onNext;

            public Observer(Action<T> onNext)
            {
                _onNext = onNext;
            }

            public void OnCompleted() { }

            public void OnError(Exception error) { }

            public void OnNext(T value)
            {
                _onNext(value);
            }
        }
        /// <summary>
        /// 自定义
        /// </summary>
        public class CustomSourceCollector
        {
            [DiagnosticName("Hello")]
            public void OnHello(int type, string msg)
            {
                Console.WriteLine($"Type:{type}");
                Console.WriteLine($"Msg:{msg}");
            }
        }

        public static void Run()
        {
            DiagnosticListener.AllListeners.Subscribe(new Observer<DiagnosticListener>(listener =>
            {
                if (listener.Name == "AppLog")
                {
                    listener.SubscribeWithAdapter(new CustomSourceCollector());
                }
            }));

            var source = new DiagnosticListener("AppLog");


            source.Write("Hello", new
            {
                Type = 1,
                Msg = "2020年5月11日"
            });


        }
    }

4 统一日志编程模型的框架 (重点)

public class Sample01
    {
        public static void Run()
        {
            var serviceProvider = new ServiceCollection()
                .AddLogging(builder => builder
                    .AddConsole()
                    .AddDebug())
                .BuildServiceProvider();

            //方法1
            var logger1 = serviceProvider.GetRequiredService<ILoggerFactory>()//工厂
                .CreateLogger("ConsoleApp2.Sample01");
            //方法2
            var logger = serviceProvider.GetRequiredService<ILogger<Sample01>>();
            // .CreateLogger("ConsoleApp2.Sample01");

            var leveles = (LogLevel[])Enum.GetValues(typeof(LogLevel));

            var eventId = 1;
            foreach (var level in leveles)
            {
                logger.Log(level, eventId++, $"这是一条{level}消息");
            }

            Console.Read();
        }
    }
public class Sample02
    {
        public static void Run()
        {
            var serviceProvider = new ServiceCollection()
                .AddLogging(builder =>
                {
                    //跟踪日志,发布
                    builder.AddTraceSource(
                            new SourceSwitch("Sample02", nameof(SourceLevels.All)),
                            new DefaultTraceListener {LogFileName = "trace.log"});
                    builder.AddConsole();
                    builder.SetMinimumLevel(LogLevel.Trace);//最低等级
                })
                .BuildServiceProvider();
            var logger = serviceProvider.GetRequiredService<ILogger<Sample02>>();

            var leveles = (LogLevel[])Enum.GetValues(typeof(LogLevel));
            var eventId = 1;
            foreach (var level in leveles)
            {
                logger.Log(level, eventId++,$"这是一条{level}消息");
            }

            Console.Read();
        }
    }
public class Sample03
    {
        public static void Run()
        {
            var serviceProvider = new ServiceCollection()
                .AddLogging(builder => builder
                     //过滤
                    .AddFilter((category, level) =>
                    {
                        return category switch
                        {
                            "LoggerA" => level >= LogLevel.Debug,
                            "LoggerB" => level >= LogLevel.Warning,
                            "LoggerC" => level >= LogLevel.None,
                            _ => level >= LogLevel.Information
                        };
                    })
                    .AddConsole()
                    .AddDebug())
                .BuildServiceProvider();

            var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
            var loggerA = loggerFactory.CreateLogger("LoggerA");
            var loggerB = loggerFactory.CreateLogger("LoggerB");
            var loggerC = loggerFactory.CreateLogger("LoggerC");

            var leveles = (LogLevel[])Enum.GetValues(typeof(LogLevel));

            var eventId = 1;
            foreach (var level in leveles)
            {
                eventId++;
                loggerA.Log(level, eventId,$"这是一条{level}消息");
                loggerB.Log(level, eventId,$"这是一条{level}消息");
                loggerC.Log(level, eventId,$"这是一条{level}消息");
            }

            Console.Read();
        }
    }
public class Sample04
    {
        public static void Run()
        {
            var serviceProvider = new ServiceCollection()
                .AddLogging(builder => builder
                      //过滤
                    .AddFilter((provider, category, level) =>
                    {
                        if (provider == typeof(ConsoleLoggerProvider).FullName)
                        {
                            return level >= LogLevel.Debug;
                        }

                        if (provider == typeof(DebugLoggerProvider).FullName)
                        {
                            return level >= LogLevel.Warning;
                        }

                        return level >= LogLevel.Information;
                    })
                    .AddConsole()
                    .AddDebug())
                .BuildServiceProvider();

            var logger = serviceProvider.GetRequiredService<ILogger<Sample04>>();

            var leveles = (LogLevel[])Enum.GetValues(typeof(LogLevel));

            var eventId = 1;
            foreach (var level in leveles)
            {
                logger.Log(level, eventId++,$"这是一条{level}消息");
            }

            Console.Read();
        }
    }
{
  "LogLevel": {
    "Default": "Error",
    "LoggerA": "Debug"
  },
  "Console": {
    "LogLevel": {
      "Default": "Information",
      "LoggerA": "Warning",
      "LoggerB": "Critical"
    } 
  } 
}
public class Sample05
    {
        public static void Run()
        {
            //通过配置文件夹配置
            var config = new ConfigurationBuilder()
                .AddJsonFile("log.json")
                .Build();

            var serviceProvider = new ServiceCollection()
                .AddLogging(builder => builder
                    .AddConfiguration(config)
                    .AddConsole()
                    .AddDebug())
                .BuildServiceProvider();

            var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
            var loggerA = loggerFactory.CreateLogger("LoggerA");
            var loggerB = loggerFactory.CreateLogger("LoggerB");
            var loggerC = loggerFactory.CreateLogger("LoggerC");

            var leveles = (LogLevel[])Enum.GetValues(typeof(LogLevel));

            var eventId = 1;
            foreach (var level in leveles)
            {
                eventId++;
                loggerA.Log(level, eventId, $"这是一条{level}消息");
                loggerB.Log(level, eventId, $"这是一条{level}消息");
                loggerC.Log(level, eventId, $"这是一条{level}消息");
            }

            Console.Read();
        }
    }
public class Sample06
    {
        public static void Run()
        {
            var serviceProvider = new ServiceCollection()
                .AddLogging(builder => builder
                    .SetMinimumLevel(LogLevel.Information)
                    .AddConsole())
                .AddSingleton<GodLog>()
                .BuildServiceProvider();

            var logger = serviceProvider.GetRequiredService<GodLog>();
            logger.Log("Hello");
            Console.Read();
        }

        public class GodLog
        {
            private const string Template = "[{LogTime}]来自{Id}-{Name}的记录:{Context}";
            private static Action<ILogger, DateTime, int ,string, string, Exception> _logAction;
            private readonly ILogger _logger;

            public GodLog(ILogger<Sample06> logger)
            {
                _logger = logger;
                
                _logAction = LoggerMessage.Define<DateTime, int, string, string>(LogLevel.Information, 1, Template);
            }

            public void Log(string context)
            {
                _logAction(_logger, DateTime.Now, 1, "God", context, null);
            }
        }

        
    }
public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.ConfigureLogging(builder =>
                        builder.AddConsole(options => options.IncludeScopes = true));//开启日志上下文

                    webBuilder.UseStartup<Startup>();
                });
    }
public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {

        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
        {
            //中间件
            app.Use(async (context, next) =>
            {
                using (logger.BeginScope($"Request Trans {Guid.NewGuid()}"))
                {
                    logger.Log(LogLevel.Information,$"Request Begin at {DateTime.Now}");
                    await next();
                    logger.Log(LogLevel.Information, $"Request End at {DateTime.Now}");
                }
            });

            app.Run(async context =>
            {
                await Task.Delay(1000);
                await context.Response.WriteAsync("Hello");
            });

        }
    }
public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {

        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
        {
            //带范围的
            var scopeFactory = LoggerMessage.DefineScope<Guid>("Request Trans {Guid}");
            var requestLog =  LoggerMessage.Define<string, DateTime>(LogLevel.Information, 0, "Request {state} at {DateTime.Now}");

            app.Use(async (context, next) =>
            {
                using (scopeFactory(logger, Guid.NewGuid()))
                {
                    requestLog(logger, "Begin", DateTime.Now, null);
                    await next();
                    requestLog(logger, "End", DateTime.Now, null);
                }
            });

            app.Run(async context =>
            {
                await Task.Delay(1000);
                await context.Response.WriteAsync("Hello");
            });

        }
    }
}

使用NLog 

包 :NLog  NLog.Web.AspNetCore

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using NLog.Web;

namespace NLogDemo
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                })
                // 配置使用NLog
                .UseNLog();
    }
}

右键添加新建项,然后选择Web配置文件,命名为nlog.config如下图所示:

net8 serilog日志 outputTemplate 添加traceid字段 .net core日志_ide

 

 

 nlog.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"
      throwConfigExceptions="true"
      internalLogLevel="info"
      internalLogFile="E:\log\internal-nlog.txt">
  <!--autoReload:修改后自动加载,可能会有延迟-->
  <!--throwConfigExceptions:NLog日志系统抛出异常-->
  <!--internalLogLevel:内部日志的级别-->
  <!--internalLogFile:内部日志保存路径,日志的内容大概就是NLog的版本信息,配置文件的地址等等-->
  <!--输出日志的配置,用于rules读取-->
  <targets>
    <!--write logs to file-->
    <!--将日志写入文件中,fileName可以指定日志生成的路径-->
    <target xsi:type="File" name="allfile" fileName="D:\Log\nlog-all-${shortdate}.log"
             layout="${longdate}|${logger}|${uppercase:${level}}|${message} ${exception}" />
     <!--同样是将文件写入日志中,写入的内容有所差别,差别在layout属性中体现。写入日志的数量有差别,差别在路由逻辑中体现-->
    <target xsi:type="File" name="ownFile-web" fileName="D:\Log\nlog-my-${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-->
    <!--以Microsoft打头的日志将进入此路由,由于此路由没有writeTo属性,所有会被忽略-->
    <!--且此路由设置了final,所以当此路由被匹配到时。不会再匹配此路由下面的路由。未匹配到此路由时才会继续匹配下一个路由-->
    <logger name="Microsoft.*" minlevel="Trace"  final="true" />
    <!--上方已经过滤了所有Microsoft.*的日志,所以此处的日志只会打印除Microsoft.*外的日志-->
    <logger name="*" minlevel="Trace" writeTo="ownFile-web" />
  </rules>
</nlog>

添加完配置文件以后,我们还需要修改配置文件的属性,设置为始终复制,如下图所示:

net8 serilog日志 outputTemplate 添加traceid字段 .net core日志_监听器_02

 

 通过上面的步骤,我们已经完成NLog的配置,接下来我们就可以在控制器中使用了,通过构造函数注入的方式实现注入。控制器代码如下:

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

namespace NLogDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class NLogTestController : ControllerBase
    {
        private readonly ILogger<NLogTestController> _logger;

        public NLogTestController(ILogger<NLogTestController> logger)
        {
            _logger = logger;
        }

        [HttpGet]
        public IActionResult Get()
        {
            _logger.LogError("这是错误信息");
            _logger.LogDebug("这是调试信息");
            _logger.LogInformation("这是提示信息");

            return Ok();
        }
    }
}

运行程序,访问nlogtest控制器,然后查看是否有日志生成:

net8 serilog日志 outputTemplate 添加traceid字段 .net core日志_ide_03