ASP.NET Core Logging Solution
This package makes it a one-liner - loggerFactory.AddFile() - to configure top-quality file logging for ASP.NET Core apps.
- Text or JSON file output
- Files roll over on date; capped file size
- Request ids and event ids included with each message
- Writes are performed on a background thread
- Files are periodically flushed to disk (required for Azure App Service log collection)
- Fast, stable, battle-proven logging code courtesy of Serilog
You can get started quickly with this package, and later migrate to the full Serilog API if you need more sophisticated log file configuration.
Getting started
1. Add the NuGet package as a dependency of your project either with the package manager or directly to the CSPROJ file:
<PackageReference Include="Serilog.Extensions.Logging.File" Version="2.0.0" />
2. In your Program class, configure logging on the web host builder, and call AddFile() on the provided loggingBuilder.
Host.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, loggingBuilder) =>
{
// loggingBuilder.AddFile("Logs/Logs_{Date}.txt");
loggingBuilder.AddFile(hostingContext.Configuration.GetSection("Logging"));
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
3. Add a custom excetion filter as a global exception handler:
public class GlobalExceptionFilter : IExceptionFilter
{
private readonly ILogger<GlobalExceptionFilter> _logger;
public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger)
{
_logger = logger;
}
public void OnException(ExceptionContext context)
{
var loggingBuilder = new StringBuilder();
if (context.HttpContext.Request.GetDisplayUrl() != null)
loggingBuilder.AppendLine($"\tUrl: {context.HttpContext.Request.GetDisplayUrl()}");
loggingBuilder.AppendLine($"\tIp: {context.HttpContext.Connection.RemoteIpAddress}");
#if DEBUG
foreach (var key in context.HttpContext.Request.Headers.Keys)
{
loggingBuilder.AppendLine($"\t{key}: {context.HttpContext.Request.Headers[key]}");
}
#endif
loggingBuilder.AppendLine($"\tError Message: {context.Exception.Message}");
if (context.Exception.InnerException != null)
{
PrintInnerException(context.Exception.InnerException, loggingBuilder);
}
loggingBuilder.AppendLine($"\tError HelpLink: {context.Exception.HelpLink}");
loggingBuilder.AppendLine($"\tError StackTrace: {context.Exception.StackTrace}");
_logger.LogError(loggingBuilder.ToString());
}
public void PrintInnerException(Exception ex, StringBuilder loggingBuilder)
{
loggingBuilder.AppendLine($"\tError InnerMessage: {ex.Message}");
if (ex.InnerException != null)
{
PrintInnerException(ex.InnerException, loggingBuilder);
}
}
}
4. In your Startup class, configure the global exception handler on the ConfigureServices method, so we can catch all unhandled exceptions:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddControllersWithViews(options =>
{
options.Filters.Add<GlobalExceptionFilter>();
});
...
}
public IActionResult Privacy()
{
throw new Exception("Unhandled exception");
return View();
}
5. In your Startup class, add the log directory as static on the Configure method, so we can view the log directory:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseStaticFiles();
//add the log directory as static, so we can view the log directory
app.UseFileServer(new FileServerOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), @"Logs")),
RequestPath = new PathString("/Log"),
EnableDirectoryBrowsing = true
});
app.UseRouting();
...
}
Done! The framework will inject ILogger instances into controllers and other classes:
class HomeController : Controller
{
readonly ILogger<HomeController> _log;
public HomeController(ILogger<HomeController> log)
{
_log = log;
}
public IActionResult Index()
{
_logger.LogInformation("Hello, world!");
_logger.LogError(new Exception("Custom exception"), "Custom exception");
}
}
The events will appear in the log file:
2016-10-18T11:14:11.0881912+10:00 0HKVMUG8EMJO9 [INF] Hello, world! (f83bcf75)
File format
By default, the file will be written in plain text. The fields in the log file are:
| Field | Description | Format | Example |
|---|---|---|---|
| Timestamp | The time the event occurred. | ISO-8601 with offset | 2016-10-18T11:14:11.0881912+10:00 |
| Request id | Uniquely identifies all messages raised during a single web request. | Alphanumeric | 0HKVMUG8EMJO9 |
| Level | The log level assigned to the event. | Three-character code in brackets | [INF] |
| Message | The log message associated with the event. | Free text | Hello, world! |
| Event id | Identifies messages generated from the same format string/message template. | 32-bit hexadecimal, in parentheses | (f83bcf75) |
| Exception | Exception associated with the event. | Exception.ToString() format (not shown) |
System.DivideByZeroException: Attempt to divide by zero\r\n\ at... |
To record events in newline-separated JSON instead, specify isJson: true when configuring the logger:
loggingBuilder.AddFile("Logs/myapp-{Date}.txt", isJson: true);
This will produce a log file with lines like:
{"@t":"2016-06-07T03:44:57.8532799Z","@m":"Hello, world!","@i":"f83bcf75","RequestId":"0HKVMUG8EMJO9"}
The JSON document includes all properties associated with the event, not just those present in the message. This makes JSON formatted logs a better choice for offline analysis in many cases.
Rolling
The filename provided to AddFile() should include the {Date} placeholder, which will be replaced with the date of the events contained in the file. Filenames use the yyyyMMdd date format so that files can be ordered using a lexicographic sort:
log-20160631.txt
log-20160701.txt
log-20160702.txt
To prevent outages due to disk space exhaustion, each file is capped to 1 GB in size. If the file size is exceeded, events will be dropped until the next roll point.
Message templates and event ids
The provider supports the templated log messages used by Microsoft.Extensions.Logging. By writing events with format strings or message templates, the provider can infer which messages came from the same logging statement.
This means that although the text of two messages may be different, their event id fields will match, as shown by the two "view" logging statements below:
2016-10-18T11:14:26.2544709+10:00 0HKVMUG8EMJO9 [INF] Running view at "/Views/Home/About.cshtml". (9707eebe)
2016-10-18T11:14:11.0881912+10:00 0HKVMUG8EMJO9 [INF] Hello, world! (f83bcf75)
2016-10-18T11:14:26.2544709+10:00 0HKVMUG8EMJO9 [INF] Running view at "/Views/Home/Index.cshtml". (9707eebe)
Each log message describing view rendering is tagged with (9707eebe), while the "hello" log message is given (f83bcf75). This makes it easy to search the log for messages describing the same kind of event.
Additional configuration
The AddFile() method exposes some basic options for controlling the connection and log volume.
| Parameter | Description | Example value |
|---|---|---|
pathFormat |
Filename to write. The filename may include {Date} to specify how the date portion of the filename is calculated. May include environment variables. |
Logs/log-{Date}.txt |
minimumLevel |
The level below which events will be suppressed (the default is LogLevel.Information). |
LogLevel.Debug |
levelOverrides |
A dictionary mapping logger name prefixes to minimum logging levels. | |
isJson |
If true, the log file will be written in JSON format. | true |
fileSizeLimitBytes |
The maximum size, in bytes, to which any single log file will be allowed to grow. For unrestricted growth, passnull. The default is 1 GiB. |
1024 * 1024 * 1024 |
retainedFileCountLimit |
The maximum number of log files that will be retained, including the current log file. For unlimited retention, pass null. The default is 31. |
31 |
outputTemplate |
The template used for formatting plain text log output. The default is {Timestamp:o} {RequestId,13} [{Level:u3}] {Message} ({EventId:x8}){NewLine}{Exception} |
{Timestamp:o} {RequestId,13} [{Level:u3}] {Message} {Properties:j} ({EventId:x8}){NewLine}{Exception} |
appsettings.json configuration
The file path and other settings can be read from JSON configuration if desired.
In appsettings.json add a "Logging" property:
{
"Logging": {
"PathFormat": "Logs/log-{Date}.txt",
"LogLevel": {
"Default": "Debug",
"Microsoft": "Information"
}
}
}
And then pass the configuration section to the AddFile() method:
loggingBuilder.AddFile(Configuration.GetSection("Logging"));
In addition to the properties shown above, the "Logging" configuration supports:
| Property | Description | Example |
|---|---|---|
Json |
If true, the log file will be written in JSON format. |
true |
FileSizeLimitBytes |
The maximum size, in bytes, to which any single log file will be allowed to grow. For unrestricted growth, passnull. The default is 1 GiB. |
1024 * 1024 * 1024 |
RetainedFileCountLimit |
The maximum number of log files that will be retained, including the current log file. For unlimited retention, pass null. The default is 31. |
31 |
OutputTemplate |
The template used for formatting plain text log output. The default is {Timestamp:o} {RequestId,13} [{Level:u3}] {Message} ({EventId:x8}){NewLine}{Exception} |
{Timestamp:o} {RequestId,13} [{Level:u3}] {Message} {Properties:j} ({EventId:x8}){NewLine}{Exception} |
Using the full Serilog API
This package is opinionated, providing the most common/recommended options supported by Serilog. For more sophisticated configuration, using Serilog directly is recommened. See the instructions in Serilog.AspNetCore to get started.
The following packages are used to provide AddFile():
- Serilog - the core logging pipeline
- Serilog.Sinks.RollingFile - rolling file output
- Serilog.Formatting.Compact - JSON event formatting
- Serilog.Extensions.Logging - ASP.NET Core integration
- Serilog.Sinks.Async - async wrapper to perform log writes on a background thread
ASP.NET Core Logging Solution的更多相关文章
- ASP.NET Core Logging in Elasticsearch with Kibana
在微服务化盛行的今天,日志的收集.分析越来越重要.ASP.NET Core 提供了一个统一的,轻量级的Logining系统,并可以很方便的与第三方日志框架集成.我们也可以根据不同的场景进行扩展,因为A ...
- Asp.net core logging 日志
1 基本概念 Dotnet core 一个重要的特征是 Dependency injection ,中文一般是依赖注入,可以简单理解为一个集合,在应用程序启动时,定义各种具体的实现类型并将其放到集合中 ...
- ASP.NET Core 源码学习之 Logging[1]:Introduction
在ASP.NET 4.X中,我们通常使用 log4net, NLog 等来记录日志,但是当我们引用的一些第三方类库使用不同的日志框架时,就比较混乱了.而在 ASP.Net Core 中内置了日志系统, ...
- ASP.NET Core 源码学习之 Logging[3]:Logger
上一章,我们介绍了日志的配置,在熟悉了配置之后,自然是要了解一下在应用程序中如何使用,而本章则从最基本的使用开始,逐步去了解去源码. LoggerFactory 我们可以在构造函数中注入 ILogge ...
- ASP.NET Core 源码学习之 Logging[4]:FileProvider
前面几章介绍了 ASP.NET Core Logging 系统的配置和使用,而对于 Provider ,微软也提供了 Console, Debug, EventSource, TraceSource ...
- 【ASP.NET Core 】ASP.NET Core 源码学习之 Logging[1]:Introduction
在ASP.NET 4.X中,我们通常使用 log4net, NLog 等来记录日志,但是当我们引用的一些第三方类库使用不同的日志框架时,就比较混乱了.而在 ASP.Net Core 中内置了日志系统, ...
- 极简版ASP.NET Core学习路径及教程
绝承认这是一个七天速成教程,即使有这个效果,我也不愿意接受这个名字.嗯. 这个路径分为两块: 实践入门 理论延伸 有了ASP.NET以及C#的知识以及项目经验,我们几乎可以不再需要了解任何新的知识就开 ...
- [转]Using NLog for ASP.NET Core to write custom information to the database
本文转自:https://github.com/NLog/NLog/issues/1366 In the previous versions of NLog it was easily possibl ...
- [转]Setting the NLog database connection string in the ASP.NET Core appsettings.json
本文转自:https://damienbod.com/2016/09/22/setting-the-nlog-database-connection-string-in-the-asp-net-cor ...
随机推荐
- 使用Rancher在K8S上部署高性能PHP应用程序
介 绍 PHP是网络上最流行的编程语言之一,许多被广泛使用的内容管理系统都使用它开发,如WordPress和Drupal,并为现代服务器端框架(如Laravel和Symfony)提供核心代码. 尽管P ...
- Python and or not 优先级
not > and >or 1 or 5 and 4: -> 1 or 4-> 1 (1 or 5) and 4: ->1 and 4 ->4 x or y . x ...
- Python-字符串内容检测
str.isnumeric():检测字符串是否只由数字组成 str.isalpha():检测字符串是否只由字母组成 str.islower():检测字符串中所有的字母是否都为小写 str.isuppe ...
- Java中的堆和栈以及堆栈的区别
在正式内容开始之前要说明一点,我们经常所说的堆栈堆栈是堆和栈统称,堆是堆,栈是栈,合在一起统称堆栈: 1.栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.与C++不同,Jav ...
- python 并发专题(四):yield以及 yield from
一.yield python中yield的用法很像return,都是提供一个返回值,但是yield和return的最大区别在于,return一旦返回,则代码段执行结束,但是yield在返回值以后,会交 ...
- Halcon一维测量官方案例解析
下面的例子简要介绍了如何使用HALCON的一维测量工具.最长的部分是预处理和后处理:测量本身只包括两个操作符调用. 测量保险丝-fuse 预处理主要是测量线的生成.在示例程序中,这个步骤是通过将测量对 ...
- Guava集合--新集合类型
Guava引入了很多JDK没有的.但我们发现明显有用的新集合类型.这些新类型是为了和JDK集合框架共存,而没有往JDK集合抽象中硬塞其他概念.作为一般规则,Guava集合非常精准地遵循了JDK接口契约 ...
- mybatis自动生成代码插件mybatis-generator使用流程(亲测可用)
mybatis-generator是一款在使用mybatis框架时,自动生成model,dao和mapper的工具,很大程度上减少了业务开发人员的手动编码时间 坐着在idea上用maven构建spri ...
- 使用SQL语句进行数据复制
使用SQL语句对数据或者表进行复制,一般用于两张表结构相同的时候使用. SQL Server中,如果目标表存在: insert into 目标表 select * from 原表; SQL Serve ...
- [日常摘要] -- zookeeper篇
概览 设计目标 是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用 简介 是一个典型的分布式数据一致性解决方案,分布式应用程序可以基于Z ...