NLog4LinqPad: 高效日志记录工具

在软件开发过程中,日志记录是一个不可或缺的工具,无论是用于概念验证(Proof of Concept, POC)代码的编写、特定场景的测试,还是调试代码。在草图或POC中,使用强大的扩展方法Dump是一种简单且足够有效的方式,甚至比传统的日志记录更好。然而,当涉及到调试已经成为大型解决方案一部分的代码,并且使用传统日志记录时,不能总是用LinqPad的工具来替代它。

背景

在日志记录方面,主要使用NLog。很多时候,需要在调用LinqPad的代码附近查看日志结果。在网上搜索时,偶然发现了一些代码片段,它们创建了一个能够将日志记录到LinqPad的Results面板的控制台日志记录器。首先,创建了一个库,以避免在草图中包含这些片段。然后,意识到想将这个输出作为一个新的目标添加,而不是替换所有现有的目标。后来,想看到彩色的日志条目,而不是纯文本。这就是这个库诞生的方式。

使用代码

如果对整个代码感兴趣,请随时访问GitHub仓库:。如果想使用这个日志记录器,需要将对库的引用添加到查询中。如果有Developer/Premium版,可以直接从NuGet安装它,对于所有其他版本,需要从GitHub下载发布包,或者自己构建它。别忘了还要添加NLog和System.Reactive.Core库。

可以使用默认设置的日志记录器,这很可能满足大部分需求。库的入口点是Nlog4LinqPad静态类,它包含两个方法:传统的LogToConsoleResults和更高级的LogToHtmlResults。两种方法的所有参数都是可选的,但得益于C# 7.2中的新特性,可以在不打扰其他参数的情况下覆盖它们的默认值。

两种方法都会将目标添加到现有配置中,或者在尚未创建任何配置的情况下创建一个新配置。注意:默认情况下,LinqPad会保持其AppDomain中加载的类型,由于NLog使用静态类,重复运行同一个草图会产生奇怪的结果。完成后按Ctrl+Shift+F5卸载进程。

控制台日志记录器

控制台日志记录器只有两个参数:最小日志级别(默认为Trace)和一个根据NLog规范的布局格式字符串(默认会显示时间戳、级别、消息和任何异常)。这个日志记录器将使用默认的结果面板进行日志记录,因此输出将与其他所有转储或写入控制台的内容混合在一起。让尝试一下:

HTML日志记录器

HTML日志记录器稍微复杂一些。让从默认值开始:

如所见,对于默认和暗色主题,默认样式是不同的。请注意,默认情况下,日志被写入一个名为"Log window"的新面板。这个面板是一个WebBrowser控件,就像Results面板一样,但它使用简化的DOM,并且(目前)没有设计上的长度限制。计划引入滚动日志视图功能,以真正支持无限日志记录。

解决方案使用Reactive Extensions来提高性能。条目被缓冲,并且文档每秒钟或当队列有200个元素时才更新一次。之后,浏览器窗口会滚动到底部。

C# observer = queue .Buffer(TimeSpan.FromSeconds( 1 ), 200 ) .ObserveOn(browser) .Where(x => x.Count > 0) .Subscribe(strings => { browser.SuspendLayout(); foreach ( var text in strings ) { var e = browser.Document.CreateElement( " div" ); e.InnerHtml = text; browser.Document.Body.InsertAdjacentElement (HtmlElementInsertionOrientation.BeforeEnd, e); } browser.ResumeLayout(); browser.Document.Body.ScrollIntoView( false ); });

主题与浏览器同步观察,因此UI线程。Rx提供的这种优雅方式,摆脱了调用!

静态方法有几个参数,所有参数都是可选的,默认值:

  • minLogLevel:与控制台日志记录器相同,默认为Trace
  • ownPanelName:默认为"Log window",用于创建日志窗口的面板名称。如果为null,则使用默认的Results面板。
  • layout:要使用的布局。它类似于标准格式,有一个区别:只有用${...}标记的布局元素被使用,每个元素将成为结果中的一个节点。任何外部的都被忽略。
  • styling:要使用的CSS样式。如果为null,则使用默认样式。样式可能性如下所述。

样式

有一个名为TargetStyling的类,可以为各种场景保存CSS样式。让以默认布局为例:"${date:format=HH\\:mm\\:ss}${level}${message}${exception:format=tostring}"。这是日志条目行的模式。每个用${...}标记的布局元素将代表该行中的一个项目。这两个的样式对应物总是会有的。所有其他应用的样式将取决于条目的内容。

HTML

<div class="lqph-row lqph-levelname"> <span class="lqph-item lqph-date">.. </span> <span class="lqph-item lqph-level">.. </span> <span class="lqph-item lqph-message">.. </span> <span class="lqph-item lqph-exception">.. </span> </div>

item、row和log level类在类中有直接的属性对应物。但还有一个名为Classes的属性,这是一个字典,可以用它为每个NLog渲染器添加样式等等。只是为了说明,这些在默认样式中使用,从而产生了上面的视图:

C# Classes = { { "date", "width: 100px;" }, { "level", "width: 70px; text-transform: uppercase; font-weight: bold;" }, { "exception:empty", "display:none;" }, { "exception", "display:block; padding: 10px;" } }

有趣的点

首先,使用了默认的Results面板,但在检查了LinqPad的代码和生成的html代码后,意识到它不是日志使用的最佳选择,因为它有不需要的功能的开销,并且有限制来支持这些。然后,发现了这段代码,在0.5版本中使用了它,但不幸的是,它被证明不适合多线程场景,也不适合高负载,因为它使用了与默认面板相同的写入器,它强加了限制和开销。在这一点上,放弃了这个方向,并实现了上面的基于Rx的方法。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485