65.9K
CodeProject 正在变化。 阅读更多。
Home

C#/.NET 中 XML 日志记录错误

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.63/5 (8投票s)

2002 年 10 月 24 日

2分钟阅读

viewsIcon

188565

downloadIcon

1039

如何将使用 Console.Error 产生的错误全部写入 XML 文件。

引言

和许多其他程序员一样,我在代码中使用大量的 try...catch 语句来捕获异常,帮助调试,并避免崩溃。 因此,我在 catch 块中使用了大量的 Console.Error.WriteLine(...) 来跟踪发生的异常。 但是,即使在发布应用程序时,也不应该再发生异常,但始终拥有某种系统来跟踪引发的异常仍然很有用。 以下代码演示了一种将这些异常跟踪记录到 XML 文件中的解决方案。

ErrorLogWriter 类

该类继承了标准的 System.IO.TextWriter 类。 继承 TextWriter 允许我们使用自定义的 ErrorLogWriter 类与 Console.Error 一起使用。
诀窍是创建一个 ErrorLogWriter 实例,然后调用 Console.SetOut(...),并将此实例作为参数传递。
然后,每个 Console.Error.WriteLine(...) 调用都将被重定向到我们的 ErrorLogWriter 实例,并在文件中添加一个 XML 条目。
我尽量使代码保持尽可能简单。 因此,可以添加许多功能,例如处理更多的 TextWriter.Write 方法或在 ErrorLogWriter.WriteLine 函数中提供更多信息。
为了使本文更有价值,我还提供了一种使用堆栈跟踪和反射来获取调用类和方法的方法。 我还在 ErrorLogWriter.WriteLine 函数中添加了一个属性,以在多线程程序中对其进行同步(相当于 lock(this) 关键字)。

using System;
using System.IO;
using System.Xml;
using System.Text;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace ErrorLogger.Utility{
    /// <summary>
    /// ErrorLogWriter class
    /// </summary>
    public class ErrorLogWriter:TextWriter{
        // Variables
        private bool Disposed;
        private XmlTextWriter Writer;

        // Constructor
        public ErrorLogWriter(string FilePath){
            Disposed=false;
            Writer=new XmlTextWriter(FilePath,Encoding.Unicode);

            // Write header
            Writer.Formatting=Formatting.Indented;
            Writer.WriteStartDocument();
            Writer.WriteStartElement("error");
            Writer.Flush();
            }

        // Destructor (equivalent to Finalize() without the need to call base.Finalize())
        ~ErrorLogWriter(){
            Dispose(false);
            }

        // Free resources immediately
        protected override void Dispose(bool Disposing){
            if(!Disposed){
                if(Disposing){
                    }
                // Close file
                Writer.Close();
                Writer=null;
                // Disposed
                Disposed=true;
                // Parent disposing
                base.Dispose(Disposing);
                }
            }

        // Close the file
        public override void Close(){
            // Write footer
            Writer.WriteEndElement();
            Writer.WriteEndDocument();
            Writer.Flush();
            // Free resources
            Dispose(true);
            GC.SuppressFinalize(this);
            }

        // Implement Encoding() method from TextWriter
        public override Encoding Encoding{
            get{
                return(Encoding.Unicode);
                }
            }

        // Implement WriteLine() method from TextWriter (remove MethodImpl attribute for single-threaded app)
        // Use stack trace and reflection to get the calling class and method
        [MethodImpl(MethodImplOptions.Synchronized)]
        public override void WriteLine(string Txt){
            Writer.WriteStartElement("event");
            Writer.WriteStartElement("time");
            Writer.WriteString(DateTime.Now.ToLongTimeString());
            Writer.WriteEndElement();
            Writer.WriteStartElement("class");
            Writer.WriteString(new StackTrace().GetFrame(2).GetMethod().ReflectedType.FullName);
            Writer.WriteEndElement();
            Writer.WriteStartElement("method");
            Writer.WriteString(new StackTrace().GetFrame(2).GetMethod().ToString());
            Writer.WriteEndElement();
            Writer.WriteStartElement("text");
            Writer.WriteString(Txt);
            Writer.WriteEndElement();
            Writer.WriteEndElement();
            Writer.Flush();
            }
        }
    }

测试类

以下是如何使用 ErrorLogWriter 类的一个示例。 当然,所有这些代码都可以在 zip 文件中找到。

using System;
using System.IO;
using ErrorLogger.Utility;

namespace ErrorLogger{
    /// <summary>
    /// Testing class
    /// </summary>
    class Test{
        /// <summary>
        /// Main loop
        /// </summary>
        [STAThread]
        static void Main(string[] args){
            // Here is the magic (file in .exe current directory)
            ErrorLogWriter Err=new ErrorLogWriter(Directory.GetCurrentDirectory()+@"\Error.xml");
            Console.SetError(Err);

            // Testing
            Console.Error.WriteLine("Here is my first error !");
            Console.Error.WriteLine("I should write this inside a catch(exception) statement...");
            // Inside another function
            newFunction();

            // Close error file
            Err.Close();

            // Wait for key
            Console.Out.WriteLine("Error file created. Press a key...");
            Console.Read();
            }

        // Just for the test
        private static void newFunction(){
            Console.Error.WriteLine("Look ! I am inside a function !");
            }
        }
    }

结论

我希望这篇文章能帮助一些人,并对某人有所用。
这里有一些基本概念,可以帮助你理解如何继承 TextWriter 类,如何重定向标准的 Console.Error 流,以及有关反射和堆栈跟踪的一些技巧。
还值得补充的是,你可以自定义此代码以重定向其他流,例如 Console.InConsole.Out

编码愉快!!!

© . All rights reserved.