ORM映射框架总结--日志处理

  在我们做项目的过程中,日志跟踪异常是非常必要的,当程序发布到服务器上时,如果出现异常直接抛出给用户这是非常不友好的。对于不懂程序的用户来说,这回让人感觉莫名其妙,对于那些程序高手,可能就是攻破这个网站的关键。

 

  在asp.net 程序的web.config 配置文件中有如下两个节点作为程序异常配置:

  (1)<customErrors>节点

    <customErrors>节点用于定义 一些自定义错误信息的信息。此节点有Mode和defaultRedirect两个属性,其中    defaultRedirect属性是一个可选属性,表示应 用程序发生错误时重定向到的默认URL,如果没有指定该属性则显示一般性错误。                       Mode属性是一个必选属性,它有三个可能值,它们所代表的意义分别如下:
        On 表示在本地和远程用户都会看到自定义错误信息。
        Off 禁用自定义错误信息,本地和远程用户都会看到详细的错误信息。
        RemoteOnly 表示本地用户将看到详细错误信息,而远程用户将会看到自定义错误信息。
    这 里有必要说明一下本地用户和远程用户的概念。当我们访问asp.net应用程时所使用的机器和发布asp.net应用程序所使用的机器为同一台机器时成为 本地用户,反之则称之为远程用户。在开发调试阶段为了便于查找错误Mode属性建议设置为Off,而在部署阶段应将Mode属性设置为On或者 RemoteOnly,以避免这些详细的错误信息暴露了程序代码细节从而引来黑客的入侵。

  (2) <error>子节点

     在<customErrors>节点下还包含有< error>子节点,这个节点主要是根据服务器的HTTP错误状态代码而重定向到我们自定义的错误页面,注意要使<error>子节点 下的配置生效,必须将<customErrors>节点节点的Mode属性设置为“On”。下面是一个例子: 
            <customErrors mode="On" defaultRedirect="GenericErrorPage.htm"> 
                  <error statusCode="403" redirect="403.htm" />
                  <error statusCode="404" redirect="404.htm" />
            </customErrors>

 

  以上配置可以让程序方式异常的时候显示更友好,不将异常信息直接抛出给用户。这个时候我们就需要达到用户友好提示的同时还要跟踪程序异常。下面介绍的是ORM框架中提供的一个小小的日志跟踪程序。

 

1. 异常消息类型

代码

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 
 6 namespace CommonData.Log
 7 {
 8     public enum MessageType
 9     {
10         /// <summary>
11         /// 未知信息异常
12         /// </summary>
13         Unkown,
14 
15         /// <summary>
16         ///普通信息异常 
17         /// </summary>
18         Common,
19 
20         /// <summary>
21         /// 警告信息异常
22         /// </summary>
23         Warning,
24 
25         /// <summary>
26         /// 错误信息异常
27         /// </summary>
28         Error,
29 
30         /// <summary>
31         /// 成功信息
32         /// </summary>
33         Success
34     }
35 }
36 

 

  以上定义的是一个枚举类型,定义了日志的级别,分别为:未知信息异常,  普通信息异常 ,  警告信息异常,  错误信息异常,  成功信息.

  写程序的过程中可以根据不同的需要输出不同级别的日志。

(2). 日志文件创建类别

代码

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 
 6 namespace CommonData.Log
 7 {
 8     public enum LogType
 9     {
10         /// <summary>
11         /// 此枚举指示每天创建一个新的日志文件
12         /// </summary>
13         Daily,
14 
15         /// <summary>
16         /// 此枚举指示每周创建一个新的日志文件
17         /// </summary>
18         Weekly,
19 
20         /// <summary>
21         /// 此枚举指示每月创建一个新的日志文件
22         /// </summary>
23         Monthly,
24 
25         /// <summary>
26         /// 此枚举指示每年创建一个新的日志文件
27         /// </summary>
28         Annually
29     }
30 }
31 

 

  这也是一个枚举类型,定义了日志文件创建的标准。程序可以每天创建一个日志文件,可以一周,一月,一年来创建一次。一般情况写我是使用每天创建一个日志文件,这样可以每日下载该日志文件跟踪程序异常。如果我们每周或更长时间创建一次,这样在这个是时段内就不能即时清理改日志文件(因为该文件在当前线程中使用,后面介绍)。

 

(3).定义日志消息实体类

代码

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 
 6 namespace CommonData.Log
 7 {
 8     public class LogMessage
 9     {
10         /// <summary>
11         /// 日志记录时间
12         /// </summary>
13         private DateTime _time;
14 
15         public DateTime Time
16         {
17             get
18             {
19                 return _time;
20             }
21             set
22             {
23                 _time = value;
24             }
25         }
26 
27         /// <summary>
28         /// 日志记录内容
29         /// </summary>
30         private string _content;
31 
32         public string Content
33         {
34             get
35             {
36                 return _content;
37             }
38             set
39             {
40                 _content = value;
41             }
42         }
43 
44         /// <summary>
45         /// 日志类型
46         /// </summary>
47         private MessageType _type;
48 
49         public MessageType Type
50         {
51             get
52             {
53                 return _type;
54             }
55             set
56             {
57                 _type = value;
58             }
59         }
60 
61 
62         public LogMessage(): this("", MessageType.Unkown)
63         {
64         }
65 
66         public LogMessage(string content, MessageType type): this(DateTime.Now, content, type)
67         {
68         }
69 
70         public LogMessage(DateTime time,string content,MessageType type)
71         {
72             this._time = time;
73             this._content = content;
74             this._type = type;
75         }
76 
77         public override string ToString()
78         {
79             return this._time.ToString() + "\t" + this._content + "\t";
80         }
81     }
82 }
83 

 

  这个类定义了日志消息的一些基本属性,其中很重要的一点就是 重写ToString 这个方法。该对象具有了新ToString方法,它返回的是该消息的时间和类容。这样在后面的日志记录和输出过程中比较方便,而不用每次都去连接字符串。

 

(4) 日志记录

代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;

namespace CommonData.Log
{
    public class Log:IDisposable
    {
        private static Queue<LogMessage> logMessages;

        private static string path;

        private static bool state;

        private static LogType logtype;

        private static DateTime time;

        private static StreamWriter writer;

        /// <summary>
        /// 无参构造方法,指定日志文件路径为当前目录,默认日志类型为每日日志类型
        /// </summary>
        public Log():this(".\\",LogType.Daily)
        {
        }

        /// <summary>
        /// 构造方法,指定日志文件路径为当前目录
        /// </summary>
        /// <param name="t">日志文件类型</param>
        public Log(LogType t):this(".\\",t)
        {
        }

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="path">指定日志文件路径</param>
        /// <param name="t">日志文件类型</param>
        public Log(string filepath,LogType t)
        {
            if(logMessages==null)
            {
                state = true;
                path= filepath;
                logtype = t;
                FileOpen();
                logMessages = new Queue<LogMessage>();
                Thread thread = new Thread(Work);
                thread.Start();
            }
        }

        /// <summary>
        /// 利用线程来写入日志内容
        /// </summary>
        private void Work()
        {
            while(true)
            {
               
                if(logMessages.Count>0)
                {
                    LogMessage message = null;
                    lock (logMessages)
                    {
                        message = logMessages.Dequeue();
                    }
                    if(message!=null)
                    {
                        WriteLogMessage(message);
                    }
                }
                else
                {
                    if(state)
                    {
                        Thread.Sleep(1);
                    }
                    else
                    {
                        FileClose();
                    }
                }
            }
        }

        /// <summary>
        /// 将日志内容写入到文本
        /// </summary>
        private void WriteLogMessage(LogMessage message)
        {
            try
            {

                if (writer == null)
                {
                    FileOpen();
                }
                else
                {
                    if (DateTime.Now >= time)
                    {
                        FileClose();
                        FileOpen();
                    }
                    writer.Write(message.Time);
                    writer.Write("\t");
                    writer.Write(message.Type);
                    writer.Write("\t\r\n");
                    writer.Write(message.Content);
                    writer.Write("\r\n\r\n");
                    writer.Flush();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

        /// <summary>
        /// 根据日志文件类型判断日志文件名称
        /// 通过判断文件的到期时间标记将决定是否创建新文件。
        /// </summary>
        /// <returns></returns>
        private string GetFileName()
        {
            DateTime now = DateTime.Now;
            string format = "";
            switch (logtype)
            { 
                case LogType.Daily:
                    time = new DateTime(now.Year,now.Month,now.Day);
                    time = time.AddDays(1);
                    //time = time.AddMinutes(1);
                    format = "yyyyMMdd'.log'";
                    break;
                case LogType.Weekly:
                    time = new DateTime(now.Year,now.Month,now.Day);
                    time = time.AddDays(7);
                    format = "yyyyMMdd'.log'";
                    break;
                case LogType.Monthly:
                    time = new DateTime(now.Year,now.Month,1);
                    time = time.AddMonths(1);
                    format = "yyyyMM'.log'";
                    break;
                case LogType.Annually:
                    time = new DateTime(now.Year,1,1);
                    time = time.AddYears(1);
                    format = "yyyy'.log'";
                    break;
            }
            return now.ToString(format);
        }

        /// <summary>
        /// 写入日志文件
        /// </summary>
        public void Write(LogMessage message)
        {
            if (logMessages != null)
            {
                lock (logMessages)
                {
                    logMessages.Enqueue(message);
                }
            }
        }

        /// <summary>
        /// 写入日志文件
        /// </summary>
        /// <param name="text">日志内容</param>
        /// <param name="type">消息类型</param>
        public void Write(string text,MessageType type)
        {
            Write(new LogMessage(text,type));
        }

        /// <summary>
        /// 写入日志文件
        /// </summary>
        /// <param name="now">当前时间</param>
        /// <param name="text">日志内容</param>
        /// <param name="type">消息类型</param>
        public void Write(DateTime now, string text, MessageType type)
        {
            Write(new LogMessage(now,text,type));
        }

        /// <summary>
        /// 写入日志文件
        /// </summary>
        /// <param name="e">异常对象</param>
        /// <param name="type">消息类型</param>
        public void Write(Exception e,MessageType type)
        {
            Write(new LogMessage(e.Message,type));
        }

        /// <summary>
        /// 打开文件准备写入内容
        /// </summary>
        private void FileOpen()
        {
            writer = new StreamWriter(path+GetFileName(),true,Encoding.Default);
        }

        /// <summary>
        /// 关闭文件流
        /// </summary>
        private void FileClose()
        {
            if(writer!=null)
            {
                writer.Flush();
                writer.Close();
                writer.Dispose();
                writer = null;
            }
        }

        /// <summary>
        /// 释放内存空间
        /// </summary>
        public void Dispose()
        {
            state = false;
            GC.SuppressFinalize(this);
        }
    }
}

 

  这个才是这个日志系统的关键部分,程序设计的思路是程序启动之后,程序开辟了另外一条线程,该线程专用于写日志信息。程序中使用了一个队列消息,当程序发生异常或者用户记录日志,会将这个日志消息放入这个队列中去,至于写日志主程序就不用再去处理,只要捕获到异常主程序只是负责将消息放入队列就可以了。写日志的工作是有开辟的线程完成的。该线程会根据定义在多长时间内创建新的日志文件,还会不断的去队列中检测是否有新的日志内容需要记录,并且完成日志的记录。正是因为这个线程,所以在日志记录的过程中不能去清理这个日志文件。所以要特别注意。

时间: 2024-10-27 17:58:38

ORM映射框架总结--日志处理的相关文章

ORM映射框架总结--数据库操作库(精修版)

1.       ORM数据库操作原理 前面已经介绍过了个人ORM映射框架中的三个核心库: 实体-数据库 映射特性关系: http://www.cnblogs.com/qingyuan/archive/2010/04/02/1702998.html 实体分析器: http://www.cnblogs.com/qingyuan/archive/2010/04/05/1704546.html Sql 语句生成组建: http://www.cnblogs.com/qingyuan/archive/20

ORM映射框架总结--代码生成器

年前发布了一些文章,是关于.NET数据操作(点击查看)的.刚开始学习编程的时候,总感觉Java中的Hibernate 功能好强大,现在也不可否认它的确强大,特别是它在数据关系处理上,却是那样的让人称叹.          当我那时还不知道.net 中的Linq的时候,一直想自己能够简单的写个ORM映射框架.去年花费了几个月的业务时间终于算是整出来了,一些基本操作都能够实现了,自己号称从数据库操作冗余代码中解脱出来,其实自己很天真,那个框架是多么的不完善.总结了一下,最近超体力透支的准备将其扩展,

ORM映射框架总结--数据操作(一)

  ORM(对象关系映射) ,在我们印象中Hibernate是体现的比较明显的.因为它的轻量级和低入侵式,得到很多IT人士的亲睐. 正是因为ORM 这种映射关系,使程序各个模块之间的耦合度大大降低,使得程序灵活多变..NET 在Linq 出现之前几乎没有看到什么ORM映射框架,今年自己也.net 方面下了一番苦功夫学习,有小小成果就是自己写了一个ORM映射框架.在2009年的最后一天与大家分享   程序总体设计思路:   姑且用上面的图来表示整个框架的流程.其实就是用一些特性来描述实体和数据库之

ORM映射框架总结--映射桥梁

1.       感言 写博客之前先自我吹嘘一下,给这些文章来些自我介绍. 半年前自己借用了5个多月的业务时间写了一个个人ORM映射框架.在之前的博 客中也有过写过该框架的相关介绍.半年前的那个ORM只不过是自己想象的关系映射的一个雏形,那一段曾经让自己骄傲过得代码的确存在着太多的问题,但是我始终没有放弃过对它的修改.又过了半年,这个ORM映射框架在之前的基础上有了很大的改进.在此与大家分享一下,希望大家共同探讨,共同学习.   2.       框架整体介绍 说道这里,其实这个ORM框架仍然存

ODB——基于c++的ORM映射框架尝试(安装)

这篇博客应该是和之前的重拾cgi一起的.当时为了模仿java的web框架,从页面的模板,到数据库的ORM,都找个对应的库来进行尝试.数据库用的就是ODB,官方网站是http://www.codesynthesis.com/products/odb/. 1.安装 odb是直接提供源代码的,主要包含这几个部分:odb.libodb.libodb-sqlite等,用途分别是: odb是ODB编译器,类似于qt的moc,将c++源码中包含ODB特定宏的代码,生成对应的c++代码. libodb是运行时库

ORM映射框架总结--SQL 语句生成组件

 1.       SQL 语句生成组建 之前说过ORM框架中有一个非常重要的组件,那就是SQL语句生成组件.SQL语句生成组件,顾名思义就是用于生成sql语句的一个组件.之前的Attribute 是用于修饰实体信息,而上一章讲的实体分析器分析了实体信息,在很大一部分程度上,以上做工作就是为这个SQL语句生成组件服务的. 该组件的核心接口是IDbFactory,它实现了接口IDisposable 目前该ORM支持SQL Server 数据库的sql语句生成,在后期过程中会逐步实现对Oracle,

ORM映射框架总结--实体分析器

1.       什么是数据分析器 前面一篇文章讲到过数据分析器,什么是数据分析器.其实很容易理解,就是对数据进行分析采集的一个工具,说白了就是一个小程序,在本ORM框架中对实体对象进行必要的数据分析,获得实体对象的各种信息缓存,以便在后续的工作中直接提取数据.这个是相对去年写的那个ORM有所改进的,在缓存实体信息的时候,在一定程度上可以提高该框架的性能 2.       实体分析器的原理简单介绍 简单的UML图: 图总是能给人最直观的感觉.从上面的图我们可以看出,这个分析器分为了几个过程: (

ORM映射框架总结--数据操作(二)

  1.TableInfo 封装实体特性类 代码  1 /** 2  *  3  * 2009-4-11 4  *  5  *  6  * 表实体的特性信息 7  * */ 8 using System; 9 using System.Collections.Generic;10 using System.Linq;11 using System.Text;12 using System.Reflection;13 14 namespace CommonData.Model15 {16     

ODB——基于c++的ORM映射框架尝试(使用)

2.使用 首先,需要定义一个对象,用来和数据库字段对应: [cce lang="cpp"] #ifndef VOLUME_H #define VOLUME_H #include <string> #include <odb/core.hxx> #pragma db object class Volume { public: Volume(const std::string &name, const std::string &location, c