.Net:如何抑制 TraceSource 标头(“SourceName TraceEventType:Id:”)?
Posted
技术标签:
【中文标题】.Net:如何抑制 TraceSource 标头(“SourceName TraceEventType:Id:”)?【英文标题】:.Net: How to suppress TraceSource header ("SourceName TraceEventType: Id : ")? 【发布时间】:2011-05-03 00:20:21 【问题描述】:我有一个 TraceSource 对象,用于记录 VB.Net 应用程序的初始化。它附加了几个 TraceListener:
ConsoleTraceListener TextWriterTraceListener EventLogTraceListener对于前两个,我希望条目输出是“原始的”——即,没有标准头:
SourceName TraceEventType: Id :
我已经实现了一个包装器,它在 TraceEventType 设置为 Verbose 时执行此操作:
If _buffer.EventType = TraceEventType.Verbose Then
For Each listener As TraceListener In _traceSource.Listeners
listener.Write(_buffer.Text)
Next
Else
_traceSource.TraceEvent(_buffer.EventType, id, _buffer.Text)
End If
我可以对所有跟踪执行此操作,但是 EventLog 中的所有条目都将使用 Level = Information 列出。所以我希望能够指定跟踪消息的严重性,但我在 TraceSource 或 TraceListeners 上找不到任何允许我这样做的方法。据我所知,TraceListener 有以下写入选项:
写() WriteLine() TraceData() TraceEvent() TraceTransfer()最后 3 个允许提供 TraceEventType(它正确标记了 EventLog 条目,但输出到控制台和日志文件的结果随后包含前缀并以如下方式结束(例如):
Bootstrapper Warning: 0 : Failed to validate assembly
有没有办法覆盖 ConsoleTraceListener 和 TextWriterTraceListener 如何格式化其输出以不包含此标头,同时能够使用 TraceEventType 标记条目(用于 EventLog)?
这是迄今为止我想出的最好的:
For Each listener As TraceListener In _traceSource.Listeners
If listener.GetType Is GetType(ConsoleTraceListener) OrElse listener.GetType Is GetType(TextWriterTraceListener) Then
listener.Write(_buffer.Text)
Else
listener.TraceEvent(Nothing, _traceSource.Name, _buffer.EventType, id, _buffer.Text)
End If
Next
这似乎可行,但在 Microsoft 的 TraceListener.TraceEvent Method 文档中,它说:
Important: This method is not intended to be called directly by application code but by members of the Debug, Trace, and TraceSource classes to write trace data to output.
..所以我不确定这是否是一件好事?
编辑:
我刚刚意识到,如果我在此处执行上一个示例的操作,则根本不需要 TraceSource,因为无论如何它都被绕过了。但这也意味着我必须实现自己的过滤和切换机制(但这可能是一个可以让它以我想要的方式工作的代价)。
【问题讨论】:
【参考方案1】:另一个具有可格式化侦听器的类似项目是Essential Diagnostics,它实际上最初是受到 Ukadc.Diagnostics 的启发。
然而,您已经表明您不想要外部依赖项,但您仍然有几个选项无需重写框架的部分内容:
(一) .NET Framework 中设计的扩展点不是重写 TraceSource,而是编写自己的 TraceListener。
如果您编写自己的跟踪侦听器“ConsoleWithoutPrefixListener”和“FileWithoutPrefixListener”,则可以重写 TraceEvent() 方法,将消息转发到 TraceWrite()(并删除前缀)。
事实上,ConsoleTraceListener 或 TextWriterTraceListener 都不是密封的,所以我认为您可以从它们继承并使用 TraceEvent() 方法(加上构造函数)的一行覆盖来实现这一点。
(B) 另一种选择是让 EventLogTraceListener 针对源进行配置,但在(而不是跟踪源)下配置其他两个侦听器。
这样做的缺点是在你的代码中你每次都需要记录两次,例如:
_traceSource.TraceEvent(_buffer.EventType, id, _buffer.Text) Trace.TraceWrite(_buffer.Text)
如果您想编写一些带有前缀的消息而一些不带前缀的消息,那么您将需要两个跟踪源:一个配置了所有三个侦听器,一个配置了事件日志侦听器。
然后,在您的包装器中写入源 A(全部三个)或源 B + Trace 静态方法。
(C) 就个人而言,我的指导是不要使用跟踪来写入事件日志——如果问题足够重要以写入事件日志,您通常不希望用户能够通过配置将其关闭。
在这种情况下,您的包装器直接写入事件日志(EventLog.WriteEntry 或其他),然后您的代码写入文件和控制台的跟踪源和/或跟踪静态方法。
请注意,要正确写入事件日志,您需要考虑权限。要创建事件日志源,您需要以管理员身份运行。作为开发人员,您通常可能拥有管理员权限,因此您需要在没有管理员权限的人的上下文中正确测试。
另外请注意,只有初始创建需要管理员权限,并且在您编写第一条消息时会自动完成,因此如果您已经作为开发人员管理员完成了它,您需要找到一台干净的机器进行测试.
因此,通常您需要将 EventLogInstaller 作为代码的一部分,由 InstallUtil(或等效的 MSI 或其他)运行,在安装期间创建事件日志源(因为 install is 由管理员完成)。那么,当程序运行时,源就存在了。
那么,这与写入跟踪有什么关系——好吧,如果您唯一要做的就是在配置中配置 EventLogTraceListener,那么对于普通用户来说,它就不起作用了;它将尝试将事件写入源(在 initializeData 属性中),然后尝试创建源,如果不以管理员身份运行将失败。
如果您确实为事件源添加了安装程序,那么如果有人更改了配置文件,您仍然会遇到问题。
因此,我建议直接在代码中创建 EventLogInstaller 和 EventLog,以确保名称匹配,而不是通过跟踪基础结构。
【讨论】:
【参考方案2】:这是我的完整解决方案,灵感来自 @Sly 的回答。
要在使用TraceEvent()
方法时抑制标头信息,您可以像这样从ConsoleTraceListener
或TextWriterTraceListener
(或任何需要的侦听器风格)继承;
namespace Custom.Lib
public class ConsoleTraceListener : System.Diagnostics.ConsoleTraceListener
// overridding this method here will suppress header information
// your TraceEvent() messages will still reach the listener
public override void Write(string message)
//base.Write(message);
注意在尝试覆盖 TraceEvent
方法时,我注意到此时标题信息尚未添加到消息字符串中。相反,我选择关闭对 Write(string)
的呼叫这似乎没有任何其他连锁反应,但它确实感觉有点“骇人听闻”,如果有人有“更清洁的方法”,我我对此持开放态度。
使用此客户侦听器的配置应如下所示;
<system.diagnostics>
<sources>
<source name="AppTrace" switchName="sourceSwitch" switchType="System.Diagnostics.SourceSwitch">
<listeners>
<add name="consoleListener"/>
</listeners>
</source>
</sources>
<switches>
<add name="sourceSwitch" value="Information"/>
</switches>
<sharedListeners>
<add name="consoleListener" type="Custom.Lib.ConsoleTraceListener, Custom.Lib" initializeData=""/>
</sharedListeners>
</system.diagnostics>
【讨论】:
【参考方案3】:查看 codeplex 上的 Ukadc.Diagnostics 项目。它是 System.Diagnostics 的一个插件,使您能够根据需要格式化日志/跟踪输出(类似于您可以使用 log4net 和 NLog 执行的操作)。您通过配置使用它,因此您的代码不会直接依赖于库。该库带有用于格式化的可配置对象和利用格式化所需的自定义 TraceListener。该库还使您可以轻松编写自己的格式化“令牌”和您自己的 TraceListener。
例如,您可以将 Ukadc.Diagnostics ConsoleTraceListener 配置为使用如下格式语句:
DateTime Source EventType Message
记录的每条消息都会导致日期/时间、源名称、事件类型和消息。
试试吧,我想你会喜欢的。我自己也使用过一些(主要用于原型设计,还没有用于“真正的”产品)并且取得了不错的成功。
请注意,对于某些标记(如 DateTime),您还可以应用适合该类型的标准格式(例如,对于 DateTime,您可以指定写入日期/时间的格式)。
Ukadc.Diagnostics 附带的文件跟踪侦听器还允许使用令牌系统指定其文件名。
【讨论】:
谢谢,我会看看(尽管出于某种原因,我不喜欢使用外部插件)。现在我也制作了自己的追踪系统,我可以在其中做类似的事情。我的类的功能类似于 TraceSource,但它有两个侦听器集合。一种以标准方式运行,使用 TraceEvent(),另一种使用“原始”Write() 函数。每条记录的消息都被推送到两个类别中的所有侦听器(取决于某些标志等),因此您可以在一个中添加需要 EventType 标记的侦听器,在另一个中添加具有普通/自定义格式的侦听器。效果很好。 我觉得这个库真的很酷,所以去试试吧,你可能会喜欢的。它可以帮助您的工作流程的一种方法是您可以使用同一组 TraceListener 类,但通过配置更改实际写入的内容。因此,您可以拥有与某些侦听器(Console 和 TextWriter)关联的“原始”格式和与其他侦听器(EventLog)关联的“事件”格式。如果您决定在下周或下个月从任一格式添加或删除一些信息,那么您只需更改 app.config 中的格式。没有代码更改。祝你好运! d7samurai,您熟悉 NotInventedHere-Antipattern 吗? @M.Stramm - 不,我不是。但这与现有功能不满足要求、不想要外部代码依赖、破坏内部架构美学等之间存在差异。不过,我确实认为我在编码方面有轻微的强迫症倾向,而且我通常会重写我的自己的代码 - 从头开始 - 在开发过程中多次重复,以保持一切“整洁”、紧密和一致。我可以花几个小时思考应用程序的变量名称/命名结构。 @M.Stramm - 还要注意这个特定项目的目的是作为一个非常简单的 BOOTSTRAPPER(作为 Windows 服务运行,动态维护/下载主应用程序的组件)启动)。以上是关于.Net:如何抑制 TraceSource 标头(“SourceName TraceEventType:Id:”)?的主要内容,如果未能解决你的问题,请参考以下文章
如何抑制 X-Frame-Options SAMEORIGIN 响应标头?
如何让 CMake 创建一个 xcode 项目,其中警告在系统标头中被抑制?
AWS Lambda、.Net Core 和 MySql:无法加载文件或程序集 'System.Diagnostics.TraceSource,版本 = 4.0.0.0
部署到 Ubuntu 18.04 的 ASP.NET Core 3.0 应用程序抛出无法加载文件或程序集 System.Diagnostics.TraceSource