{A}
{S0}目录表
**崭新的新功能
诊断资源管理器是一个。NET库和网站,它允许开发者揭露和查看他们的。NET进程中的任意诊断信息。构造和在内存中。NET对象的属性,可以很容易地暴露,如log4net的框架所产生的日志信息一起观看。我一直在开发和使用资源管理器在过去的5年,在生产系统中的诊断,监测发现它的宝贵工具。NET进程,并迅速解决问题。
该项目作为一个试图找出Windows服务内发生的事情,我是工作在2005年就开始。服务跑细,当所有的好,但如果出事了,然后广泛的侦查工作需要诊断的问题。唯一的问题,可以问的Windows服务quot;是它运行?quot;
各种日志框架存在,如log4net的和微软的日志应用程序块,和性能计数器可以用来揭露某些类型的数据的性能指标。我发现现有的技术,机构臃肿,所以我写了一个简单的网站,它使用了远程接口,以获取并显示从Windows服务的键/值属性的集合。该项目的发展,因为我意识到如何使该技术更通用,几种技术(远程的HTML,AJAX的WinForms,WPF中,并最终WCF / Silverlight的),资源管理器诊断结果。
任何。NET过程中,可以公开引用DiagnosticExplorer.dll大会诊断。该程序集包含的所有要求,以使您的应用程序出现在上图中的Silverlight浏览器,并从任何托管。NET对象,你想公开的属性。
首先,应用程序使用DiagnosticHostingService类主机可以请求诊断的属性,值和日志消息从WCF服务。服务可以被配置为使用特定的端口,或一个随机的免费端口号(见下面暴露诊断)。
二,您的应用程序使用DiagnosticManager类注册。NET对象,其属性将暴露,EventSink的类或日志框架(见下面使用log4net的)揭露日志消息。
当您选择您在Silverlight浏览器的应用程序,WCF服务托管您的应用程序轮询每一秒,以便检索和显示诊断信息。注册
诊断Web服务保持一个所有注册的应用程序列表(实际上,一个文件夹结构)。当您的应用程序启动时,如何诊断的Web服务知道它正在运行,它的端点地址是什么?有两种选择:一个在Silverlight浏览器的右键单击上下文菜单可让您手动注册的应用程序提供其名称和端点地址。对于这项工作虽然,应用程序必须使用固定的端口号。可配置DiagnosticHostingService注册自己的名称和诊断的Web服务端点地址。如果使用一个随机端口号,这是强制性的。{A32}
两行代码(加少许配置)都需要开始暴露在自己的应用程序的诊断。您必须首先引用DiagnosticExplorer.dll和使用DiagnosticHostingService.Start()和DiagnosticHostingService.Stop()方法。这个类是负责为托管WCF服务和诊断的Web服务注册:using DiagnosticExplorer;
...
public Form1()
{
InitializeComponent();
DiagnosticHostingService.Start();
FormClosed += StopDiagnostics;
}
private void StopDiagnostics(object sender, EventArgs e)
{
DiagnosticHostingService.Stop();
}
,如果DiagnosticHostingService是注册本身,它必须知道如何联系诊断的Web服务:{C}
可选配置部分可用于自定义DiagnosticHostingService的行为:<configuration>
<configSections>
<section name="diagnosticExplorer"
type="DiagnosticExplorer.DiagnosticSectionHandler,
DiagnosticExplorer" />
</configSections>
<diagnosticExplorer>
<!-- Used to differentiate between multiple instances -->
<!-- of the same application running on a machine (optional) -->
<instanceName>Dev</instanceName>
<!-- Auto or Manual port number selection -->
<portMode>Auto</portMode>
<!-- Port to use when portMode is Manual -->
<port>12345</port>
<!-- True if this application should register
itself with the diagnostics web service -->
<autoRegister>true</autoRegister>
</diagnosticExplorer>
</configuration>
当你运行你的应用程序和DiagnosticHostingService已经开始,一些有限的系统信息已经在Silverlight浏览器可见。
{A33}
当暴露在IIS中承载Web应用程序的诊断,DiagnosticHostingService可以在Global.asax的Application_Start和Application_End方法正常使用,或者,您可以添加一个WCF服务到您的应用程序和手动注册的URL。WebDiagnostics.svc诊断Explorer的Web服务(在下载DiagnosticWeb文件夹)复制文件。把这个在自己的Web应用程序的某处(有没有代码隐藏)。复制服务的WCF配置的LT; system.serviceModelgt;在web.config中的部分。你将需要:LT; servicesgt; LT;服务名称="WebDiagnosticsquot; ...LT; behaviorsgt; LT; serviceBehaviorsgt; LT;行为名称= quot; WebDiagnosticsquot; ...LT; bindingsgt; LT; wsHttpBindinggt,LT绑定的名称"; WebDiagnosticsquot ...检查,您现在可以浏览到您的浏览器中键入URL到新的服务,例如:http://localhost/MyWebApp/WebDiagnostics.svc。在诊断资源管理器的Silverlight浏览器,右键单击在左侧面板,并选择"注册Processquot;键入一个名称和您的WebDiagnostics服务的URL。{A34}
这是很容易开始公开自己的信息使用DiagnosticManager.Register(OBJ,名称,类别)方法。只需选择一个对象,你认为有一些有趣的性质,并注册:public partial class Form1 : Form
{
private SomeClass myObject;
public Form1()
{
InitializeComponent();
DiagnosticHostingService.Start();
FormClosed += (sender, e) => DiagnosticHostingService.Stop();
myObject = new SomeClass();
DiagnosticManager.Register(myObject,
"My Object", "My Category");
}
class SomeClass
{
public string MyProp1 { get { return "A Value"; } }
public string MyProp2 { get { return "A Different Value"; } }
}
}
当你运行的应用程序,Silverlight的浏览器现在应该看起来像这样:
{S2}
需要注意的是要保持与DiagnosticManager您注册任何对象的引用。这是因为DiagnosticManager只拥有一个WeakReference对象的,所以不会阻止垃圾收集。这有助于避免内存泄漏,否则可能发生,并消除了需要调用DiagnosticManager.Unregister(MyClass的)。相反,你注册的对象从Silverlight浏览器会消失,只要它被垃圾收集。{A35}
新增的[属性(AllowSet = TRUE)]属性以上的任何财产,这将是从诊断管理器进行编辑。或者,您可以指定类中的所有属性应用编辑[DiagnosticClass(AllPropertiesSettable = TRUE)]以上类声明的属性。可编辑的属性显示一个蓝色的前景。
诊断资源管理器将尝试使用Convert.ChangeType设置属性。如果失败,一个静态Parse(String)方法上存在的属性类型,将被调用。否则,一个错误信息显示给用户。[Property(AllowSet = true)]
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged("Name");
}
}
{S3}{A36}
沽[DiagnosticMethod]上述任何属于任何对象,可见,在诊断和旁边会显示一个黄色的明星的方法。现在,您可以点击并调用任何注册的方法。[DiagnosticMethod]
public string SayHelloSync(string caption, string message)
{
if (message == "throw")
throw new ArgumentException("Ok, I'll throw");
Stopwatch watch = Stopwatch.StartNew();
Action sayHello = () => MessageBox.Show(this, message, caption,
MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
Invoke(sayHello);
return string.Format("User clicked Ok in {0:N1} seconds", watch.Elapsed.TotalSeconds);
}
{S4}的{A37}
通过Silverlight浏览器暴露事件的方式有两种。使用的EventSink
第一种方式是直接从代码中使用的EventSink类。如果如上添加以下代码添加到Form1,Silverlight的浏览器应该是这个样子的:
{五}
使用log4net的private EventSink mySink;
...
mySink = EventSink.GetSink("My Events", "My Category");
mySink.LogEvent(EventSeverity.Low, "Low severity issue",
"Low severity detail");
mySink.LogEvent(EventSeverity.Medium, "Medium severity issue",
"Medium severity detail");
mySink.LogEvent(EventSeverity.High, "High severity issue",
"High severity detail");
的首选和更灵活的方法,但是,是用一个如log4net的日志框架:using log4net;
...
ILog log = LogManager.GetLogger(typeof(Form1));
log.Info("This is an INFO level log message");
log.Warn("This is a WARN level log message", myException);
log.Error("This is an ERROR level log message\n", myException);
在log4net配置文件,您必须添加一个appender的类型DiagnosticExplorer.Log4Net.DiagnosticAppender和配置所需SinkName和SinkCategory。这个appender使用的EventSink类log4net框架的指示时,记录一个事件。
{A38}<appender name="DiagnosticExplorer_Form1"
type="DiagnosticExplorer.Log4Net.DiagnosticAppender, DiagnosticExplorer">
<SinkName>My Events</SinkName>
<SinkCategory>My Category</SinkCategory>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</appender>
我知道有可怕的安全隐患在允许编辑属性和调用方法(潜在生产)过程暴露诊断。我将在我的下一个版本中解决这一扩大的安全漏洞。{A39}
在运行诊断资源管理器,确保你已经安装了{A40}。{A41}创建一个Web应用程序调用IIS诊断的基础上DiagnosticWeb在示例下载文件夹。如果你是工作的源代码,这是DiagnosticExplorer.Web解决方案中的项目。检查,你可以浏览到(本地主机推定):http://localhost/Diagnostics/RegistrationService.svchttp://localhost/Diagnostics/Diagnostics.svchttp://localhost/Diagnostics/WebDiagnostics.svc检查,您可以通过Silverlight的浏览器,浏览到:http://localhost/Diagnostics/Default.aspx{A42}
编辑App.config文件提供WidgetSample。这是WidgetSample \ WidgetSample.exe.config在示例下载,否则WidgetSample项目。确保注册服务的客户端的端点地址是正确的。运行WidgetSample。在Silverlight的浏览器的外观和验证的示例应用程序出现。如果没有,运行{A43}看到,如果有任何错误报告,并从那里排查。{A44}
这部分多一点,最后两个步骤困难。我们要实现的是储存的记录,使他们可以检索和复古的Silverlight播放器"选项卡中显示的事件。
,这将有可能插入记录到数据库中的事件直接写一个log4net的appender的。我不希望我追加写入到数据库中,但是,所以我有一个appender在MSMQ写入一个WCF服务。一个Windows服务,然后从队列中读取消息,从诊断Web服务可以阅读它们,使用一个NetMsmqBinding的,并将其插入到数据库。
这听起来像一个示例应用程序太多的故障点,但这里有云:创建数据库和消息队列创建一个名为诊断数据库。该脚本CreateDatabase.sql是包含在解决方案和示例下载。创建事务性消息队列称为诊断。确保它的权限,以便在log4net的示例应用程序的appender可以写,并在下一步的Windows服务可以读。安装Windows服务使用installutil.exe安装诊断Explorer的Windows服务。确保Windows服务配置文件包含了正确的数据库连接字符串,正确的MSMQ路径在LT; system.serviceModelgt;部分,RegistrationService端点是正确的。从服务控制面板,开始诊断的资源管理器服务。检查Windows服务注册本身在使用Silverlight浏览器的诊断。配置和运行WidgetSample检查在WidgetSample log4net.xml配置文件。确保LT;文献的appender - REF ="MsmqLoggerquot; / GT;没有被注释掉。它被配置为使用LoggingService_MSMQ端点,以便核实LoggingService_MSMQ端点在App.config中正确的队列路径。运行WidgetSample和验证,它出现在Silverlight浏览器。通过点击一些按钮,生成的几个事件。验证Windows服务是成功地从消息队列中读取事件。您可以通过查询数据库,或在Silverlight浏览器查看Windows服务。查看"Retroquot;诊断确保Web.config中的数据库连接字符串在Web应用程序是正确的。选择在Silverlight浏览器的复古标签,然后点击"刷新"按钮。如果一切顺利,你应该看到已记录到数据库中的事件。
注意,如果你要提供你自己的方式坚持和检索事件,可以实现ILogWriter和ILogReader发现DiagnosticExplorer.dll。的Windows服务和Web应用程序的bin目录内放置你自己的实现,并相应地改变的App.config和Web.config文件:{A45}{A46}
如果你有一个类,它包含了一些有趣的静态属性,你可以注册它就像你将一个对象的实例。
{中六}
{A47}DiagnosticManager.Register(typeof(MyClass),
"Static Stuff", "My Category");
...
public class MyClass
{
public static string Hello { get { return "World"; } }
public static string Goodbye { get { return "Cruel World"; } }
}
要停止暴露在诊断特定的属性,使用忽略= TRUE PropertyAttribute。另外,使用[可浏览(假)]属性。
{七}
{A48}class SomeClass
{
public string MyProp1 { get { return "I'm not ignored"; } }
//Won't be visible in diagnostics
[Property(Ignore = true)]
public string MyProp2 { get { return "I am ignored"; } }
}
使用DiagnosticClassAttribute,您可以指定其中明确PropertyAttribute或[可浏览(真)]显着的唯一属性,应在诊断暴露。
{S8}
{A49}[DiagnosticClass(AttributedPropertiesOnly = true)]
class SomeClass
{
[Property]
public string MyProp1 { get { return "I am attributed :)"; } }
//Won't be visible in diagnostics
public string MyProp2 { get { return "I'm not attributed :("; } }
}
如果您诊断类是一个子类,你不希望任何继承的属性显示,使用[DiagnosticClass(DeclaringTypeOnly = TRUE)]属性。请注意,如果超类使用此属性,那么它的属性将暴露的子类。public class Class1
{
[Browsable(true)]
public string PropA
{ get { return "I'm not exposed despite being browsable"; } }
}
[DiagnosticClass(AttributedPropertiesOnly = true, DeclaringTypeOnly = true)]
public class Class2 : Class1
{
[Browsable(true)]
public string PropB { get { return "I am exposed"; } }
[Property]
public string PropC { get { return "I am exposed too"; } }
public string PropD { get { return "I'm not exposed (no attribute)"; } }
}
PropertyAttribute可以被用来定制你想要的属性被暴露。
{S9}class SomeClass
{
public string MyProp1 { get { return "A Value"; } }
[Property(Name = "Alternate name",
Category = "Some Category",
Description = "This appears in the tooltip",
FormatString = "Value is: {0:N3}")]
public double MyIntValue { get { return 12345.6789; } }
}
注意ComponentModel属性分类(quot;一些Categoryquot;)]和[描述("这似乎在tooltipquot)]也可以被使用。{A51}
变成一个字符串对象的属性时的默认行为是使用Convert.ToString或string.Format格式字符串指定。这本身是复杂的对象的属性,这种行为可以与ExtendedPropertyAttribute修改。
{S10}
{A52}class SomeClass
{
public string MyProp1 { get { return "A Value"; } }
[ExtendedProperty]
public Person SomePerson{ get; set; }
}
集合属性可以显示诊断。默认情况下,下面的代码看起来像这样的诊断:
{S11}class SomeClass
{
public string MyProp1 { get { return "A Value"; } }
//Contains 12 items
public IList<Person> People { get { return _myListOfPeople; } }
}
class Person
{
public string Name { get; set; }
public int Height { get; set; }
public string Nationality { get; set; }
public override string ToString()
{
return string.Format("{0}, {1}cm, {2}", Name, Height, Nationality);
}
}
应用CollectionPropertyAttribute集合属性,可用于自定义如何显示集合。请点击下面的链接看到属性如何影响行为。
[CollectionProperty(CollectionMode.Count)]
{S12}
[CollectionProperty(CollectionMode.Count的FormatString = quot;有{0:N2} peoplequot;)]
{S13}
[CollectionProperty(CollectionMode.List)]
{S14}
[CollectionProperty(CollectionMode.Concatenate,分隔符= quot; - >",MaxItems = 3)]
{S15}
[CollectionProperty(CollectionMode.Concatenate,分离的FormatString =" - >",MaxItems = 2,=({0}";人)quot;)]
{S16}
[CollectionProperty(CollectionMode.List,分类= quot;我Peoplequot; NameProperty = quot; Namequot;)]
{S17}
[CollectionProperty(CollectionMode.Categories)]
{S18}
[CollectionProperty(CollectionMode.Categories CategoryProperty = quot; Namequot,分类= quot; Peoplequot;)]
{S19}{A53}
作为一个捕捉事件的发生率在您的代码的援助,RateCounter类提供。这就像一个重量轻的性能计数器,它暴露了诊断的秒数接收到的信号数的平均。
下面的代码看起来在诊断时这样:
{S20}
如果你的注释的RateProperty属性,它看起来像这样:
{S21}{A54}
当尝试远程解决一个问题,它会很高兴知道如何执行的代码是:哪些方法被调用,以何种顺序,有什么重要的事情正在发生,并且它是所有服用多少时间。您可以登录事件和检查的辐射,但是当你有多个操作,同时,这是特别困难。也许你有多个线程都运行相同的代码,你必须以某种方式确定属于哪个线程日志消息。
为了解决这个问题,我已在DiagnosticExplorer.dll称为TraceScope一类。它是一个类,设置一个线程静态quot; ambientquot;范围收集跟踪信息。它应该始终使用块构造如下图所示,一个Actionlt; stringgt;可以传递给构造。 TraceScope是处置时,它创建的字符串表示形式的跟踪收集到的信息传递给它Actionlt; stringgt;
您可以调用静态方法TraceScope.Trace("我的调试messagequot;)在任何大会的任何地方,如果有一个环境TraceScope,该邮件将被追加到它。如果您创建一个TraceScope,已经有一个环境TraceScope,将被嵌套的范围。
考虑下面的代码,并采取在看TraceScopeExample类是引用。 {A55}:private static ILog _formLog = LogManager.GetLogger(typeof (Form1));
private void btnTraceScope_Click(object sender, EventArgs e)
{
using (new TraceScope(_formLog.Info))
{
TraceScope.Trace("In Trace Scope Button Click");
TraceScopeExample.TestTraceScope1();
}
MessageBox.Show("Just generated a trace scope. Check diagnostics.");
}
TraceScope输出的路径,你的代码通过各种范围和所有跟踪收集消息一路上缩进的文本表示。你在方括号中的数字创建以来最外层的范围的总时间和经过时间以来的最后一丝消息。
的Silverlight浏览器认识到,当一个日志消息中包含的一个TraceScope结果。解析它提供了用户友好的显示,并试图突出了大部分时间的执行路径。你可以看到它是如何在观众看起来。
{S22}
我认为它可以改善,所以任何想法欢迎。{A56}
Web.config文件包含一些自定义设置。<appSettings>
<-- Time after which Auto registered processes renew their registrations -->
<add key="RenewTime" value="00:00:20" />
<-- The frequency (ms) at which the Silverlight Viewer polls a process -->
<add key="PollTime" value="1000" />
<-- The frequency (ms) at which the Silverlight Viewer
refreshes the process menu -->
<add key="MenuRefresh" value="2000" />
<!-- The implementations of ILogReader and ILogWriter
which are used to read and write "retro" events -->
<add key="ILogReader" value="DiagnosticExplorer.SqlLoggingService,
DiagnosticExplorer.Common" />
<add key="ILogWriter" value="DiagnosticExplorer.SqlLoggingService,
DiagnosticExplorer.Common" />
</appSettings>
PollTime和MenuRefresh,这些设置,可重写的URL http://localhost/Diagnostics/Default.aspx?PollTime=1500amp; MenuRefresh = 5000。{A57}
虽然我提到,该系统是在生产环境中使用,这里介绍的是版本的第一个版本使用与Web服务的WCF,自动端口选择,并自注册。 。NET Remoting的是在以前的版本,用于通信,端口选择手动,您必须手动更新一个XML文件来注册应用程序。这有缺点未能启动同一进程的多个实例,作为率先启动该端口将被。
在复古"选项卡上有一个小错误不起作用,如果你在网格中的项目之一点击"刷新"按钮。
源代码托管在{A58}。如果你是在所有有兴趣的和有一些想法,我会欢迎的贡献者。{A59}二零一零年三月四日最初版本。三月十四日,2010年:一些变化作了明确使用MSMQ的删除日志消息:删除MessageQueueAppender log4net的appender的。它已被使用了WCF ILogWriter服务LoggingServiceAppender,所以你现在可以使用任何你想您的应用程序和日志服务之间的运输。复古的功能,必须为创建消息队列必须是事务性队列。已取代ILogReader和ILogWriter IEventIO接口。二零一零年三月二十八日转换到Visual Studio 2010的Silverlight 4 RC。新增支持ComponentModel属性:BrowsableAttribute的CategoryAttribute,DescriptionAttribute。2010年10月,24日转换为Silverlight工具包2010年4月。改进的上下文菜单。改进的重命名和新注册的弹出窗口。包裹LoggingServiceAppender的Send方法与新的TransactionScope(TransactionScopeOption.Suppress)停止交易的干扰。修正了几个轻微的UI错误。2010年11月7日,暴露在Web应用程序的诊断,改进的支持和文档。残疾人拖/放左手树Silverlight工具包树随机启动拖动操作。 (重新启用上下文菜单。)Recut我所有的图像,使它们无法调整大小,在CodeProject希望。2010年11月,27日现在,您可以编辑属性和诊断资源管理器调用方法!右侧的标签现在改变颜色,当事件到达。
| cameron_elliot