需求

在我们项目开发的过程中,使用.NET 6自带的日志系统有时是不能满足实际需求的,比如有的时候我们需要将日志输出到第三方平台上,最典型的应用就是在各种云平台上,为了集中管理日志和查询日志,通常会选择对应平台的日志SDK进行集成。比如微软Azure提供的Azure App Service Logging,基础的用法可以参考这篇文章:ASP.NET Core Logging with Azure App Service and Serilog。同时在这篇文章中也提到了使用Serilog提供的多种Sink,可以实现将日志写入不同云平台或者是非云平台的日志存储中去,这是我们这篇文章讲要研究的内容。

目标

我们将为TodoList添加一个方便替换和扩展的日志策略,简单来说就是在与具体第三方打交道的Infrastructure项目中实际设置使用的日志服务,并在Api项目中进行依赖注入,方便在整个应用程序中无具体日志配置感知地使用日志服务。

原理和思路

查阅Serilog的官方文档和一些示例后确定,我们要做的事情有三件:

  1. 引入Serilog.AspNetCore包(很多文章或者教程里都让你根据需要使用的Sink去继续引入类似Serilog.Sink.File之类的包,但是实际上Serilog.AspNetCore包的依赖项里已经包含了File这个Sink,所以实际上没有必要再去添加一次);
  2. 二是需要为SerilogLogger对象提供一个LoggerConfiguration,可以以代码的方式进行配置,也可以通过加载.json文件的方式进行配置,看自己的需求和对配置热更新的有没有独特的要求决定;
  3. 在程序启动构造WebApplicationBuilder对象的时候声明UseSerilog()
  4. 在需要使用日志的地方注入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.csWeatherForecast.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项目中添加第三方日志服务框架,下一篇文章将会引入数据存储服务。

参考资料

  1. Serilog
  2. ASP.NET Core Logging with Azure App Service and Serilog
  3. 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)——引入第三方日志库的更多相关文章

  1. 使用.NET 6开发TodoList应用(4)——引入数据存储

    需求 作为后端CRUD程序员(bushi,数据存储是开发后端服务一个非常重要的组件.对我们的TodoList项目来说,自然也需要配置数据存储.目前的需求很简单: 需要能持久化TodoList对象并对其 ...

  2. uni-app开发微信小程序引入UI组件库(Vant-weapp)步骤

    uni-app开发微信小程序引入UI组件库(Vant-weapp)步骤 这里以vant-weapp为例 uni-app官方文档介绍引入组件的方法 1. 新建相关目录 根目录下创建 wxcomponen ...

  3. Android NDK编程,引入第三方.so库

    android自带的编译工具NDK进行编译时(非单纯的调用第三方.so而是进行ndk编程),armeabi以及armeabi-v7a文件夹下的第三方so文件将会被删除,只会产生编译后的so文件,其他的 ...

  4. ionic3.0--angular4.0 引入第三方插件库的方法

    ionic3.0 引入第三方插件 (swiper),方法很多,现详细说明下官方推荐(typings)做法. 1.全局安装Typings 1. npm install -g typings  2.搜索你 ...

  5. Vue引入第三方JavaScript库和如何创建自己的Vue插件

    一 第三方JavaScript库 前言 .vue文件 中不解析 script标签引入js文件,只能用 import 引入 有两种用法: 1.import a from '../a' 2.import ...

  6. android开发学习——android studio 引入第三方库的总结

    http://www.jianshu.com/p/0c592fff5d89 总结的很溜

  7. Vue 中如何引入第三方 JS 库

    一绝对路径直接引入全局可用 二绝对路径直接引入配置后import 引入后再使用 三webpack中配置 aliasimport 引入后再使用 四webpack 中配置 plugins无需 import ...

  8. 转《vue引入第三方js库》

    一.绝对路径直接引入,全局可用 二.绝对路径直接引入,配置后,import 引入后再使用 三.webpack中配置 alias,import 引入后再使用 四.webpack 中配置 plugins, ...

  9. Xcode6 引入第三方静态库project的方法

    首先.介绍一下把在当前project中引入其它依赖project的方法: 第一:把其它项目project加入到现有project做法: 定义: FPro 现有project == 父project C ...

随机推荐

  1. [bzoj1005]明明的烦恼

    根据purfer序列的原理,每一个purfer序列都一一对应了一棵树,每一个点在purfer序列中出现的次数就是它的度数,那么直接用组合数去计算即可,注意要加高精度 1 #include<cst ...

  2. 如何隐藏shell脚本内容

    从事 Linux 开发的同学,经常需要编写 shell 脚本,有时脚本中会涉及到一些敏感内容,比如一些 IP 地址,用户名以及密码等,或者脚本中有一些关键的代码, 所有这些内容你都不想别人阅读或者修改 ...

  3. 【POJ3614 Sunscreen】【贪心】

    题面: 有c头牛,需要的亮度在[min_ci,max_ci]中,有n种药,每种m瓶,可以使亮度变为v 问最多能满足多少头牛 算法 我们自然考虑贪心,我们首先对每头牛的min进行排序,然后对于每种药,将 ...

  4. Linux内网时钟同步问题(ntp和chrony)

    我们都知道时钟同步可以使用外网服务器,在内网内不能连接外网的时候也需要时钟同步,那怎么进行呢? 选择内网的一台稳定的服务器作为时钟源,然后让其他机器都来同步这台机器即可. 注:其实ntp服务和chro ...

  5. 15.Pow(x, n)

    Pow(x, n) Total Accepted: 88351 Total Submissions: 317095 Difficulty: Medium Implement pow(x, n). 思路 ...

  6. lua5.4 beta中的to-be-closed变量的用法

    对应目前最新lua5.4 beta版本:2019-10-09发布 这个功能之前修改过两次语法,当前的语法不出意外将会是最终决定了,目前还没有最新的中文资料,所以我来这里发一下. 先介绍下这个功能: 被 ...

  7. Hadoop入门 完全分布式运行模式-准备

    目录 Hadoop运行环境 完全分布式运行模式(重点) scp secure copy 安全拷贝 1 hadoop102上的JDK文件推给103 2 hadoop103从102上拉取Hadoop文件 ...

  8. 如何使用 Kind 快速创建 K8s 集群?

    作者|段超 来源|尔达 Erda 公众号 ​ 导读:Erda 作为一站式云原生 PaaS 平台,现已面向广大开发者完成 70w+ 核心代码全部开源!在 Erda 开源的同时,我们计划编写<基于 ...

  9. Spark基础:(二)Spark RDD编程

    1.RDD基础 Spark中的RDD就是一个不可变的分布式对象集合.每个RDD都被分为多个分区,这些分区运行在分区的不同节点上. 用户可以通过两种方式创建RDD: (1)读取外部数据集====> ...

  10. Kafka 集群安装部署

    2.1 安装部署 2.1.1 集群规划 192.168.1.102 192.168.1.103 192.168.1.104 zookeeper zookeeper zookeeper kafka ka ...