.NET Core -日志
.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如下图所示:
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>
添加完配置文件以后,我们还需要修改配置文件的属性,设置为始终复制,如下图所示:
通过上面的步骤,我们已经完成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控制器,然后查看是否有日志生成:
其他可参考:https://www.cnblogs.com/dotnet261010/p/13286218.html?utm_source=tuicool
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)