一、简介#

日志组件,作为程序员使用频率最高的组件,给程序员开发调试程序提供了必要的信息。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. 很带劲,Android9.0可以在i.MX8开发板上这样跑

    米尔MYD-JX8MX开发板移植了Android9.0操作系统,现阶段最高版本的Android9.0操作系统将给您的产品在安全与稳定性方面带来更大的提升.可惜了,这里不能上传视频在i.MX8开发板跑A ...

  2. 史上最全的整合第三方登录的工具JustAuth

    JustAuth,如你所见,它仅仅是一个第三方授权登录的工具类库,它可以让我们脱离繁琐的第三方登录SDK,让登录变得So easy! 参考图例 授权gitee 授权github 授权weibo 授权钉 ...

  3. TensorFlow NMT的数据处理过程

    在tensorflow/nmt项目中,训练数据和推断数据的输入使用了新的Dataset API,应该是tensorflow 1.2之后引入的API,方便数据的操作.如果你还在使用老的Queue和Coo ...

  4. linux服务器问题排查:w命令卡住

    基本情况 系统: ubuntu16.04 症状: who命令可以用,w命令用不了 sudo iotop命令会卡住,黑屏 nvidia-smi命令和nvl命令都用不了,卡住 排查步骤 strace ps ...

  5. ZYNQ7000性能分析

    提到自动驾驶,机器人视觉,高清摄像机,都要想到摄像头这个单元,先前本侠也讲过一些FPGA应用在高清摄像头和机器视觉中的深度摄像头以及双目摄像头等,FPGA在里面的作用主要是对采集的图像进行处理,对图像 ...

  6. Nodejs入门级

    应用不同模块分析 我们来分解一下这个应用,为了实现一个应用,我们需要实现哪些部分呢? 我们需要提供Web页面,因此需要一个HTTP服务器 对于不同的请求,根据请求的URL,我们的服务器需要给予不同的响 ...

  7. linux系统IO操作

    本文重点说明下面内容: 什么是标准IO,什么是文件IO? 什么是Direct IO? O_SYNC标识有什么意义? 各个层面的缓存如何同步? 还在page cache中的脏页可以读写吗? IO路径上的 ...

  8. windows下,tomcat设置为服务启动

    一.配置号tomcat 二.cmd命令符下进入tomcat/bin目录,输入:service.bat install 三.运行中输入services.msc 打开服务管理控制台,可以找到 Apache ...

  9. centos7搭建lnmp

    一.准备 1. 修改网络yum源 先将系统自带的yum配置文件重命名或删除,然后下载下面两个文件 阿里云:http://mirrors.aliyun.com/repo/Centos-7.repo ep ...

  10. Linux运维技术之详解任务计划(crontab命令)

    crontab命令 按照预先设置的时间周期(分钟.小时.天……)重复执行用户指定的命令操作,属于周期性计划任务 (1).先来看一下/etc/crontab文件的内容: [root@localhost ...