.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() 方法时抑制标头信息,您可以像这样从ConsoleTraceListenerTextWriterTraceListener(或任何需要的侦听器风格)继承;

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:”)?的主要内容,如果未能解决你的问题,请参考以下文章

如何抑制 IWYU 系统标头错误?

log4net 与 TraceSource [关闭]

如何抑制 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