一套标准的ASP.NET Core容器化应用日志收集分析方案

讲故事

关注我公众号的朋友,应该知道我写了一些云原生应用日志收集/分析相关的文章,其中内容大多聚焦某个具体的组件:

  • 超级有用的TraceId,快点用起来吧!
  • 如何利用NLog输出结构化日志,并在Kibana优雅分析日志?
  • 既然能直接向ElasticSearch写日志,为什么还要logstash日志摄取器?

本文记录一套标准的、无侵入的的容器化应用日志收集方案:

  1. 什么样的日志应该被收集?
  2. 如何输出为结构化日志?
  3. 使用EFK无侵入的收集分析日志

定制ASP.NET Core日志; 将结构化日志输出到stdout;Fluentbit无侵入式转发容器日志;存储在Es并在Kibana上分析日志

定制ASP.NET Core日志

面向互联网的经典应用,不外乎三部分日志:请求、业务处理、数据库操作。
在实际采集日志时,关注[特定日志场景]

  • 提供给第三方调用的API(有撕逼可能性)
  • 核心流程业务 (996排障)
  • 数据库操作(删库跑路可能性)
  • 应用内部http请求
  • Warn、Error、Fatal级别日志(持续关注)

ASP.NETCore灵活的配置系统、可插拔的组件系统,让我们轻松配置日志、管理日志组件。

日志采集策略

ASP.NET Core应用的日志配置取决于appsettings.{Environment}.json文件的Logging配置节,
支持多个LogProvider、过滤日志、定制特定种类日志的收集级别。

"Logging": {
"LogLevel": {
"Microsoft": "Warning",
"Microsoft.AspNetCore.Hosting.Diagnostics": "Information", // 提供给第三方调用API日志
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.EntityFrameworkCore.Database.Command": "Information", //数据库操作sql日志
"System.Net.Http.HttpClient": "Information", // 记录内部http请求
"Default": "Warning" // 除以上日志之外,记录Warning+级别日志
}
}

以上Logging配置针对[特定日志场景],满足经典互联网应用的日志采集需求。

NLog Provider

结构化日志提出[MessageTemplate]来解决传统文本日志对机器不友好的问题。

① 这里使用NLog Provider接管所有的日志输出

// Please install-package NLog.Web.AspNetCore
internal static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging((hostBuilder, loggerBuilder) =>
{
loggerBuilder.ClearProviders();
loggerBuilder.AddNLog("nlog.production.config");
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});

② 编写NLog[JsonLayout]将传统文本日志转换为JSON格式日志:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true" internalLogFile="logs/nlog-internal.log" internalLogLevel="Info" >
<targets async="true">
<target name="console" xsi:type="Console">
<layout xsi:type="JsonLayout" includeAllProperties="true" excludeProperties="EventId_Id,EventId_Name,EventId">
<attribute name="time" layout="${date:format=yyyy/MM/dd HH\:mm\:ss.fff zzz}" />
<attribute name="category" layout="${logger}" />
<attribute name="log_level" layout="${level:lowerCase=true}" />
<attribute name="message" layout="${message}" />
<attribute name="trace_id" layout="${aspnet-TraceIdentifier:ignoreActivityId=true}" />
<attribute name="user_id" layout="${aspnet-user-identity}" />
<attribute name="exception" layout="${exception:format=tostring}" />
</layout>
</target>
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="console" ruleName="console" />
</rules>
</nlog>

与业务紧密相关的日志字符:

  • includeAllProperties="true" 输出日志条目的所有属性
  • trace_id=${aspnet-TraceIdentifier:ignoreActivityId=true} 取得trace_id,排障时很有用
  • user_id=${aspnet-user-identity} 取得该条日志生产者的名字

启动应用日志长这样:

请保持所有应用日志的输出目标为stdout,让Fluent-bit无侵入采集!

....【TODO: 制作Docker镜像!!!!】 ...

Fluent-Bit收集容器日志

Fluent-bit采集日志,小巧够用!

采集容器日志需要将容器应用的Logging Driver改为[Fluentd]
Fluentd Driver默认会在宿主机24224端口监听Forward消息 。

一个简单的容器Docker-compose示例:

version: "3.7"
services:
website:
image: ${DOCKER_REGISTRY}/eap/website:0.1
ports:
- "80:80"
environment:
- TZ=Asia/Shanghai
networks:
- webnet
logging:
driver: fluentd // 注意,这里需要指定使用 Fluentd 作为Logging Driver
options:
# fluentd-address: localhost:24224
tag: eap-website
restart: always
networks:
webnet:
external: true
name: eap-net

请注意上面的app容器使用Fluentd作为 Logging Driver, 请给app容器添加适当的日志标签tag: eap-website, 这个标签在后面Fluent-bit过滤数据时会用到。

Fluentd Driver采集的格式如下 :

{
"container_id": "...",
"container_name": "...",
"source": "stdout",
"log": "This is log content"
}

容器应用产生的json日志(位于log字段)会被编码,这就很尴尬了,处心积虑的结构化日志没有萃取出日志字段!!

多番搜索,在Fluentbit上找到Decoders插件, 能将被编码的JSON字符串解码:

完整的fluent-bit.conf 如下:

[SERVICE]
flush 1
log_Level info
daemon off
http_server on // 在宿主机作为http server启动
http_listen 0.0.0.0
http_port 2020
storage.metrics on
Parsers_File parsers.conf // 加载用于Parser的文件
[INPUT]
name forward
max_chunk_size 1M
max_buffer_size 5M
[FILTER] // Filter Praser插件(docker)解码应用的json日志
Name parser // 插件名称,某枚举值
Match eap-website // 匹配什么tag的日志
Key_Name log // 要解析的字段
Parser docker // 以docker日志格式解析 [具体内容在在parser.conf文件】
Preserve_Key True // 保留原解析的字段
Reserve_Data True // 保留原始其他字段
[FILTER] // 这一部分是nginx容器日志
Name parser
Match eap-frontend // Filter Praser插件(nginx)解析前端nginx日志
Parser nginx
Key_Name log
Preserve_Key True
Reserve_Data True
[OUTPUT]
name es
match *
host es01
port 9200
logstash_format on
replace_dots on
retry_limit false

这样输出的结果就是:

nice,后面就请自由在Kibana中分析日志吧。

完整的EFK收集容器日志的源码配置,github传送门:https://github.com/zaozaoniao/dockercompose-efk

这是一套完整的容器日志采集和分析方案: ①经典互联网应用的日志收集策略、②结构化输出、③无侵入式采集,提供github配置源码,可学习可商用。

posted @   码甲哥不卷  阅读(1932)  评论(4编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示

目录导航