如何从Serilog请求日志记录中排除健康检查终结点
这是在ASP.NET Core 3.X中使用Serilog.AspNetCore系列文章的第四篇文章:。
- 第1部分-使用Serilog RequestLogging减少日志详细程度
- 第2部分-使用Serilog记录所选的终结点属性
- 第3部分-使用Serilog.AspNetCore记录MVC属性
- 第4部分-从Serilog请求日志记录中排除健康检查端点(本文)
作者:依乐祝
在本系列的前几篇文章中,我描述了如何配置Serilog的RequestLogging中间件以向Serilog的请求日志摘要中添加附加属性,例如请求主机名或选定的端点名称。我还展示了如何使用过滤器将MVC或RazorPage特定的属性添加到摘要日志。
在本文中,我将展示如何过滤掉某个特定请求的摘要日志消息。当您有一个访问比较频繁的端点时,这非常有用,因为为每个请求都进行记录几乎没有什么价值。
健康检查访问较频繁
这篇文章的动机来自我们在Kubernetes中运行应用程序时看到的行为。Kubernetes使用两种类型的“健康检查”(或“探针”)来检查应用程序是否正常运行:liveness probes和readiness probes。您可以将探测配置为向应用程序发出HTTP请求,作为应用程序正常运行的指示器。
从Kubernetes 1.16版开始,存在第三种探针,即startup probe。
在ASP.NET Core 2.2+中提供的健康检查终结点非常适合这些探针。您可以设置一个简单,没有任何返回值的健康检查,该健康检查对每个请求返回200 OK
的响应,以使Kubernetes知道您的应用程序没有崩溃。
在ASP.NET Core 3.x中,可以使用终结点路由来配置健康检查。您必须在Startup.cs中的ConfigureServices
中通过调用AddHealthChecks()来添加必须的服务,并在Configure
中使用MapHealthChecks()
来添加健康检查终结点:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// ..other service configuration
services.AddHealthChecks(); // Add health check services
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// .. other middleware
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapHealthChecks("/health"); //Add health check endpoint
endpoints.MapControllers();
});
}
}
在上面的示例中,向/healthz
发送请求将调用健康检查终结点。由于我没有配置任何运行状况检查200
,因此只要应用程序正在运行,端点将始终返回响应:
在上面的示例中,向/healthz发送请求将调用运行状况检查终结点。由于我没有配置任何运行的健康检查,因此只要应用程序正在运行,端点将始终返回200响应:
这里存在的唯一的问题是Kubernetes将非常频繁的调用这个终结点。当然,确切的频率由您决定,但每10秒检查一次应该是很常见的。但是如果你想让Kubernetes可以快速重启有故障的Pod的话,您就需要一个相对较高的频率了。
这本身不是问题;Kestrel每秒可以处理数百万个请求,因此这不是性能问题。这里令人比较烦恼的问题是每个请求都会生成一定数量的日志。虽然它没有MVC基础架构的请求所示的那么多-每个请求10个日志,但是即使每个请求只有1个日志(就像我们从Serilog.AspNetCore获得的那样)都可能会令人不快。
这里的主要问题是成功进行健康检查请求的日志实际上并未告诉我们任何有用的信息。它们与任何业务活动都不相关,它们纯粹是基础设施。这里如果能够跳过这些请求的Serilog请求摘要日志会很好。在下一部分中,我将介绍我所想出的方法,该方法依赖于本系列前面几篇文章的内容,并在其基础上做出更改。
定制用于Serilog请求日志的日志级别
在上一篇文章中,我展示了如何在Serilog请求日志中包括所选终结点。我的方法是在注册Serilog中间件时为RequestLoggingOptions.EnrichDiagnosticContext
属性提供一个自定义函数
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ... Other middleware
app.UseSerilogRequestLogging(opts
// EnrichFromRequest helper function is shown in the previous post
=> opts.EnrichDiagnosticContext = LogHelper.EnrichFromRequest);
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapHealthChecks("/healthz"); //Add health check endpoint
endpoints.MapControllers();
});
}
RequestLoggingOptions
具有另一个属性,GetLevel
该属性的Func<>
被用于确定应用于给定请求日志的日志记录级别。默认情况下,它设置为以下功能:
public static class SerilogApplicationBuilderExtensions
{
static LogEventLevel DefaultGetLevel(HttpContext ctx, double _, Exception ex) =>
ex != null
? LogEventLevel.Error
: ctx.Response.StatusCode > 499
? LogEventLevel.Error
: LogEventLevel.Information;
}
此函数检查是否为请求引发了异常,或者响应代码是否为5xx
错误。如果是这样,它将创建一个Error
级别的摘要日志,否则将创建一个Information
级别日志。
假设您希望将摘要日志记录为Debug
而不是Information
。首先,您将创建一个具有以下所需逻辑的辅助函数,如下所示:
public static class LogHelper
{
public static LogEventLevel CustomGetLevel(HttpContext ctx, double _, Exception ex) =>
ex != null
? LogEventLevel.Error
: ctx.Response.StatusCode > 499
? LogEventLevel.Error
: LogEventLevel.Debug; //Debug instead of Information
}
然后,您可以在调用时设置级别功能UseSerilogRequestLogging()
:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ... Other middleware
app.UseSerilogRequestLogging(opts => {
opts.EnrichDiagnosticContext = LogHelper.EnrichFromRequest;
opts.GetLevel = LogHelper.CustomGetLevel; // Use custom level function
});
//... other middleware
}
现在,您的请求摘要日志将全部记录为Debug
,除非发生错误(Seq的屏幕截图):
但这如何解决我们的冗长日志的问题呢?
当你在配置Serilog时,你通常应该会定义一个最低请求级别。例如,以下简单配置将默认级别设置为Debug()
,并将其写入控制台接收器:
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.CreateLogger();
因此,过滤日志的最简单方法是使日志级别低于MinimumLevel
记录器配置中指定的级别。一般而言,如果使用最低级别Verbose
,它将几乎总是被过滤掉。
困难之处在于我们不想总是将Verbose
用作摘要日志的日志级别。如果这样做,我们将不会获得任何非错误的请求日志,而Serilog中间件将变得毫无意义!
相反,我们希望将日志级别设置为Verbose
仅针对运行健康检查端点的请求。在下一节中,我将展示如何在不影响其他请求的情况下识别这些请求。
将自定义日志级别用于健康检查终结点请求
我们需要的是能够在写入摘要日志时识别出健康检查的请求的能力。如前所示,该GetLevel()
方法将当前HttpContext
作为参数,因此理论上有一些可行性。对我来说,最明显的做法是:
- 将
HttpContext.Request
路径与已知的健康检查路径列表进行比较 - 当健康检查终结点被请求时,使用选定的端点元数据来进行标识
第一种选择是最明显的,但是它真的不值得尝试。一旦你陷入其中,你会发现你必须开始复制请求路径并处理各种边缘情况,因此在这里我将跳过该情况。
第二种方法使用了与我上一篇文章中使用的方法类似,在该方法中,我们获得了EndpointRoutingMiddleware为给定请求选择的IEndpointFeature。此功能(如果存在)提供了所选端点的显示名称和路由数据等详细信息。
如果我们假设健康检查是使用默认显示名称注册的,即"Health checks"
,则我们可以使用HttpContext
来标识“健康检查”的请求,如下所示:
public static class LogHelper
{
private static bool IsHealthCheckEndpoint(HttpContext ctx)
{
var endpoint = ctx.GetEndpoint();
if (endpoint is object) // same as !(endpoint is null)
{
return string.Equals(
endpoint.DisplayName,
"Health checks",
StringComparison.Ordinal);
}
// No endpoint, so not a health check endpoint
return false;
}
}
我们可以将此功能与默认GetLevel
功能的自定义版本结合使用,以确保运行健康检查请求的摘要日志使用Verbose
级别,当发生错误时使用Error
而其他请求则使用Information
:
public static class LogHelper
{
public static LogEventLevel ExcludeHealthChecks(HttpContext ctx, double _, Exception ex) =>
ex != null
? LogEventLevel.Error
: ctx.Response.StatusCode > 499
? LogEventLevel.Error
: IsHealthCheckEndpoint(ctx) // Not an error, check if it was a health check
? LogEventLevel.Verbose // Was a health check, use Verbose
: LogEventLevel.Information;
}
}
这个嵌套的三目运算符有一个额外的逻辑-对于无错误,我们检查是否选择了显示名为“Health check”的端点,如果选择了,则使用级别Verbose
,否则使用Information
。
您可以进一步推广此代码,以允许传入其他显示名称或其他自定义使用的日志级别。为了简单起见,我在这里没有这样做,但是GitHub上的相关示例代码显示了如何执行此操作。
剩下的就是更新Serilog中间件RequestLoggingOptions
以使用您的新功能:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ... Other middleware
app.UseSerilogRequestLogging(opts => {
opts.EnrichDiagnosticContext = LogHelper.EnrichFromRequest;
opts.GetLevel = LogHelper.ExcludeHealthChecks; // Use the custom level
});
//... other middleware
}
这时候当你运行应用程序后检查日志时,您会看到标准请求的普通请求日志,但没有健康检查的日志(除非发生错误!)。在下面的屏幕截图中,我将Serilog配置为也记录Verbose
日志,以便您可以查看运行状况检查请求-通常会将它们过滤掉!
总结
在本文中,我展示了如何为Serilog中间件的RequestLoggingOptions提供一个自定义函数,该函数定义了要为给定请求的日志使用的LogEventLevel。例如,我展示了如何使用它将默认级别更改为Debug。如果您选择的级别低于最低级别,它将被完全过滤掉,并且不会被记录。
我还展示了您可以使用这种方法来过滤通过调用健康检查端点生成的公共(低级别的)请求日志。一般来说,这些请求只有在指出问题时才有意义,但它们通常也会在成功时生成请求日志。由于这些端点被频繁调用,因此它们可以显著增加写入的日志数量(无用)。
本文中的方法是检查选定的IEndpointFeature并检查它是否具有显示名称“Health checks”。如果是,请求日志将使用Verbose
级别写入,这通常会被过滤掉。为了更灵活,您可以自定义在这个帖子中显示的日志来处理多个端点名称,或者任何其他的标准。
如何从Serilog请求日志记录中排除健康检查终结点的更多相关文章
- 论文系统Step1:从日志记录中提取特定信息
论文系统Step1:从日志记录中提取特定信息 前言 论文数据需要,需要实现从服务器日志中提取出用户的特定交互行为信息.日志内容如下: 自己需要获取"请求数据包一行的信息"及&quo ...
- 如何在 ASP.Net Core 中实现 健康检查
健康检查 常用于判断一个应用程序能否对 request 请求进行响应,ASP.Net Core 2.2 中引入了 健康检查 中间件用于报告应用程序的健康状态. ASP.Net Core 中的 健康检查 ...
- 在.NET Core 中实现健康检查
.NET Core中提供了开箱即用的运行状况检查,首先,我将在.NET Core API应用程序中执行运行状况检查,接下来,我们将使用DbContext集成SQL Server或数据库的运行状况检查, ...
- 在 ASP.NET Core 中使用 Serilog 进行日志记录
目录 从 NuGet 安装 Serilog 在 Main函数 中配置 Serilog 在项目中使用 Serilog 进行日志输出 从 NuGet 安装 Serilog 核心的包是 Serilog 和 ...
- .Net Core 3.0 使用 Serilog 把日志记录到 SqlServer
Serilog简介 Serilog是.net中的诊断日志库,可以在所有的.net平台上面运行.Serilog支持结构化日志记录,对复杂.分布式.异步应用程序的支持非常出色.Serilog可以通过插件的 ...
- springcloud zuulfilter 实现get,post请求日志记录功能
import com.alibaba.fastjson.JSONObject; import com.idoipo.infras.gateway.open.model.InvokeLogModel; ...
- K8s中Pod健康检查源代码分析
了解k8s中的Liveness和Readiness Liveness: 表明是否容器正在运行.如果liveness探测为fail,则kubelet会kill掉容器,并且会触发restart设置的策略. ...
- Kubernetes中Pod健康检查
目录 1.何为健康检查 2.探针分类 2.1.LivenessProbe探针(存活性探测) 2.2.ReadinessProbe探针(就绪型探测) 3.探针实现方法 3.1.Container Exe ...
- ASP.NET CORE在docker中的健康检查(healthcheck)
在使用docker-compose的过程中,很多程序都提供了健康检查(healthcheck)的方法,通过健康检查,应用程序能够在确保其依赖的程序都已经启动的前提下启动,减少各种错误的发生,同时,合理 ...
随机推荐
- 0014 标签显示模式:display(重点)
目标: 理解 标签的三种显示模式 三种显示模式的特点以及区别 理解三种显示模式的相互转化 应用 实现三种显示模式的相互转化 2.1 什么是标签显示模式 什么是标签的显示模式? 标签以什么方式进行显示, ...
- ELK学习实验009:安装kibana的仪表盘
一 metricbeat仪表盘 1.1 安装metricbeat仪表盘 可以将metricbeat数据在kibana中展示 [root@node4 ~]# cd /usr/local/metricbe ...
- 数据导出至excle
ASP.NET MVC导出Excel 首先下载 NPOI.dll 引用到项目中 建议下载地址:http://download.csdn.net/detail/pukuimin1226/5851747 ...
- C++版本的UnEscape 解析\uxxxx\uxxxx编码字符
解析类似于这种Unicode编码格式的字符串 \u5b55\u5987\u88c5\u590f\u88c52018\u65b0\u6b3e\u5bbd\u677e\u77ed\u8896\u4e2d\ ...
- $AT2292\ Division\ into\ Two$ $dp$
正解:$dp$ 解题报告: 传送门$QwQ$ 不妨令$A\geq B$,于是先$sort$然后预处理判下如果有三个元素两两差都小于$B$的就直接$GG$了. 然后考虑对集合$X$进行$dp$,剩下的数 ...
- 基于Github Pages + docsify,我花了半天就搭建好了个人博客
目录 前言 一些说明 准备工作 上docsify官网看一看 使用docsify命令生成文档站点 部署到Github上 写在最后 前言 "作为一个真正的码农,不能没有自己的个人博客" ...
- wrk性能测试(详解)
一.简介 wrk 是一款针对 Http 协议的基准测试工具,它能够在单机多核 CPU 的条件下,使用系统自带的高性能 I/O 机制,如 epoll,kqueue 等,通过多线程和事件模式,对目标机器产 ...
- 小小知识点(三十九) 正交频分复用OFDM的基本原理及实现
引言 符号间干扰(ISI)是无线传输系统设计中需要考虑的因素,采用什么样的处理方法取决于数据传输速率或等效传输带宽来决定 (1)若数据速率低且与信道最大延迟相比符号持续时间较长,那么就可能无需任何均衡 ...
- 28.python操作excel表格(xlrd/xlwt)
python读excel——xlrd 这个过程有几个比较麻烦的问题,比如读取日期.读合并单元格内容.下面先看看基本的操作: 首先读一个excel文件,有两个sheet,测试用第二个sheet,shee ...
- 【Java基础总结】GUI
GUI(Graphical User Interface),图形用户接口 CLI(Command Line User Interface),命令行用户接口 1. 容器 Container GUI主要位 ...