最近在写数据库程序,需要一个高性能的结构化日志记录组件,简单研究了一下Microsoft.Extensions.Logging和Serilog,还是决定重造一个轮子。

一、使用方法

  直接参考以下示例代码:

NanoLogger.Start();

DateTime? nullable = null;
const bool boolValue = true;
const char charValue = 'C';
const int intValue1 = 12345;
const int intValue2 = 0xABCDEF;
const string stringValue = "你好世界";
var point = new Point { X = 123, Y = 456 };
var person = new Person { Name = "Rick", Birthday = new DateTime(1977, 3, 1), Phone = "13861838709" }; var log = new NanoLogger(); log.Trace("Trace message");
log.Trace($"Trace {DateTime.Now}, {intValue1}, 0x{intValue2:X}");
log.Debug($"Debug {DateTime.Now:yyyy-MM-dd hh:mm:ss}, 你好世界!");
log.Info($"Info {point}, {person}, {charValue}");
log.Warn($"这是警告: {boolValue}");
log.Error($"发生异常: {nullable}, Msg={stringValue}"); NanoLogger.Stop();

执行后控制台输出如下图(记录的结构化值会高亮显示):

二、性能测试

  以下测试仅用一个日期类型参数: nanoLogger.Info($"Hello World {now}");

Method Mean Error StdDev Ratio Lock Contentions Allocated Alloc Ratio
NanoLog 154.6 ns 0.91 ns 3.48 ns 0.04 - - 0.00
MsLog 3,922.2 ns 49.13 ns 202.60 ns 1.00 0.0004 264 B 1.00
MsLogCodeGen 4,079.3 ns 52.49 ns 218.77 ns 1.04 0.0010 208 B 0.79
  • NanoLog 本组件控制台输出
  • MsLog Microsoft.Extensions.Logging控制台输出
  • MsLogCodeGen 使用[LoggerMessageAttribute]代码生成方式

三、实现原理


+-----Logger Threads-----+ +-----Background Thread----+
| | | |
| logger.Info(xxx) | | ConsoleLogger.Log() |
| | +-----Log Queue---+ | |
| logger.Debug(xxx) | ==> |-Log-|-Log-|-...-| ==> | FileLogger.Log() |
| | +-----------------+ | |
| logger.Warn(xxx) | | OtherLogger.Log() |
| | | |
+------------------------+ +--------------------------+
  • 日志记录时先判断对应的日志级别是否启用,不启用直接忽略。这里使用C# 6的InterpolatedStringHandlerAttribute自定义实现LogMessageBuilder,一方面避免值类型的装箱,另一方面可以记录结构化信息(名称、类型、值、格式化);

  • 启用则将日志消息、对应的属性类型及属性值序列化后写入LogMessage内。这里的序列化非常简单,仅相当于一个内存复制(参考下图)。LogMessage是一个结构体,如果序列化后的数据小于阀值则直接存储在内置的缓冲块内(没有Heap内存分配的问题),否则从ArrayPool内租用一个缓冲块存储超出部分;

+--------------------LogMessage 缓冲块-----------------------+
|-TokenType-|---Value---|-TokenType-|--------Value------|---|
| Literal | 5,"Hello" | Int | "name",12345,"X2" | |
+-----------------------------------------------------------+
  • 序列化后的事件信息(LogEvent)及消息数据(LogMessage)直接加入一个多生产者-单消费者的消息队列,至此前端日志记录过程结束,不阻塞后续代码执行;

  • 后台线程循环从队列取出待处理日志,由配置的ILogger实现处理。例如ConsoleLogger格式化后输出至控制台;FileLogger将数据写入文件存储。

四、日志搜索

  结构化日志当然得支持结构化搜索,参考控制台工程NanoLog.File.Viewer使用Roslyn解析字符串表达式编译后过滤日志记录(参考下图):

  • 表达式中e.XXX对应LogEvent的相关属性条件;
  • 表达式中e["xxx"]["yyy"]对应LogMessage结构化记录的值条件。

五、本文小结

  最后GitHub地址:https://github.com/enjoycode/NanoLog.git, 作者个人能力实在有限Bug在所难免,如有问题请邮件联系或Github Issue,欢迎感兴趣的小伙伴们加入共同完善,当然更欢迎赞助项目或给作者介绍工作(目前找工作中)。

开源高性能结构化日志模块NanoLog的更多相关文章

  1. .NET下使用 Seq结构化日志系统

    前言 我们公司在日志管理方面一直没有统一,主要痛点有: 每个开发人员都是各用各的,存储日志的形式也是五花八门,如:本地文件,数据库,Redis,MongoDB 由于公司访问服务器要通过堡垒机,所以本机 ...

  2. .NET Core开发日志——结构化日志

    在.NET生态圈中,最早被广泛使用的日志库可能是派生自Java世界里的Apache log4net.而其后来者,莫过于NLog.Nlog与log4net相比,有一项较显著的优势,它支持结构化日志. 结 ...

  3. 结构化日志类库 ---- Serilog库

    在过去的几年中,结构化日志已经大受欢迎.而Serilog是 .NET 中最著名的结构化日志类库 ,我们提供了这份的精简指南来帮助你快速了解并运用它. 0. 内容 设定目标 认识Serilog 事件和级 ...

  4. 探索ASP.Net Core 3.0系列六:ASP.NET Core 3.0新特性启动信息中的结构化日志

    前言:在本文中,我将聊聊在ASP.NET Core 3.0中细小的变化——启动时记录消息的方式进行小的更改. 现在,ASP.NET Core不再将消息直接记录到控制台,而是正确使用了logging 基 ...

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

    上文我们演示了使用NLog向ElasticSearch写日志的基本过程(输出的是普通文本日志),今天我们来看下如何向ES输出结构化日志.并利用Kibana中分析日志. NLog输出结构化日志 Elas ...

  6. 那些年我们用过的组件-结构化日志组件 Serilog

    什么是结构化日志 我们记录日志惯常使用 log4j2.NLog 等日志组件,这些组件提供了输出到多种终端的能力,但是大部分时候我们选择将日志输出到操作系统的文件系统中,为什么呢?至少有一部分原因是记录 ...

  7. Asp.Net Core中利用Seq组件展示结构化日志功能

    在一次.Net Core小项目的开发中,掌握的不够深入,对日志记录并没有好好利用,以至于一出现异常问题,都得跑动服务器上查看,那时一度怀疑自己肯定没学好,不然这一块日志不可能需要自己扒服务器日志来查看 ...

  8. 【转】结构化日志类库 ---- Serilog库

    源地址:https://www.cnblogs.com/mq0036/p/8479956.html 解决异常: Invalid cast from 'System.String' to 'Serilo ...

  9. 【腾讯Bugly干货分享】微信mars 的高性能日志模块 xlog

    本文来自于腾讯bugly开发者社区,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/581c2c46bef1702a2db3ae53 Dev Club 是一个交流移动 ...

  10. 【腾讯Bugly干货分享】微信终端跨平台组件 mars 系列(一) - 高性能日志模块xlog

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57ff5932cde42f1f03de29b1 本文来源: 微信客户端开发团队 ...

随机推荐

  1. 牛客网-SQL专项训练18

    ①在下列sql语句错误的是?B 解析: 在sql中若要取得NULL,则必须通过IS NULL或者IS NOT NULL进行获取,无法直接使用等号. 一个等号(=)表示把1赋值给变量啊 ==:称为等值符 ...

  2. HarmonyOS NEXT应用开发实战—组件堆叠

    介绍 本示例介绍运用Stack组件以构建多层次堆叠的视觉效果.通过绑定Scroll组件的onScroll滚动事件回调函数,精准捕获滚动动作的发生.当滚动时,实时地调节组件的透明度.高度等属性,从而成功 ...

  3. 通过部署流行Web框架掌握Serverless技术

    简介: 通过学习部署流行Web框架,如SpringBoot,Express,Web IDE,让你掌握Serverless函数计算架构和技术,领略弹性并发,高可用的好处.大家好,我是霍大侠,欢迎来到我的 ...

  4. EventBridge 在 SaaS 企业集成领域的探索与实践

    简介: 当下降本增效是各行各业的主题,而 SaaS 应用作为更快触达和服务业务场景的方式则被更多企业熟知和采用.本文将结合实际业务场景讲述在 SaaS 行业的洞察与 SaaS 集成的探索实践. 作者: ...

  5. 基于Ganos百行代码实现亿级矢量空间数据在线可视化

    简介: 本文介绍如何使用RDS PG或PolarDB(兼容PG版或Oracle版)的Ganos时空引擎提供的数据库快显技术,仅用百行代码实现亿级海量几何空间数据的在线快速显示和流畅地图交互,且无需关注 ...

  6. 阿里云容器服务全面升级为 ACK Anywhere,让云的边界拓展至企业需要的每个场景

    ​简介: 2021 年 9 月 26 日上海阿里云计算峰会上,阿里巴巴研究员.阿里云云原生应用平台负责人丁宇宣布,阿里云容器服务全面升级为 ACK Anywhere,让企业在任何需要云的地方,都能获得 ...

  7. Python:Lambda

    Lambda >>> (lambda: 3)() # Using a lambda expression as an operator in a call exp. 经过查阅资料,理 ...

  8. WPF 将 StaticResource 和 ResourceDictionary 放在一起的魔幻行为

    本文将记录一些在 WPF 里面,使用 StaticResource 将 ResourceDictionary 玩坏的做法.大家可以放心的是,这些玩法基本只有高级玩家或逗比开发者才会使用到 后加入的资源 ...

  9. 2.生产环境k8s-1.28.2集群小版本升级到1.28.5

    环境:https://www.cnblogs.com/yangmeichong/p/17956335 # 流程:先升级master,再升级node # 1.备份组件参考:https://kuberne ...

  10. Linux下ffmpeg库的编译链接

    /usr/bin/ld: /usr/local/ffmpeg/lib/libavformat.a(aviobuf.o): in function `ff_crc04C11DB7_update':/ho ...