一、简介#

日志组件,作为程序员使用频率最高的组件,给程序员开发调试程序提供了必要的信息。ASP.NET Core中内置了一个通用日志接口ILogger,并实现了多种内置的日志提供器,例如

  • Console

  • Debug

  • EventSource

  • EventLog

  • TraceSource

  • Azure App Service

除了内置的日志提供器,ASP.NET Core还支持了多种第三方日志工具,例如

开发人员在ASP.Net Core中可以自由指定日志提供器,并将日志发送到指定的位置。
本篇博文中,我们将由浅入深的介绍ASP.Net Core中通用日志接口,最后我们将实现一些自定义的日志提供器(Log Provider)。

二、使用系统提供的内置日志提供器#

(一)、日志级别(Log Level)#

ASP.NET Core中提供了6种日志级别,分别是Trace, Debug, Information, Warning, Error, Critical。以下是他们的具体使用场景

日志级别

常用场景

Trace

记录一些对程序员调试问题有帮助的信息,

其中可能包含一些敏感信息, 所以应该避免在

生产环境中启用Trace日志

Debug

记录一些在开发和调试阶段有用的短时变

量(Short-term usefulness), 所以除非为了临时排除生产环境的

故障,开发人员应该尽量避免在生产环境中启用Debug日志

Information

记录应用程序的一些流程, 例如,记录当前api请求的url

Warning

记录应用程序中发生的不正常或者未预期的事件信息。

这些信息中可能包含错误消息或者错误产生的条件, 例如, 文件未找到

Error

记录应用程序中某个操作产生的错误和异常信息。

Critical

记录一些需要立刻修复的问题。例如数据丢失,磁盘空间不足。

(二)、如何创建日志#

为了创建一个日志,我们首先需要通过依赖注入获取一个实现ILogger<日志类别>的泛型接口对象。

已以下代码为例, 在ValuesController的构造函数中,我们注入了一个ILogger的日志记录器

    [Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly ILogger<ValuesController> _logger = null; public ValuesController(ILogger<ValuesController> logger)
{
_logger = logger;
} // GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
_logger.LogInformation("[Test Log]Getting items.");
return new string[] { "value1", "value2" };
}
}

然后我们使用ILogger接口提供的LogInformation方法添加了一个Information类型日志"[Test Log]Getting items"。

注:ILogger为了提供了6个可用的输出日志方法,分别对应了6个不同的日志级别

  • LogTrace

  • LogDebug

  • LogInformation

  • LogWarning

  • LogError

  • LogCritical!

下面我们使用Kestral服务器启动项目

项目产生的日志如下,我们手动输出的日志出现在控制台中。

(三)、日志配置

可能针对以上的代码,有些同学可能有疑问,我们没有在Startup.cs中注入任何日志提供器,但是日志却正常产生了。这是由于Program.cs中默认使用WebHost.CreateDefaultBuilder方法添加了2个日志提供器。

(四)、默认日志提供器

当创建一个新的ASP.NET Core WebApi项目,我们通常在Program.cs中看到以下代码。

 public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}

下面我们看一下WebHost.CreateDefaultBuilder的源代码

    public static IWebHostBuilder CreateDefaultBuilder(string[] args)
{
var builder = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment; config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); if (env.IsDevelopment())
{
var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
if (appAssembly != null)
{
config.AddUserSecrets(appAssembly, optional: true);
}
} config.AddEnvironmentVariables(); if (args != null)
{
config.AddCommandLine(args);
}
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.UseConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
})
.UseIISIntegration()
.UseDefaultServiceProvider((context, options) =>
{
options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
})
.ConfigureServices(services =>
{
services.AddTransient<IConfigureOptions<KestrelServerOptions>, KestrelServerOptionsSetup>();
}); return builder;
}

你会发现代码中通过logging.AddConsolelogging.AddDebug默认配置了Console和Debug类型的日志提供器,这也就是为什么我们没有注入任何日志提供器,日志却能正常产生了。

手动添加日志提供器#

看了以上代码后,你应该可以也清楚了如何自己添加其他内置的日志提供器。我们只需要在Program.cs中使用ConfigureLogging方法就可以配置我们需要的日志提供器了。

例:

    public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConsole();
logging.AddDebug();
logging.AddEventSourceLogger();
})
.UseStartup<Startup>();
}

除了在Program.cs添加日志提供器之外,我们还可以在Startup.cs中添加日志提供器。
在Startup.cs中,我们可以为Configure方法添加第三个参数ILoggerFactory loggerFactory, 并使用该参数添加日志提供器。

例:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} loggerFactory.AddConsole();
loggerFactory.AddDebug(); app.UseMvc();
}

(五)、配置文件及日志级别过滤

ASP.NET Core默认会从appSetting.json中的Logging属性读取日志的配置(当然你也可以从其他文件中读取配置),这里设置了不同的日志提供器产生的最低的日志级别,配置样例如下。

{
"Logging": {
"Debug": {
"LogLevel": {
"Default": "Information"
}
},
"Console": {
"LogLevel": {
"Microsoft.AspNetCore.Mvc.Razor.Internal": "Warning",
"Microsoft.AspNetCore.Mvc.Razor.Razor": "Debug",
"Microsoft.AspNetCore.Mvc.Razor": "Error",
"Default": "Trace"
}
},
"LogLevel": {
"Default": "Debug"
}
}
}

以上代码中的Debug表示Debug日志提供器, Console表示Console日志提供器, 最后一个LogLevel表示其他日志提供器通用。
Debug中的Default设置为Information, 即Debug中产生的日志最低级别是Information, 低于Information级别的日志不会输出。Console中的配置同理。

(六)、自定义日志组件

在学习了以上基础知识之后,我们应该对内置的日志提供器有了简单的认识。下面我们尝试自定义2个日志提供器。
在ASP.NET Core中,我们可以通过实现ILogger, ILoggerProvider2个接口来创建我们自己的日志提供器。

1、编写一个自定义样式的控制台日志组件

这里我们希望添加一个在控制台中输出的日志,但是和内置Console类型日志的区别是我们为不同的日志类型设置了不同的颜色。

首先我们创建一个新的Api项目ColoredConsoleLoggerSample

然后我们创建一个针对不同日志级别的字体颜色配置类ColoredConsoleLoggerConfiguration, 代码如下

    public class ColoredConsoleLoggerConfiguration
{
public LogLevel LogLevel { get; set; } = LogLevel.Warning;
public ConsoleColor Color { get; set; } = ConsoleColor.Yellow;
}

这个类中定义了针对不同日志类型设置不同的字体颜色。

然后我们创建一个日志类ColoredConsoleLogger, 它实现了ILogger接口,代码如下

    public class ColoredConsoleLogger : ILogger
{
private readonly string _name;
private readonly ColoredConsoleLoggerConfiguration _config; public ColoredConsoleLogger(string name, ColoredConsoleLoggerConfiguration config)
{
_name = name;
_config = config;
} public IDisposable BeginScope<TState>(TState state)
{
return null;
} public bool IsEnabled(LogLevel logLevel)
{
return logLevel == _config.LogLevel;
} public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (!IsEnabled(logLevel))
{
return;
} var color = Console.ForegroundColor;
Console.ForegroundColor = _config.Color;
Console.WriteLine($"{logLevel.ToString()} - {_name} - {formatter(state, exception)}");
Console.ForegroundColor = color;
}
}

代码解释

  • ColoredConsoleLogger仅针对一种日志级别

  • 只要当前产生的日志级别和ColoredConsoleLogger中定义的日志级别一样时,日志才会输出,这里我们是用IsEnable方法判断的

  • Log是ILogger接口中定义的方法,我们就是在这个方法中输出日志的

  • 这里我们在输入日志前记录下了当前控制台的原始字体颜色, 当输出日志完成之后,我们将字体颜色恢复成了原来的颜色

然后我们添加一个Logger提供器类ColoredConsoleLoggerProvider,代码如下

    public class ColoredConsoleLoggerProvider : ILoggerProvider
{
private readonly ColoredConsoleLoggerConfiguration _config; public ColoredConsoleLoggerProvider(ColoredConsoleLoggerConfiguration config)
{
_config = config;
} public ILogger CreateLogger(string categoryName)
{
return new ColoredConsoleLogger(categoryName, _config);
} public void Dispose()
{ }
}

代码解释

  • ColoredConsoleLoggerProvider仅针对一种日志级别

  • CreateLoggerILoggerProvider接口中定义的方法,它是用来返回一个日志生成器的

最后我们修改Startup.cs中的Configure方法, 代码如下

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} loggerFactory.AddProvider(new ColoredConsoleLoggerProvider(new ColoredConsoleLoggerConfiguration
{
LogLevel = LogLevel.Information,
Color = ConsoleColor.Blue
}));
loggerFactory.AddProvider(new ColoredConsoleLoggerProvider(new ColoredConsoleLoggerConfiguration
{
LogLevel = LogLevel.Debug,
Color = ConsoleColor.Gray
})); app.UseMvc();
}

这里我们添加了2个日志日志提供器,分别是针对Information级别日志和Debug级别日志的

最终效果

我们的日志根据我们预设的字体颜色正确的显示了出来

2、编写一个与SignalR集成的实时日志组件

下面我们再来自定义一个与SignalR集成的日志提供器,我们希望产生的日志通过一个SignalR服务器推送到一个网页中。

首先我们创建一个ASP.NET Core WebApi项目,命名为SignalrServer, 创建之后,我们右键项目属性,修改App Url为http://localhost:5000

然后我们创建一个LogHub类,它集成自Hub类,代码如下

    public class LogHub : Hub
{
public async Task WriteLog(Log log)
{
await Clients.All.SendAsync("showLog", log);
}
} public class Log
{
public LogLevel Level { get; set; } public string Content { get; set; }
}

代码解释

  • 这里我们创建了一个写日志的方法,它会把日志推送到所有连接到SignalR服务器的客户端,并调用客户端的showLog方法来展示推送的日志信息。

然后我们修改Startup.cs文件,代码如下

    public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddSignalR();
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(p => p.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials());
app.UseSignalR(routes =>
{
routes.MapHub<LogHub>("/logHub");
}); app.UseMvc();
}
}

代码解释

  • 我们通过service.AddSignalR注册了SignalR服务

  • 我们通过app.UserSignalR方法注册一个logHub

  • 这里我们启用了CORS, 因为需要提供跨域访问

然后我们创建一个另外一个ASP.NET Core WebApi项目, SignalRLoggerSample

项目创建成功之后,我们右键点击项目属性,并设置App URL为http://localhost:5001

然后我们使用Package Console Manager, 安装Microsoft.AspNetCore.SignalR.Client

PM> install-package Microsoft.AspNetCore.SignalR.Client

为了创建一个SignalR日志提供器, 我们分别创建一个SignalRLogger类和一个SignalRLoggerProvider类, 代码如下

SignalRLogger.cs

    public class SignalRLogger : ILogger
{
HubConnection connection; public SignalRLogger()
{
connection = new HubConnectionBuilder()
.WithUrl("http://localhost:5000/LogHub")
.Build();
} public IDisposable BeginScope<TState>(TState state)
{
return null;
} public bool IsEnabled(LogLevel logLevel)
{
return true;
} public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (!IsEnabled(logLevel))
{
return;
} connection.StartAsync().Wait();
var task = connection.SendAsync("writeLog", new { Level = logLevel, Content = formatter(state, exception) });
task.Wait();
}
}

SignalRLoggerProvider.cs

    public class SignalRLoggerProvider : ILoggerProvider
{
public SignalRLoggerProvider()
{
} public ILogger CreateLogger(string categoryName)
{
return new SignalRLogger();
} public void Dispose()
{ }
}

代码解释

  • 这里使用HubConnectionBuilder创建了一个SignalR连接

  • 连接启动成功之后,我们使用connection.SendAsync方法,将当前产生的日志信息发送到SignalR服务器

添加完成之后,我们在wwwroot文件夹中创建一个index.html, 在其中引入jquery和signalr的js库,并指定连接的signalR服务器是http://localhost:5000/logHub

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="jquery-1.10.2.min.js"></script>
<script src="signalr.min.js"></script>
</head>
<body>
<h1>Logs</h1>
<div id="content" style="border:1px solid #0094ff"> </div>
<script type="text/javascript">
var levels = [
{ level: , name: 'Trace', backgroundColor: 'gray' },
{ level: , name: 'Debug', backgroundColor: 'green' },
{ level: , name: 'Information', backgroundColor: 'blue' },
{ level: , name: 'Warning', backgroundColor: 'yellow' },
{ level: , name: 'Error', backgroundColor: 'orange' },
{ level: , name: 'Critical', backgroundColor: 'red' },
]; function getLevelName(level) {
return levels.find(function (o) {
return o.level == level;
}).name;
} function getLevelColor(level) {
return levels.find(function (o) {
return o.level == level;
}).backgroundColor;
} var connection = new signalR.HubConnectionBuilder().withUrl("http://localhost:5000/logHub").build(); connection.on("showLog", function (message) {
var div = "<div style='background-color:" + getLevelColor(message.level)+"'>[" + getLevelName(message.level) + "]:" + message.content + "</div>";
$("#content").append(div);
}); connection.start().catch(function (err) {
return console.error(err.toString());
});
</script>
</body>
</html>

然后我们修改ValuesController文件,代码如下

    [Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private ILogger<ValuesController> _logger = null; public ValuesController(ILogger<ValuesController> logger)
{
_logger = logger;
} // GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
_logger.LogTrace("User call the /api/values api");
_logger.LogDebug("User call the /api/values api");
_logger.LogInformation("User call the /api/values api");
_logger.LogWarning("User call the /api/values api");
_logger.LogError("User call the /api/values api");
_logger.LogCritical("User call the /api/values api");
return new string[] { "value1", "value2" };
}
}

代码解释

  • 我们创建了一个ValueController类的日志

  • 当用户请求/api/values时,我们输出了6个不同级别的日志

最后我们修改Startup.cs中的Configure方法,使用我们之前介绍的方法,将SignalRLoggerProvider添加到管道中

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles(); loggerFactory.AddProvider(new SignalRLoggerProvider()); app.UseMvc(); }

最终效果

最后我们按照顺序,先启动SignalRServer, 再启动SignalRLoggerSample, 效果如下

参考资料:https://www.cnblogs.com/lwqlun/p/9683482.html

Net core学习系列(八)——Net Core日志的更多相关文章

  1. 【.Net Core 学习系列】-- EF Core 实践(Code First)

    一.开发环境: VS2015, .Net Core 1.0.0-preview2-003156 二解决方案: 新建项目: File --> New --> Project -->   ...

  2. 【.Net Core 学习系列】-- EF Core实践(DB First)

    一.开发环境: VS2015, .Net Core 1.0.0-preview2-003156 二.准备数据: CREATE DATABASE [Blogging]; GO USE [Blogging ...

  3. EntityFramework Core 学习系列(一)Creating Model

    EntityFramework Core 学习系列(一)Creating Model Getting Started 使用Command Line 来添加 Package  dotnet add pa ...

  4. ASP.NET Core学习系列

    .NET Core ASP.NET Core ASP.NET Core学习之一 入门简介 ASP.NET Core学习之二 菜鸟踩坑 ASP.NET Core学习之三 NLog日志 ASP.NET C ...

  5. Net core学习系列(一)——Net Core介绍

    一.什么是Net Core .NET Core是适用于 windows.linux 和 macos 操作系统的免费.开源托管的计算机软件框架,是微软开发的第一个官方版本,具有跨平台 (Windows. ...

  6. Linux学习系列八:操作网口

    一些相对高性能的单片机会带以太网接口,网口在MCU里算是比较复杂的外设了,因为它涉及到网络协议栈,通常情况下网络协议栈会运行在一个RTOS中,所以对普通单片机开发者来说网口使用起来相对难度较大一些.在 ...

  7. Net core学习系列(四)——Net Core项目执行流程

    "跨平台"后的ASP.Net Core是如何接收并处理请求的呢? 它的运行和处理机制和之前有什么不同?本章从"宏观"到"微观"地看一下它的结 ...

  8. 【.Net Core 学习系列】-- 自定义错误页面在IE浏览器中不能正常显示

    测试场景: 1. 新建.Net Core Web项目 2. 选择模板: 3. 修改Error页面代码:(去掉母版页并修改页面显示信息) 4. 修改[ASPNETCORE_ENVIRONMENT],并抛 ...

  9. Net core学习系列(十)——Net Core配置

    一.前言 选项(Options)模式是对配置(Configuration)的功能的延伸.在12章(ASP.NET Core中的配置二)Configuration中有介绍过该功能(绑定到实体类.绑定至对 ...

随机推荐

  1. OpenGL 中的三维纹理操作

    #define _CRT_SECURE_NO_WARNINGS #include <gl/glut.h> #include <stdio.h> #include <std ...

  2. Android实现二维码扫描功能

    1.效果预览 先上图展示效果(模拟器没有摄像头,录出来效果不好,将就看) 2.集成步骤 1.拷贝本项目demo中的com.google.zxing5个包引入到自己的项目中. 2.拷贝本项目demo中的 ...

  3. I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2

    遇到了这个问题,意思是你的 CPU 支持AVX AVX2 (可以加速CPU计算),但你安装的 TensorFlow 版本不支持 解决:1. 如果是初学者 或者 没有太大计算速度的需求,在开头加上这两行 ...

  4. Win10下免安装版MySQL5.7的安装和配置

    1.MySQL5.7解压 2.新建配置文件my.ini放在D:\Free\mysql-5.7.26-winx64目录下 [mysql] # 设置mysql客户端默认字符集 default-charac ...

  5. linux内核--wait_event_interruptible_timeout()函数分析(转)

    原文:https://blog.csdn.net/wuyongpeng0912/article/details/45723657 网上有关于此函数的分析,但大都是同一篇文章转载来转载去,没有进一步的分 ...

  6. linux下apache和tomcat整合

    一 Apache与Tomcat比较联系 apache支持静态页,tomcat支持动态的,比如servlet等. 一般使用apache+tomcat的话,apache只是作为一个转发,对jsp的处理是由 ...

  7. Kubernetes YAML 文件全字段详解

    Kubernetes YAML 文件全字段详解 Deployment yaml 其中主要参数都在podTemplate 中,DaemonSet StatefulSet 中的pod部分一样. apiVe ...

  8. Linux学习23-Xftp上传文件显示乱码问题

    前言 当我们在windows新建一个文件,里面有中文时,使用Xftp上传到linux服务器上,会出现乱码问题. Windows的默认编码为GBK Linux的默认编码为UTF-8 Xftp上传文件乱码 ...

  9. git---如何解决The authenticity of host can't be established.

    新生成密钥的时候,git clone或者push的时候,可能会报这样的错误: ``` The authenticity of host 'gitee.com (xxx.xxx.xxx.xxx)' ca ...

  10. javascript---call,apply,bind

    对于这三个函数,估计大家都还是很模糊,具体是用来干什么?简而言之,是用来对象冒充的. 首先这三个方法是每个函数都包含的非继承的的方法. 我来搬砖一下,此文引用 http://www.cnblogs.c ...