帮酷LOGO
0 0 评论
文章标签:log  错误日志  


Sample Image - NotSoSimpleErrorLog.gif

内容

简介

本文是一个基于XML简单的错误日志( Error )的重构。 但是在这个版本中,我做了很多更改,所以我宁愿使用新的文章而不是更新。 基本思想是,将应用程序中发生的异常记录到XML文件中。 主要区别如下:

  • 所有异常都作为来自命名空间 DNH.Common的基本异常 DNHCommonException的衍生记录。 我将在本文的后面详细介绍它。
  • ErrorLog 在日志记录中提供了更多选项:
    • 单个文件
    • 每小时单个文件
    • 每天单个文件
    • 每个异常单个文件
  • 为了提高性能和减少内存消耗,日志记录的实际代码被完全重写。 同样,我将介绍本文中的优化。
  • ErrorLog 带有预先创建的XSLT转换。
  • ErrorLog 现在是线程安全的。
  • 日志格式是通过 XML Schema 描述的。
  • 异常本身现在为XML提供了实际格式。
  • DNH.Common.Errors 提供错误通知( 将在以后讨论通知事件和通知提供程序)的方法。
  • ErrorLogError 事件。

正如你所看到的,主要关注的是可以伸缩性和合理性能,所以我相信这篇文章。

你能学到什么

本文提供了一些有关如何执行以下操作的示例:

  • 有效地附加到大型XML文件中。
  • 设计插件架构( 好吧,我想要一些反馈)。
  • 使用 System.Web.Mail 中的类发送邮件。
  • System.Xml 转换中使用XSLT支持转换XML文件。
  • 使用 System.Xml.XPath 命名空间中的类有效地查询XML文件。
  • 引发和处理事件。

图书馆

ErrorLog 是我的库 DNH.Common的一部分。 这个图书馆除了完成的项目外,别担心。 最有可以能的( 90%机会) 我不会改变它的接口,以便在这里提供的日志解决方案。 图书馆的基本部分是 DNH.Common.Dll。 在这里程序集中,有一个非常重要的类和接口。 类称为 DNHCommonException,该接口为 IOutputAsXml

IOutputAsXml接口

这个接口的NAME 表示,实现 IOutputAsXml的类提供了某种XML输出。 这个系统的一点是你不关心这些类的XML表示。 你把它们扔到 IOutputAsXml。 以下是 C# 中的外观:

///<summary>/// Provides XML output for objects implementing this interface.///</summary>publicinterface IOutputAsXml
{
 ///<summary>/// Returns XML representation of this object.///</summary> XmlDocument ToXml();
 ///<summary>/// Gets or sets XML Schema for result of ToXml() method.///</summary> System.Xml.Schema.XmlSchema Schema{get;set;}
}

这是个典型的用法:

// MyObject.csclass MyObject:IOutputAsXml
{
 // TODO: constructor etc..privatestring _value;
 public XmlDocument ToXml()
 {
 XmlDocument doc = new XmlDocument();
 XmlDeclaration declaration = 
 doc.CreateXmlDeclaration("1.0","UTF-8","yes");
 XmlElement root = 
 doc.CreateElement(null,"root",this.Schema.TargetNamespace);
 root.InnerText = this._value;
 doc.AppendChild(declaration); 
 doc.AppendChild(root);
 return doc; 
 }
}// ThisUseMyObject.cs...
XmlDocument doc = myObject.ToXml();
doc.Save("myObject.xml");
...// myObject.xml// assuming myObject._value had value"myValue"<?xml version="1.0" encoding="UTF-8" standalone="yes"?><root>myValue</root>

这里时,你可以看到可以为成员调用 ToXml(),因这里可以轻松地表示XML中的复合对象。

IOutputAsXml和序列化函数之间的区别

在. NET 中,单词序列化的意思是: "序列化可以定义为将对象实例的状态存储到存储 medium的过程。 在此过程中,对象的public 和 private 字段以及类的NAME ( 包括包含类的程序集) 将转换为字节流,然后将它的写入到数据流中。 对象随后反序列化时,原始对象的精确克隆被创建"另一种方式,IOutputAsXml 允许实现程序提供 *some* XML表示形式,也不要求是精确克隆。 把它当作通用 object.ToString() 方法的XML替代。

DNHCommonException类

DNHCommonExceptionSystem.Exception 派生并实现 IOutpuAsXml 接口。 DNHCommonException 提供只读属性 DNHCommonExceptionType ExceptionType 返回 DNHCommonExceptionType的成员。 可能的值及其含义为:

///<summary>/// Represents types of exception severity.///</summary>publicenum DNHCommonExceptionType
{
 ///<summary>/// Identifies general errors, like IO/missing files, wrong format, timeouts. ///This is default value.///</summary> Error = 0,
 ///<summary>/// Identifies fatal errors, like null referece, etc.///</summary> FatalError = 1,
 ///<summary>/// Identifies security errors, like insufficient permisson.///</summary> SecurityError = 2,
 ///<summary>/// Identifies unhandled exception.///</summary> UnhandledError = 3}

可以在异常重载的构造函数中指定错误的类型。 显然,这里信息包含在实际的日志文件中。

XML Schema

你可以在这里找到基本的DNHCommon.DNHCommonException,这里有。

错误日志

此类实现对XML文件的实际写入。 日志记录有几个"模式",有时编写XML的技术也不同。 ErrorLog 公开了两个事件:ErrorNotification。 第一个事件在 ErrorLog 日志异常之前激发,第二个事件在发送通知之前激发。

注意:在当前实现中,两个事件在记录异常之前激发,但这可能在将来发生更改。 规则是在异常日志记录之前触发 Error事件,并在发出通知之前触发通知事件,但不会发出错误通知通知事件的。

将错误信息保存到文件时发生的情况取决于日志记录模式。 在 oneExceptionFile 模式下,保存是按以下方式进行的:

// create new documentXmlDocument doc = new XmlDocument();
doc.LoadXml(this.ToXml().OuterXml);
XmlDocumentFragment frag = doc.CreateDocumentFragment();
frag.InnerXml = e.ToXml2().OuterXml;
doc.DocumentElement.AppendChild(frag);
doc.Save(tempLogName);

不可能更简单。 一个条目是相对较小的XML,因此使用 XmlDocument 没有什么大的问题。

不同的情况是我们使用"附加"模式之一。 在这种情况下,XML文件增长,你可以很容易地获得数MB或者更大的文件。 是时候用不同的方法了。 在我的代码中,你可以找到这里方法:

privatevoid Append(string path, DNHCommonException e)
{
 StreamWriter sw = File.AppendText(path);
 XmlTextWriter xtw = new XmlTextWriter(sw);
 xtw.WriteRaw(e.ToXml2().OuterXml);
 xtw.Close();
}

基本上,它将XML追加到纯文本文件中。 XML甚至没有 root 元素,因此不能直接使用。 相反,我使用高效技术中描述的技术来修改大型XML文件。 点正在使用 IO API,它比使用 XmlReader/XmlWriter 或者( 更糟糕) XmlDocument 要快得多。 现在有了问题:好的,我们有像纯文本文件这样的xml。 如何利用XSLT的所有优点( 等等 ) 生成"常规"xml文件? 答案是- 实体与文本文件一起,有如下所示的XML文件:

<?xmlversion="1.0"encoding="UTF-8"standalone="no"?><!doctypeerrorlog[<!ENTITYlogSYSTEM"log.txt">]><errorlogxmlns="http://dnhsoftware.org/schemas/dnhcommon/ErrorLog.xsd">&log;</errorlog>

在文档类型定义中可以看到,&log; 引用外部实体,在本例中是文本文件 log.txt。 XML阅读器可以扩展XML文件读取我们的XML文件,它将 log.txt 到我们的XML文件中。 因此,在结果中,当你对它调用XSTL转换时,结果包含所有标记- 甚至是 log.txt。

NotificationProviderBase类

NotificationProviderBase的通知提供程序的基类( 令人惊奇)。 它有一个功能:

publicabstractvoid Send(DNHCommonException ex);

如果要发送错误通知,则调用这里函数( 比如。 你想发送电子邮件给管理员,并告诉他访问DB失败或者类似于。 配置文件中描述的规则。如何以及如何发送通知。 DNH.Common.Errors 有一个 NotificationProviderBase 实现,EmailNotificationProvider 在组装 DNH.Common.Errors.Providers.EmailNotificationProvider.dll。 你可以看看它是如何写的( 源包含在库中)。 实际上,Send()的重写非常简单:

///<summary>/// Sends notification.///</summary>publicoverridevoid Send(DNHCommonException ex)
{ 
 if(this._smtpServer!= null)
 {
 SmtpMail.SmtpServer = this._smtpServer;
 }
 SmtpMail.Send(message);
}

ErrorLogConfig类

ErrorLogConfig,就像 NAME 所说,为库文件的配置提供了 API。 虽然 System.Configuration 命名空间有类,但它们不满足我的需要,所以我编写了类,以便提供API我需要。 它内部使用 System.Xml.XPath.XPathDocument 读取配置文件。 谈到 XPath 文档,在. NET 框架中有效地使用XML还有另一个规则: 如果你不希望对XML文档进行收费,那么不要使用 XmlDocumentXmlDocument 对于XML文件中的xpath quering ( 选择节点) 使用它是比较重要的,而且它是内存/性能过于。 使用 XPathDocument

配置文件格式

<?xmlversion="1.0"encoding="utf-8"?><configuration><!-- 
 List of exceptions.
 Add new exception here.
 --><exceptions><exceptiontype="DNH.Common.DNHCommonException"><targetname="boss"/><targetname="admin"/></exception></exceptions><!-- List of notifications.
 Add new notification here.
 --><notifications> 
 <notificationtarget="admin@example.org"nick="admin"><providername="Email"/> 
 </notification><notificationtarget="boss@contozo.com"nick="boss"><providername="Email"/></notification></notifications><!-- 
 List of notification providers.
 Add new notification provider here.
 --><providers><providername="DNH.Common.Errors.Providers.EmailNotificationProvider"nick="Email"/> 
 </providers></configuration>

我希望这种结构足够直观。 通常,存在一个长的异常 List,目标和提供者的List 较短。

ErrorLogFormatter类

这是一个 helper 类,它有一个方法:

publicstaticvoid FormatErrorLog(string inFile, string outFile, 
 String StyleSheetURI)

这里方法将 XSLT 转换(。StyleSheetURL 参数是 .xslt 文件的URL ) 应用到文件 inFile,并将结果保存为 outFile。 demo predefined predefined predefined files log2html.xslt log2txt.xslt。 第一种格式将XML格式化为漂亮的HTML,第二种格式为旧的纯文本格式。 当然,如果知道 XSLT,你可以提供自己的格式。 实现类似于:

///<summary>/// Formats error log with given xslt transformation and saves result in file.///</summary>///<paramname="inFile">Input XML file.</param>///<paramname="outFile">Output file.</param>///<paramname="StyleSheetURI">URI to stylesheet.</param>publicstaticvoid FormatErrorLog(string inFile, string outFile, String StyleSheetURI)
{
 XslTransform transform = new XslTransform(); 
 transform.Load(StyleSheetURI);
 XmlWriter outWriter = new XmlTextWriter(outFile,System.Text.Encoding.UTF8);
 XmlDocument myDoc = new XmlDocument();
 XmlValidatingReader vr = new XmlValidatingReader(new XmlTextReader(inFile));
 vr.EntityHandling = EntityHandling.ExpandEntities;
 vr.ValidationType = ValidationType.None; 
 myDoc.Load(vr);
 XmlUrlResolver myResolver = new XmlUrlResolver(); 
 myDoc.XmlResolver = myResolver;
 transform.Transform(myDoc,null,outWriter,myResolver);
 outWriter.Close();
}

示例

最后一件事:如何真正使用 ErrorLog? 你可以声明/创建 ErrorLog的新实例,如下所示:

public ErrorLog log;
log = new ErrorLog("logs/log.xml");

比你能打电话 ErrorLog.SaveExceptionToLog(Exception ex)try-catch 块中的方法。

try{ 
 InfinityRulez(); 
}catch (Exception ex)
{
 log.SaveExceptionToLog(ex);
}

如果要在调用 ErrorLog.SaveExceptionToLog() 方法时执行自定义操作( 比如 显示错误页),则可以像这样 register 事件 Error:

privatevoid InitializeComponent()
{
 this.log.Error += new ErrorLogErrorEventHandler(log_Error);
. . .

那么你只需要编写 log_Error 处理程序的主体。 你可以使用 register/Notification 事件同样的方式。

有关抛出和处理异常的指导信息,请搜索arraylist或者 MSDN,或者搜索Google或者它的他最喜欢的搜索引擎。 有很多关于这个主题的说明,它将是一个全新文章的材料。 所以我跳过这个部分祈祷你( 读卡机) 会自己调查 !

演示应用程序插件

我已经包含了演示应用程序,所以你可以快速看到我的解决方案。 用户界面和整个应用程序的收费非常简单,它只有一个用途- - 显示日志外观,它是线程安全的等等。 但是有些硬编码路径所以请相信我的文件夹 logs XSLT XSLT XSLT XSLT它们的内容应该是现在的位置。 当然,只有在这个样本中 ! 在实际使用中,你可以根据需要更改所有路径。 但是,配置文件 DNH.Common.Errors.Config 必须位于与程序集 DNH.Common.Errors.Dll 相同文件夹中。 如果你想使用通知提供程序的位置,则它的位置必须与你在文件中写入的位置相同。 这就是,有趣的,我期待着你的Bug 报告,想法和改进 !

待办事项

当然有很多要做的。 :

[TODOs from Simple XML based Error Log ]

  • 当同时发生更多异常时,应处理。 完成了
  • 添加更多信息(。类似于你的应用程序中当前登录用户的信息)。 完成了
  • 使用 XmlDocument 或者 XmlDocumentFragment 可以处理 XML。 更清楚一点没有 !
  • 生成的XML由DTD描述。 预计在下一个版本中使用 XML Schema。 完成了
  • 这一点很困难:自动分析发生的。 但这将是伟大的:

[Current TODOs ]

引用

历史记录

  • 24.4.2005

    文章首次发布到 CodeProject。



文章标签:log  错误日志  

Copyright © 2011 HelpLib All rights reserved.    知识分享协议 京ICP备05059198号-3  |  如果智培  |  酷兔英语