.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控制器,然后查看是否有日志生成: