使用.NET 6开发TodoList应用(3)——引入第三方日志库
需求
在我们项目开发的过程中,使用.NET 6自带的日志系统有时是不能满足实际需求的,比如有的时候我们需要将日志输出到第三方平台上,最典型的应用就是在各种云平台上,为了集中管理日志和查询日志,通常会选择对应平台的日志SDK进行集成。比如微软Azure提供的Azure App Service Logging,基础的用法可以参考这篇文章:ASP.NET Core Logging with Azure App Service and Serilog。同时在这篇文章中也提到了使用Serilog提供的多种Sink,可以实现将日志写入不同云平台或者是非云平台的日志存储中去,这是我们这篇文章讲要研究的内容。
目标
我们将为TodoList添加一个方便替换和扩展的日志策略,简单来说就是在与具体第三方打交道的Infrastructure
项目中实际设置使用的日志服务,并在Api
项目中进行依赖注入,方便在整个应用程序中无具体日志配置感知地使用日志服务。
原理和思路
查阅Serilog的官方文档和一些示例后确定,我们要做的事情有三件:
- 引入
Serilog.AspNetCore
包(很多文章或者教程里都让你根据需要使用的Sink去继续引入类似Serilog.Sink.File
之类的包,但是实际上Serilog.AspNetCore
包的依赖项里已经包含了File
这个Sink,所以实际上没有必要再去添加一次); - 二是需要为
Serilog
的Logger
对象提供一个LoggerConfiguration
,可以以代码的方式进行配置,也可以通过加载.json
文件的方式进行配置,看自己的需求和对配置热更新的有没有独特的要求决定; - 在程序启动构造
WebApplicationBuilder
对象的时候声明UseSerilog()
; - 在需要使用日志的地方注入
ILogger<T>
对象即可,我们一般是在构造函数里进行注入,当然也可以选择其他两种注入方式。
好了,了解了原理,接下来一步就是想一下我们要在哪里做这几件事。
在第二篇文章中,我提到了Clean Architecture
,里面有一条原则可以理解为:如果系统需要与外部(第三方)系统进行集成或交互,那么具体的集成工作应该放入Infrastructure
层进行处理,而程序的其他部分只对外部服务进行抽象的使用。好处是今后如果需要替换第三方系统,比如原本日志是写到本地文件里,后来有了上云和日志集中化处理的需求,需要将日志服务对接到诸如Azure App Service Logging
或者AWS CloudWatch
,那么我们只需要去修改(扩展)Infrastructure
中进行日志具体配置的逻辑就可以了。虽然日志服务本身相对比较简单,还不能很好地体现这个优点,我们姑且遵循这个原则,将配置工作放到Infrastructure
里面去。
实现
日志配置实现
我们在TodoList.Infrastructure
项目中新增一个文件夹,取名Log
,在其中新建文件ConfigureLogProvider.cs
,实现一个针对WebApplicationBuilder
的扩展方法,为了演示在这里配置的扩展性,我多用了一个appsettings.json
中的字段来控制配置过程,缺失的包需要安装一下。
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Serilog;
namespace TodoList.Infrastructure.Log;
public static class ConfigureLogProvider
{
public static void ConfigureLog(this WebApplicationBuilder builder)
{
if (builder.Configuration.GetValue<bool>("UseFileToLog"))
{
// 配置同时输出到控制台和文件,并且指定文件名和文件转储方式(形如log-20211219.txt格式),转储文件保留的天数为15天,以及日志格式
// 配置Enrich.FromLogContext()的目的是为了从日志上下文中获取一些关键信息诸如用户ID或请求ID,我们的应用中暂时不使用这些。
Serilog.Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.File(
"logs/log-.txt",
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 15)
.CreateLogger();
}
else
{
// 仅配置控制台日志
Serilog.Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.WriteTo.Console()
.CreateLogger();
}
// 使用Serilog作为日志框架,注意这里和.NET 5及之前的版本写法是不太一样的。
builder.Host.UseSerilog();
}
}
主程序配置
在TodoList.Api
项目的Main.cs
中,使用该扩展方法:
using TodoList.Infrastructure.Log;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// 配置日志
builder.ConfigureLog();
builder.Services.AddControllers();
// ... 省略以下
并向appsettings.Development.json
文件中添加用于测试的配置项:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"UseFileToLog": true
}
注入使用
嗯……我把第二篇文章结束时删除的示例WeatherForecastController.cs
和WeatherForecast.cs
又加回来了。Controller中已经注入了ILogger<WeatherForecastController>
,我们就在示例的接口里试一下:
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
// 记录日志
_logger.LogInformation($"maybe this log is provided by Serilog...");
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
好了,到此为止我们就可以验证一下了。
验证
运行TodoList.Api
项目,和第二篇文章一样,我们使用Hoppscotch
测试示例接口,观察控制台和日志文件的输出内容和格式:
- 控制台输出
- 文件输出
总结
在这篇文章中,我向大家展示了如何在.NET 6 Web API
项目中添加第三方日志服务框架,下一篇文章将会引入数据存储服务。
参考资料
- Serilog
- ASP.NET Core Logging with Azure App Service and Serilog
- Integrate logging in a asp.net core application using Serilog and Seq
系列导航
- 使用.NET 6开发TodoList应用(1)——系列背景
- 使用.NET 6开发TodoList应用(2)——项目结构搭建
- 使用.NET 6开发TodoList应用(3)——引入第三方日志
- 使用.NET 6开发TodoList应用(4)——引入数据存储
- 使用.NET 6开发TodoList应用(5.0)——领域实体创建和配置
- 使用.NET 6开发TodoList应用(5.1)——实现CQRS模式
- 使用.NET 6开发TodoList应用(5.2)——实现AutoMapper
- 使用.NET 6开发TodoList应用(6)——实现POST请求
- 使用.NET 6开发TodoList应用(7)——实现GET请求
- 使用.NET 6开发TodoList应用(8)——实现全局异常处理
- 使用.NET 6开发TodoList应用(9)——实现PUT请求
- 使用.NET 6开发TodoList应用(10)——实现PATCH请求
- 使用.NET 6开发TodoList应用(11)——HTTP请求幂等性的考虑
- 使用.NET 6开发TodoList应用(12)——实现接口请求验证
- 使用.NET 6开发TodoList应用(13)——实现ActionFilter
- 使用.NET 6开发TodoList应用(14)——实现查询分页
- 使用.NET 6开发TodoList应用(15)——实现查询过滤
- 使用.NET 6开发TodoList应用(16)——实现查询搜索
- 使用.NET 6开发TodoList应用(17)——实现查询排序
- 使用.NET 6开发TodoList应用(18)——实现数据塑形
- 使用.NET 6开发TodoList应用(19)——实现HATEAOS支持
- 使用.NET 6开发TodoList应用(20)——处理OPTION和HEAD请求
- 使用.NET 6开发TodoList应用(21)——实现Root Document
- 使用.NET 6开发TodoList应用(22)——实现API版本控制
- 使用.NET 6开发TodoList应用(23)——实现缓存
- 使用.NET 6开发TodoList应用(24)——实现请求限流和阈值控制
- 使用.NET 6开发TodoList应用(25)——实现基于JWT的Identity功能
- 使用.NET 6开发TodoList应用(26)——实现RefreshToken
- 使用.NET 6开发TodoList应用(27)——实现Configuration和Option的强类型绑定
- 使用.NET 6开发TodoList应用(28)——实现API的Swagger文档化
- 使用.NET 6开发TodoList应用(29)——实现应用程序健康检查
- 使用.NET 6开发TodoList应用(30)——实现本地化功能
- 使用.NET 6开发TodoList应用(31)——实现Docker打包和部署
- 使用.NET 6开发TodoList应用(32)——实现基于Github Actions和ACI的CI/CD
使用.NET 6开发TodoList应用(3)——引入第三方日志库的更多相关文章
- 使用.NET 6开发TodoList应用(4)——引入数据存储
需求 作为后端CRUD程序员(bushi,数据存储是开发后端服务一个非常重要的组件.对我们的TodoList项目来说,自然也需要配置数据存储.目前的需求很简单: 需要能持久化TodoList对象并对其 ...
- uni-app开发微信小程序引入UI组件库(Vant-weapp)步骤
uni-app开发微信小程序引入UI组件库(Vant-weapp)步骤 这里以vant-weapp为例 uni-app官方文档介绍引入组件的方法 1. 新建相关目录 根目录下创建 wxcomponen ...
- Android NDK编程,引入第三方.so库
android自带的编译工具NDK进行编译时(非单纯的调用第三方.so而是进行ndk编程),armeabi以及armeabi-v7a文件夹下的第三方so文件将会被删除,只会产生编译后的so文件,其他的 ...
- ionic3.0--angular4.0 引入第三方插件库的方法
ionic3.0 引入第三方插件 (swiper),方法很多,现详细说明下官方推荐(typings)做法. 1.全局安装Typings 1. npm install -g typings 2.搜索你 ...
- Vue引入第三方JavaScript库和如何创建自己的Vue插件
一 第三方JavaScript库 前言 .vue文件 中不解析 script标签引入js文件,只能用 import 引入 有两种用法: 1.import a from '../a' 2.import ...
- android开发学习——android studio 引入第三方库的总结
http://www.jianshu.com/p/0c592fff5d89 总结的很溜
- Vue 中如何引入第三方 JS 库
一绝对路径直接引入全局可用 二绝对路径直接引入配置后import 引入后再使用 三webpack中配置 aliasimport 引入后再使用 四webpack 中配置 plugins无需 import ...
- 转《vue引入第三方js库》
一.绝对路径直接引入,全局可用 二.绝对路径直接引入,配置后,import 引入后再使用 三.webpack中配置 alias,import 引入后再使用 四.webpack 中配置 plugins, ...
- Xcode6 引入第三方静态库project的方法
首先.介绍一下把在当前project中引入其它依赖project的方法: 第一:把其它项目project加入到现有project做法: 定义: FPro 现有project == 父project C ...
随机推荐
- Windows快捷键及cmd打开方式
Windows快捷键 win+e 打开我的电脑 win+r 打开运行 ctrl+z 撤销 shift+del 彻底删除 alt+F4 关闭窗口 ctrl+c 复制 ctrl+a 全选 ctrl+x 剪 ...
- 『学了就忘』Linux权限管理 — 55、文件特殊权限
目录 1.文件特殊权限说明 2.设置SetUID 3.检测SetUID的脚本 4.设置SetGID (1)针对文件的作用 (2)针对目录的作用 5.Sticky BIT 6.设定文件特殊权限 7.文件 ...
- [转载]CSP-J/S 第一轮知识点选讲
CSP-J/S 第一轮知识点选讲 转载自这里 感谢原博主的大力整理! 信息学史及基本知识 一.信息学及计算机史 计算机的顶级奖项:图灵奖.冯·诺依曼奖 图灵奖:由ACM(美国计算机协会)设立于1966 ...
- vector去重--unique
具体实现见中间源码 function template <algorithm> std::unique equality (1) template <class ForwardIte ...
- 巩固javaweb第十五天
巩固内容: 单选按钮: 在注册功能中,用户选择学历使用的是单选按钮,并且是多个单选按钮,每个选项对 应一个单选按钮,用户只能选择其中一个,这多个单选按钮的格式相同.如果用户要输入 的信息只有少数几种可 ...
- abundant
In ecology [生态学], local abundance is the relative representation of a species in a particular ecosys ...
- SparkStreaming消费Kafka,手动维护Offset到Mysql
目录 说明 整体逻辑 offset建表语句 代码实现 说明 当前处理只实现手动维护offset到mysql,只能保证数据不丢失,可能会重复 要想实现精准一次性,还需要将数据提交和offset提交维护在 ...
- 零基础学习java------day5------do....while循环、嵌套、方法(函数)
1 do...while循环 格式 初始化语句; do { 循环体语句; 控制条件语句; }while(判断条件语句); 流程: 先执行初始化语句 再执行循环体语句 再执行条件控制语句 再做条件的判 ...
- JS去除对象或数组中的空值('',null,undefined,[],{})
javascript去掉对象或数组中的'',null,undefined,[],{}.思路就是创建一个新的空对象,然后对传入的对象进行遍历,只把符合条件的属性返回,保留有效值,然后就相当于把空值去掉了 ...
- 【区间dp】- P1880 [NOI1995] 石子合并
记录一下第一道ac的区间dp 题目:P1880 [NOI1995] 石子合并 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 代码: #include <iostream> ...