如何利用NLog输出结构化日志,并在Kibana优雅分析日志?

上文我们演示了使用NLog向ElasticSearch写日志的基本过程(输出的是普通文本日志),今天我们来看下如何向ES输出结构化日志、并利用Kibana中分析日志。
- NLog输出结构化日志
- ElasticSearch面向文档
什么是结构化日志?
当前互联网、物联网、大数据突飞猛进,软件越复杂,查找任何给定问题的起因就越困难(且成本更高)。
在实践中我们开发了各种规避、诊断应用程序错误行为的利器:
静态类型检查,自动化测试,事件探查器,崩溃转储和监视系统。但是记录程序执行步骤的日志仍然是事后诊断最丰富的数据源。
在日志分析时,小批量普通的文本对于人类很友好,但却很难从大量普通文本中快速定位、精准提取特定信息。
.....
[2018-04-07T13:45:56.789Z INF] https://example.com/api/warehouse,query reserve,took 100 ms
[2018-04-07T13:45:56.789Z INF] api/commitOrder,OrderId:9876543210,commit order took 50 ms
......
[2018-04-07T13:45:56.789Z INF] /login,user:Kenny,from ip_address:127.0.0.1,took 100 ms
......
[2018-04-07T13:45:56.789Z INF] https://example.com/api/warehouse,OrderId:9876543210,decrease reserve took 10000 ms
[2018-04-07T13:45:56.789Z INF] /api/creatNewOrder,OrderId:9876543210, create order took 100 ms
.....
- 如果找到特定OrderId?
- 如何找到哪些请求耗时较长(比如大于2S)?
- 如何定位到该耗时请求处理管道中哪一段出现性能瓶颈?
- 出现性能瓶颈的请求占比?
普通文本对人类友好,对于机器不友好。
结构化日志提出了Message template来解决日志对机器不友好的问题。
Messgae Template: 是一个与语言无关的规范,以对人类和机器友好的格式捕获、呈现结构化的日志事件。
var traceid = _.TraceIdentifier;
// 【锁定库存】 这个动作耗时较长
_logger.LogInformation("{TraceId},{endpoint},OrderId:{orderId},decrease reserve took {elasped} ms", traceid, "https://example.com/api/warehouse", 9876543210, 10000);
注意命名占位符,它们能如格式化字符串占位符{0}{1}一样占位,而且能将属性名称与每个匹配位置的消息数据相关联,如下图以json格式提取了关键消息。

消息模板的优势在于:既能保持普通文本的格式,又具备捕获结构化数据的能力(对机器友好)。
下面来完整输出、分析提交订单请求的日志:

利用NLog向ES输出结构化日志
NLog4.5引入结构化日志,支持Message Template, 在ASP.NET Core脚手架Startup文件--->Configure方法添加如下代码:
app.MapWhen(_ => _.Request.Path.Value == "/" ,
appBuilder => appBuilder.Run(_ =>
{
var traceid = _.TraceIdentifier;
// 查询库存
_logger.LogInformation("{traceId},{endpoint},query reserve,took{elasped} ms", traceid, "https://example.com/api/warehouse", 100);
// 创建订单
_logger.LogInformation("{traceId},{endpoint},OrderId:{orderId}, create order took {elasped} ms", traceid, "/api/creatNewOrder", 9876543210, 100);
// 锁定库存
_logger.LogInformation("{traceId},{endpoint},OrderId:{orderId},decrease reserve took {elasped} ms", traceid, "https://example.com/api/warehouse", 9876543210, 10000);
// 提交订单
_logger.LogInformation("{traceId},{endpoint},OrderId:{orderId},commit order took {elasped} ms", traceid, "api/commitOrder", 9876543210, 50);
_.Response.StatusCode = StatusCodes.Status200OK;
_.Response.WriteAsync("Generate Order OK!");
return Task.CompletedTask;
}));
这里我们关注如何向ElasticSearch输出结构化日志,请务必将includeAllProperties="true",这样输出到ES的才会包含所有事件属性。
<target name="elastic" xsi:type="BufferingWrapper" flushTimeout="5000">
<target xsi:type="ElasticSearch" includeAllProperties="true" index="logstash-20200805" uri="${configsetting:item=ConnectionStrings.ElasticUrl}" />
</target>
Kibana中分析日志
这个订单请求,会产生6条日志(这里你也会看到日志的显示顺序可能不能如你所愿):

下面给出[锁定库存]日志ES文档, 文档上已经出现了关键的消息属性[traceId] [endpoint] [orderId] [elasped]
{
"_index": "logstash-20200805",
"_type": "logevent",
"_id": "emTivXMBwcdwe4RliB9f",
"_version": 1,
"_score": null,
"_source": {
"@timestamp": "2020-08-05T17:10:00.7170456+08:00",
"level": "Info",
"message": "2020-08-05 17:10:00.7170|INFO|EqidManager.Startup|0HM1P3TAGNJ5Q:00000001,https://example.com/api/warehouse,OrderId:9876543210,decrease reserve took 10000 ms",
"TraceId": "0HM1P3TAGNJ5Q:00000001",
"endpoint": "https://example.com/api/warehouse",
"orderId": 9876543210,
"elasped": 10000
},
"fields": {
"@timestamp": [
"2020-08-05T09:10:00.717Z"
]
},
"sort": [
1596618600717
]
}
通过Kibana界面我们可以便捷地完成如下分析:
- 通过{TraceId}找到某次请求所有日志
- 通过{elasped} >=10s 过滤出处理时长大于10s的阶段
- 通过{ordeid} 追踪该订单完整链路
......

总结
本文肝时较长(elasped>=10天)
- 从常规诊断日志谈到[对机器友好,适用于分析的结构化日志],其中的核心是消息模板。
- 再谈到我是如何利用NLog输出结构化日志,其中注意在NLog Target中设置
includeAllProperties=true(默认是false), 摸索了很久 - 最后在Kibana中演示便捷的分析结构化日志
干货周边
- [消息模板] https://messagetemplates.org/
- [如何利用NLog输出结构化日志] https://github.com/nlog/nlog/wiki/How-to-use-structured-logging
- [NLog to ES] https://github.com/markmcdowell/NLog.Targets.ElasticSearch
- [TraceId]
- Logging with ElasticSearch, Kibana, ASP.NET Core and Docker
如何利用NLog输出结构化日志,并在Kibana优雅分析日志?的更多相关文章
- 利用Mongoose来结构化模式与验证
Mongoose是一个文档对象模型(ODM)库,为MongoDB Node.js原生驱动程序提供更多的功能. 把结构化的模式应用到一个MongoDB集合,提供了验证和类型转换的好处 Mongoose通 ...
- [AI开发]基于DeepStream的视频结构化解决方案
视频结构化的定义 利用深度学习技术实时分析视频中有价值的内容,并输出结构化数据.相比数据库中每条结构化数据记录,视频.图片.音频等属于非结构化数据,计算机程序不能直接识别非结构化数据,因此需要先将这些 ...
- 视频结构化 AI 推理流程
「视频结构化」是一种 AI 落地的工程化实现,目的是把 AI 模型推理流程能够一般化.它输入视频,输出结构化数据,将结果给到业务系统去形成某些行业的解决方案. 换个角度,如果你想用摄像头来实现某些智能 ...
- 有效的结构化思维训练,MECE分析法
MECE原则,表达精准分类与全面性的有效利器 结构化思维的本质就是逻辑,其目的在于对问题的思考更完整.更有条理,它帮助我们一个一个找到线头,理清思路,探求事物之间的相互联系.MECE分析法是一种结构化 ...
- Asp.Net Core中利用Seq组件展示结构化日志功能
在一次.Net Core小项目的开发中,掌握的不够深入,对日志记录并没有好好利用,以至于一出现异常问题,都得跑动服务器上查看,那时一度怀疑自己肯定没学好,不然这一块日志不可能需要自己扒服务器日志来查看 ...
- .NET Core开发日志——结构化日志
在.NET生态圈中,最早被广泛使用的日志库可能是派生自Java世界里的Apache log4net.而其后来者,莫过于NLog.Nlog与log4net相比,有一项较显著的优势,它支持结构化日志. 结 ...
- 结构化日志类库 ---- Serilog库
在过去的几年中,结构化日志已经大受欢迎.而Serilog是 .NET 中最著名的结构化日志类库 ,我们提供了这份的精简指南来帮助你快速了解并运用它. 0. 内容 设定目标 认识Serilog 事件和级 ...
- [C#] 将NLog输出到RichTextBox,并在运行时动态修改日志级别过滤
作者: zyl910 一.缘由 NLog是一个很好用的日志类库.利用它,可以很方便的将日志输出到 调试器.文件 等目标,还支持输出到窗体界面中的RichTextBox等目标. 而且它还支持在运行时修改 ...
- 探索ASP.Net Core 3.0系列六:ASP.NET Core 3.0新特性启动信息中的结构化日志
前言:在本文中,我将聊聊在ASP.NET Core 3.0中细小的变化——启动时记录消息的方式进行小的更改. 现在,ASP.NET Core不再将消息直接记录到控制台,而是正确使用了logging 基 ...
随机推荐
- Python面试【315+道题】
第一部分 Python基础篇(80题) 为什么学习Python? 通过什么途径学习的Python? Python和Java.PHP.C.C#.C++等其他语言的对比? 简述解释型和编译型编程语言? P ...
- git的撤销、删除和版本回退
目录 备注: 知识点: 查看git仓库的状态 查看历史记录. 版本回退 备注: 本文参考于廖雪峰的博客Git教程.依照其博客进行学习和记录,感谢其无私分享,也欢迎各位查看原文. 知识点: 1.git ...
- bzoj1745[Usaco2005 oct]Flying Right 飞行航班*
bzoj1745[Usaco2005 oct]Flying Right 飞行航班 题意: n个农场,有k群牛要从一个农场到另一个农场(每群由一只或几只奶牛组成)飞机白天从农场1到农场n,晚上从农场n到 ...
- 最小割树(Gomory-Hu Tree)
当我们遇到这样的问题: 给定一个 \(n\) 个点 \(m\) 条边的无向连通图,多次询问两点之间的最小割 我们通常要用到最小割树. 博客 建树 分治.记录当前点集,然后随便找俩点当 \(s\) 和 ...
- js读取其他网页内容(同源)
通过xss第一次取得网页内容,然后获取到管理员账号页面进行二次盲打.js需要保留script部分其余去除. <html><p id='d1'></p> <sc ...
- APP自动化 -- 获取toast元素的文本内容
一.toast元素 1.表现形式:toast元素就是下图中 “操作成功” 那个一闪而过的标签. 2.特殊点:因为一闪而过,时间太短,用UIAutomatorView截屏截不到. 二.获取方法 1.用 ...
- 【Unity3D】简单常用的功能实现1——鼠标点击实现移动
[鼠标点击实现移动] 第一步,在要移动的GameObject的Inspector面板中添加角色控制器组件并调整参数. 参数的调整可以依照Scene面板,如下图的绿色线框(角色控制器组件是一种胶囊形状的 ...
- MySQL(四)数据备份与还原
数据备份与还原: 备份:将当前已有的数据或者记录保留 还原:将已经保留的数据恢复到对应的表中 为什么要做备份还原: 1.防止数据丢失:被盗.误操作 2.保护数据的记录 数据备份还原的方式很多:数据表备 ...
- [leetcode/lintcode 题解] 微软面试题:股票价格跨度
编写一个 StockSpanner 类,它收集某些股票的每日报价,并返回该股票当日价格的跨度. 今天股票价格的跨度被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,包括今天). 例如 ...
- java基础(二)--main方法讲解
main()函数是如下的固定格式,除了args可以修改名字,其余均不可以修改 public class TestBase02MainMath { public static void main(Str ...