zoukankan      html  css  js  c++  java
  • 设计一个错误处理类库

    上次发了“写一个监测跟踪的类库”的帖子,这次贴错误处理的类库

    上次的帖子地址如下

    http://onlytiancai.cnblogs.com/archive/2005/07/30/203649.html

    其实写这些文章没啥用,就是开拓开拓思路而已,微软已经发布了几个好用的应用程序快,什么blok,我也记不住那些英文。把偶用的错误处理类库贴出来,是让大家批评批评看看有哪些设计不当,考虑不全的地方,大家多多指点一下,比直接用那些现成的东西有收获应该,对吧。

    /*
     * Enumeration : GWExceptionMessages
     * Namespace   : GW.MonitorServices.Logging
     * Assembly    : GW.MonitorServices.Logging
     * Author       : Kevin Hoffman
     * Description : Enumeration containing index values into the string resource containing the standardized error messages
     
    */


    using System;

    namespace GW.MonitorServices.Logging
    {
        
    /// <summary>
        
    /// 这是个保存错误类型的枚举,和ErrorMessages.resx资源文件里的
        
    /// 详细错误描述相对应
        
    /// </summary>

        public enum GWExceptionMessages
        
    {
            DefaultMessage 
    = 1000,
            DbLogFailed 
    = 1001,
            SeeDatabase 
    = 1002,
            PersistenceFailure 
    = 1003
        }

    }


    /*
     * Class       : FileErrorLog
     * Namespace   : GW.MonitorServices.Logging
     * Assembly    : GW.MonitorServices.Logging
     * Author       : Kevin Hoffman
     * Description : Class responsible for logging error information to HTML text files as backup/alternate to DB error logging.
     
    */


    using System;
    using System.Configuration;
    using System.Diagnostics;
    using System.Reflection;

    namespace GW.MonitorServices.Logging
    {

        
    /// <summary>
        
    /// 把错误持久到文本文件的类,这个类用来把错误信息或指定信息记录在一个文本文件里,并
        
    /// 使用HTML格式,方便你查看
        
    /// </summary>

        public class FileErrorLog
        
    {
            
    /// <summary>
            
    /// 设置一个读写锁,防治在操作日志文本文件的时候别人也使用,这样就不会出现并发问题
            
    /// </summary>

            private static readonly System.Threading.ReaderWriterLock errorFileLock =
                
    new System.Threading.ReaderWriterLock();

            
    /// <summary>
            
    /// 一个静态方法,用来把一个异常信息记录下来
            
    /// </summary>
            
    /// <param name="e"></param>

            public static void LogError( Exception e )
            
    {
                LogError( e, 
    string.Empty );
            }


            
    /// <summary>
            
    /// 通过错误消息,引发错误的原始异常来持久化一个错误,这里时挖掘错误详细信息的地方,
            
    /// 这里调用了MonitorUtilities工具函数的一些功能获取发生错误的堆栈等,以及遍历原始异常的内部异常,
            
    /// 取出引发异常的类,方法等来获取发生错误时足够多的信息,并把它持久化
            
    /// </summary>
            
    /// <param name="e"></param>
            
    /// <param name="rootMessage"></param>

            public static void LogError( Exception e, string rootMessage )
            
    {
                GWTrace.EnteringMethod( MethodBase.GetCurrentMethod() );
                rootMessage 
    = ( rootMessage == null ? string.Empty : rootMessage.Trim() );
                Exception originalException 
    = e;

                System.Text.StringBuilder buffer 
    = new System.Text.StringBuilder(4096);
                
    if ( rootMessage.Length > 0 )
                    buffer.AppendFormat(
    "<font color='RED' size=2><b>{0}</b></font><br/>",
                        rootMessage );
                
    while (e != null )
                
    {
                    buffer.AppendFormat(
    "<font color='RED' size=2><b>{0}</b></font><br/>", e.Message );
                    
    if (e.TargetSite != null )
                    
    {
                        buffer.Append(
    "<font size=1>");
                        buffer.AppendFormat( 
    "at method {0}.{1}()<br/>", e.TargetSite.DeclaringType.Name, e.TargetSite.Name );
                    }

                    e 
    = e.InnerException;
                }


                e 
    = originalException;
                buffer.Append(
    "<br><font size=2 color=red><b>Stack Trace:</b></font><br/>\n");
                buffer.Append(
    "<font size=1>\n");
                buffer.Append(MonitorUtilities.ExpandStackTrace(e).Replace(
    "\n""<br>\n"));
                buffer.Append(
    "</font>");

                appendMessageToErrorLogFile( buffer.ToString() );
            }


            
    /// <summary>
            
    /// 通过错误信息,,错误参数来持久化一条消息,这个重载的方法通常用来记录一条人为的信息
            
    /// 比如说谁在什么时候执行了一个什么操作,
            
    /// </summary>
            
    /// <param name="message"></param>
            
    /// <param name="arrParams"></param>

            public static void LogError( string message, params Object[] arrParams )
            
    {
                message 
    = ( message == null ? string.Empty : message.Trim() );
                message 
    = MonitorUtilities.SafeFormat( message, arrParams );
                appendMessageToErrorLogFile( message );
            }


            
    /// <summary>
            
    /// 这个是把错误状态持久化的真正的地方,使用System.IO下的几个类,把传进来的信息保存在文本文件里
            
    /// 这里调用私有函数getAppErrorLogFileName()来获取错误日志文件的位置,下面的英文注释可能是说权限之类
            
    /// 的问题吧,你设置的存放文本日志的地方要让给ASPNET用户有写的权限.因为这是个可能引发异常的方法,所以
            
    /// 要做一些异常处理.System.IO里的几个类都比较熟悉了,就不在多注释了哦
            
    /// </summary>
            
    /// <param name="errorMessage"></param>

            private static void appendMessageToErrorLogFile( string errorMessage )
            
    {
                
    // Note that if the ASPNET account does not have write privileges
                
    // in the directory that you are planning on storing the file-based
                
    // error log, that file will never be created.
                System.IO.StreamWriter errLog = null;
                errorFileLock.AcquireWriterLock(
    10000);
                
    try
                
    {
                    errLog 
    = System.IO.File.AppendText( getAppErrorLogFileName() );
                    errLog.WriteLine(
    "<span style='font-family:Verdana'><font size=2>");
                    errLog.WriteLine(
    "<br/><hr/>\n");
                    errLog.WriteLine(
    "The following error occurred in the application on {0}", System.DateTime.Now);
                    errLog.WriteLine(
    "<hr/>\n");
                    errLog.WriteLine( errorMessage );
                    errLog.Flush();
                    errLog.Close();
                }

                
    catch (Exception ex)
                
    {
                    GWTrace.Trace(
                        TraceLevel.Error, 
    "An error occurred when saving an error to disk: {0}", ex.ToString() );
                }

                
    finally
                
    {
                    errorFileLock.ReleaseLock();
                    
    try 
                    
    {
                        
    if (errLog != null )
                        
    {
                            errLog.Flush();
                            errLog.Close();
                        }

                    }

                    
    catch { }
                }

            }


            
    /// <summary>
            
    /// 获取存放文本日志的位置,先从web.config里后去,如果设置的目录没有的话就创建一个目录,如果创建不成功的话
            
    /// 就默认到C盘跟目录下写日志,一般系统最少有一个主分区,也就是说一般都会有个C盘,所以C盘很保险,这里也是考虑
            
    /// 了多种情况,最终保证日志尽量能持久下来,这里是在指定的目录里,根据错误生成的时间来创建一个文本文件,以便
            
    /// 以后方便分类按日期查看.这个方法里调用了私有静态方法checkAndCreateDir,接下来咱们就来看这个方法
            
    /// </summary>
            
    /// <returns></returns>

            private static string getAppErrorLogFileName()
            
    {
                
    string errorLogBaseDir = System.Configuration.ConfigurationSettings.AppSettings["ErrorLogBaseDir"];
                
    string errorLogDir = checkAndCreateDir( errorLogBaseDir, "C:\\" );
                
                
    string errorFileName = string.Format(
                    
    "Error-{0}.htm",
                    System.DateTime.Now.ToString(
    "yyyyMMMdd"));

                
    return errorLogDir + errorFileName;
            }


            
    /// <summary>
            
    /// 从web.config里获取保存错误日志的目录,如果没有就创建,如果创建不了就返回一个默认的目录
            
    /// </summary>
            
    /// <param name="newDir">要检查的目录</param>
            
    /// <param name="fallBackDir">默认目录</param>
            
    /// <returns>最终返回的目录</returns>

            private static string checkAndCreateDir( string newDir, string fallBackDir )
            
    {
                GWTrace.EnteringMethod( MethodBase.GetCurrentMethod() );
                
    if (System.IO.Directory.Exists( newDir ) ) return newDir;

                
    try 
                
    {
                    System.IO.Directory.CreateDirectory( newDir );
                    
    if (System.IO.Directory.Exists( newDir ) )
                        
    return newDir;
                    
    else
                        
    return fallBackDir;
                }

                
    catch (Exception ex )
                
    {
                    GWTrace.Trace( TraceLevel.Error,
                        
    "There was an error creating the directory {0} : {1}",
                        newDir,
                        ex.ToString() );
                    
    return fallBackDir;
                }

            }

        }

    }



    /*
     * Class       : DbErrorLog
     * Namespace   : GW.MonitorServices.Logging
     * Assembly    : GW.MonitorServices.Logging
     * Author       : Kevin Hoffman
     * Description : Class that is responsible for logging system errors to the database.
     
    */


    using System;
    using System.Text;
    using System.Reflection;
    using System.Diagnostics;

    using GW.CMPServices;
    using GW.MonitorServices;

    namespace GW.MonitorServices.Logging
    {
        
    /// <summary>
        
    /// 这个类用来把错误状态保存到数据库里,一会儿我把保存错误的表结构发给大家哦
        
    /// </summary>

        public class DbErrorLog
        
    {
            
    //防治实例化本垒
            private DbErrorLog() { }

            
    /// <summary>
            
    /// 记录异常
            
    /// </summary>
            
    /// <param name="e">要记录的异常</param>
            
    /// <returns>返回的异常编号</returns>

            public static long LogError( Exception e )
            
    {
                
    return LogError( e, string.Empty );
            }


            
    /// <summary>
            
    /// 重载的方法,根据原始异常和错误信息把这些信息记录到数据库里,这里使用的不是普通的SqlHelper方式来保存数据库
            
    /// 而是用一种托管容器持久性的方法来完成的,也就是CMP模式,如果你看不懂,你可以修改成你能看懂的方式,但是要引入相关的
            
    /// System.Data.SqlClient等空间,不过以后我有空会给大家介绍在.NET里如何实现EJB里的CMP模式的.
            
    /// </summary>
            
    /// <param name="e">原始异常</param>
            
    /// <param name="rootMessage">错误消息</param>
            
    /// <returns>返回错误号</returns>

            public static long LogError( Exception e, string rootMessage )
            
    {
                
    //跟踪输出本方法
                GWTrace.EnteringMethod( MethodBase.GetCurrentMethod() );
                
                
    //创建一个字符串缓存类,用来保存一些错误状态的相信信息,一会儿就要把他们保存到数据库里
                StringBuilder buffer = new StringBuilder(2048);
                
    try
                
    {
                    
    if (rootMessage.Length > 0)
                        buffer.AppendFormat( 
    "{0}\n\n", rootMessage );        //原始错误信息
                    buffer.Append( MonitorUtilities.ExpandStackTrace( e ) );//发生错误的堆栈

                    DbErrorEntry dbEntry 
    = new DbErrorEntry();                //创建一个错误记录实体,一会儿我就贴它的源码
                    dbEntry.ErrorMessage = buffer.ToString();                //设置错误信息
                    dbEntry.ExtendedInfo = MonitorUtilities.GetProcessInfo();//设置扩展信息
                    dbEntry.ServerName = MonitorUtilities.GetMachineName();    //设置发生错误的机器

                    SqlPersistenceContainer sqlPC 
    = new SqlPersistenceContainer(
                        CMPServices.CMPConfigurationHandler.ContainerMaps[
    "ERROR_LOG"] );    //创建一个托管的容器
                    
                    
    //执行容器的Insert方法,并把刚才创建的促无实体做为参数,要保证这一步成功要做一些额外的设置,在web.config里
                    
    //设置元数据,最后再给大家介绍,容器只执行CRUD这些标准操作,如果你想让一个容器不支持某个操作,需要重写它的那些
                    
    //标准操作,并引发异常,下次有机会再详细阐述,关于ORM,CMP的详细内容太复杂,而且争议也很大,这里不多唠叨了.
                    sqlPC.Insert( dbEntry );                                
                    
    return dbEntry.ErrorId;
                }

                
    catch (Exception ex )
                
    {
                    
    //这里一定要把异常抛出去,因为一般不直接调用这个类来持久化错误,它一般由ErrorLog类来调用
                    
    //所以这里有错误要向外层抛出,否则外面就接不到了,也就无法处理了,对吧.
                    
    // this must be thrown so the generic log front-end can
                    
    // tell that there was a db error log failure and write the
                    
    // error to a disk file instead.
                    GWTrace.Trace( TraceLevel.Error, "LogError Failed [{0}]", ex.ToString() );
                    
    throw new Exception("Database log failure", ex );
                }

            }

        }

    }


    /*
     * Class       : ErrorLog
     * Namespace   : GW.MonitorServices.Logging
     * Assembly    : GW.MonitorServices.Logging
     * Author       : Kevin Hoffman
     * Description : Class for handling all forms of error logging.
     
    */


    using System;
    using System.Configuration;
    using System.Reflection;
    using System.Diagnostics;

    namespace GW.MonitorServices.Logging
    {
        
    /// <summary>
        
    /// 错误日志类,本来来把程序运行中出现的错误持久化,方便以后分析,先视图把它放在数据库里,
        
    /// 并在一个文本文件里做个标记,如果在把错误持久到数据库的过程中遇到了错误,就把信息保存在一个
        
    /// html文件里,这样只要有错误发生始终会持久在一个安全的地方,方便你做错误分析,嘿嘿.
        
    /// </summary>

        public class ErrorLog
        
    {
            
    /// <summary>
            
    /// 错误日志标志的文件目录
            
    /// </summary>

            private static string errorUrlPrefix;

            
    /// <summary>
            
    /// 只传入异常的构造函数,返回一个长整型的错误号
            
    /// </summary>
            
    /// <param name="appError">异常</param>
            
    /// <returns>返回错误号</returns>

            public static long LogError( Exception appError )
            
    {
                
    return LogError( appError, string.Empty );
            }


            
    /// <summary>
            
    /// 根据原始异常和错误信息来持久化错误状态
            
    /// </summary>
            
    /// <param name="appError">引发错误的异常</param>
            
    /// <param name="rootMessage">自定义信息</param>
            
    /// <returns></returns>

            public static long LogError( Exception appError, string rootMessage )
            
    {
                
    //跟踪输出这个方法
                GWTrace.EnteringMethod( MethodBase.GetCurrentMethod() );
                rootMessage 
    = ( rootMessage == null ? string.Empty : rootMessage.Trim() );
                
                
                
    //试图把错误信息持久到数据库里,并在一个文本文件里做个标志,提示有个错误发生,已经把它持久到数据库里了,你去看看
                
    //如果不能就把它持久到数据库里就执行catch后面的语句,把它试图持久到一个文本文件里
                try 
                
    {
                    
    long errorId = DbErrorLog.LogError( appError, rootMessage );
                    FileErrorLog.LogError( GWException.GetGWExceptionMessage( GWExceptionMessages.SeeDatabase ), 
                        ErrorViewUrlPrefix, errorId );
                    
    return errorId;
                }

                
    catch (Exception dbError )
                
    {
                    
    //跟踪输出一条信息,就说是在往数据库里写错误的时候失败了.
                    GWTrace.Trace( TraceLevel.Error, "DB Error Log Attempt Failed" );
                    
    try 
                    
    {
                        
    //把错误记录到错误日志文件里去
                        FileErrorLog.LogError( appError, rootMessage );

                        
    //在错误标志文件里记录一条,数据库持久错误的消息,因为如果执行到这里,肯定是在把错误保存到数据库的时候
                        
    //失败了,对吧,这时候还要返回一个错误码,以便让调用程序知道这个方法到底执行了哪一步,这也是一个小技巧
                        FileErrorLog.LogError( dbError, GWException.GetGWExceptionMessage( GWExceptionMessages.DbLogFailed ) );
                        
    return -1;
                    }

                    
    catch
                    
    {
                        
    //如果都无法持久错误,哪只好跟踪输出一条错误信息了,就说在持久错误状态的时候失败了,一般这时候就是有严重错误了
                        
    //最好在这里给管理员发封电子邮件,那些东西你自己扩展吧,你发条儿短信都行.
                        GWTrace.Trace( TraceLevel.Error, "Backup File Error Log Attempt Failed");
                        
    return -2;
                    }

                }

            }


            
    /// <summary>
            
    /// 错误标志文件的目录,错误发生的时候无论是把相信信息记录到数据库里了,还是记录到错误日志文本文件里了
            
    /// 都会在一个错误标志文件里记录一条,表示发生了一条错误,你想查看具体错误就去数据库和去保存错误日志的目录
            
    /// 里去看吧,就这个意思,所以你每天检查错误标志文件就行了.默认位置是/GadgetsWarehouse/ErrorLog/这里,当然
            
    /// 你可以在web.config里设置,我不会翻译ErrorViewUrlPrefix这是什么意思哦,先把它翻译成错误标志文件目录吧
            
    /// </summary>

            private static string ErrorViewUrlPrefix
            
    {
                
    get 
                
    {
                    
    if ( errorUrlPrefix != nullreturn errorUrlPrefix;

                    
    string prefix = ConfigurationSettings.AppSettings["ErrorViewUrlPrefix"];
                    prefix 
    = ( prefix == null ? string.Empty : prefix.Trim() );

                    
    if (prefix.Length == 0 )
                        prefix 
    = "/GadgetsWarehouse/ErrorLog/";

                    errorUrlPrefix 
    = prefix;
                    
    return errorUrlPrefix;
                }

            }

        }

    }

  • 相关阅读:
    godaddy的win主机发邮件的组件
    读取excel的时候,往往多了很多空白行,下面的代码是去掉空白行的
    where泛型约束
    博客园页面有问题,
    今晚就出发回家啦!!!!
    呵呵,日期小小技巧
    获取设置本地当前默认打印机
    Queue Explorer过期处理
    SQL多关键字查询 并按精确度排序
    python 高阶函数
  • 原文地址:https://www.cnblogs.com/onlytiancai/p/204861.html
Copyright © 2011-2022 走看看