我有一个TraceSource对象,用于记录VB.Net应用程序的初始化。它附加了几个TraceListeners:
前两个我希望输入输出为“raw” - 即没有标准标题:
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
我可以为所有跟踪执行此操作,但随后将使用Level = Information列出EventLog中的所有条目。所以我希望能够指定跟踪消息的严重性,但我无法在TraceSource或TraceListeners上找到允许我这样做的任何方法。据我所知,TraceListener有这些选项可以写入它:
最后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,因为它无论如何都被绕过了。但这也意味着我必须实现自己的过滤和切换机制(但这可能是一个好的代价,让它按照我想要的方式工作)。
答案 0 :(得分:2)
另一个可以使用的格式化侦听器的类似项目是Essential Diagnostics,其实际上最初是受到Ukadc.Diagnostics的启发。
但是,您已指出您不想要外部依赖项,但您仍然有几个选项而无需重新编写部分框架:
(A) .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 +跟踪静态方法。
(C) 就个人而言,我的指导是不使用跟踪来写入事件日志 - 如果问题非常重要,可以写入事件日志,通常不希望用户能够通过配置将其关闭。 / p>
在这种情况下,您的包装器直接写入事件日志(EventLog.WriteEntry或其他),然后您的代码将写入文件和控制台的跟踪源和/或跟踪静态方法。
请注意,要使写入事件日志正常工作,您需要考虑权限。要创建事件日志源,您需要以管理员身份运行。作为开发人员,您通常可能拥有管理员权限,因此您需要在没有人的情况下对此进行正确测试。
另请注意,只有初始创建需要管理员权限,这是在您编写第一条消息时自动完成的,因此如果您已经以开发人员管理员身份完成此操作,则需要找到一台要测试的干净机器
因此,通常需要将EventLogInstaller作为代码的一部分,由安装期间创建事件日志源的InstallUtil(或等效的MSI或其他)运行(因为install 是由管理员完成)。然后,当程序运行时,源存在。
那么,这与写入跟踪有什么关系 - 好吧,如果您唯一要做的就是在配置中配置EventLogTraceListener,那么对于普通用户来说,它不会工作;它会尝试将事件写入源(在initializeData属性中),然后尝试创建源,如果没有运行,则管理员将失败。
如果您确实为事件源添加了安装程序,那么如果有人更改了配置文件,您仍然会遇到问题。
因此,我建议直接在代码中创建EventLogInstaller和EventLog,以确保名称匹配,而不是通过跟踪基础结构。
答案 1 :(得分:1)
这是我对此的完整解决方案,受到@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);
}
}
}
N.B。尝试覆盖 TraceEvent
方法时,我注意到此时尚未将标头信息添加到消息字符串中。相反,我选择将呼叫静音 Write(string)
,这似乎没有任何其他连锁效应,但如果有人采用“更清洁的方法”,它确实感觉有点'hackish' “我很开放。
使用此客户监听器的配置应该如下所示;
<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>
答案 2 :(得分:0)
查看codeplex上的Ukadc.Diagnostics项目。它是System.Diagnostics的一个附加组件,它使您能够根据需要格式化日志记录/跟踪输出(类似于您可以使用log4net和NLog执行的操作)。您可以通过配置使用它,因此您的代码不会直接依赖于库。该库附带了可配置的格式化对象以及利用格式化所需的自定义TraceListeners。该库还使您可以轻松编写自己的格式“令牌”和自己的TraceListener。
例如,您可以将Ukadc.Diagnostics ConsoleTraceListener配置为使用如下格式语句:
{DateTime} {Source} {EventType} {Message}
记录的每条消息都会导致日期/时间,源名称,事件类型和消息。
尝试一下,我想你会喜欢它。我自己使用过它(主要是用于原型设计,而不是用于“真正的”产品)并取得了很好的成功。
请注意,对于某些令牌(如DateTime),您还可以应用适合该类型的标准格式(例如,对于DateTime,您可以指定应该写入日期/时间的格式)。
Ukadc.Diagnostics附带的文件跟踪侦听器也允许使用令牌系统指定其文件名。