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

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:   在我们做项目的过程中,日志跟踪异常是非常必要的,当程序发布到服务器上时,如果出现异常直接抛出给用户这是非常不友好的。对于不懂程序的用户来说,这回让人感觉莫名其妙,对于那些程序高手,可能就是攻破这个网站的关键。

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

 

  在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. 异常消息类型

img_405b18b4b6584ae338e0f6ecaf736533.gif 代码
 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). 日志文件创建类别

img_405b18b4b6584ae338e0f6ecaf736533.gif 代码
 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).定义日志消息实体类

img_405b18b4b6584ae338e0f6ecaf736533.gif 代码
 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) 日志记录

img_405b18b4b6584ae338e0f6ecaf736533.gif 代码
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 );
        }
    }
}

 

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

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
1月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
328 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
2月前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
328 3
|
2月前
|
Java 程序员 API
Android|集成 slf4j + logback 作为日志框架
做个简单改造,统一 Android APP 和 Java 后端项目打印日志的体验。
138 1
|
3月前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP的编程实践中,设计模式是解决常见软件设计问题的最佳实践。单例模式作为设计模式中的一种,确保一个类只有一个实例,并提供全局访问点,广泛应用于配置管理、日志记录和测试框架等场景。本文将深入探讨单例模式的原理、实现方式及其在PHP中的应用,帮助开发者更好地理解和运用这一设计模式。
在PHP开发中,单例模式通过确保类仅有一个实例并提供一个全局访问点,有效管理和访问共享资源。本文详细介绍了单例模式的概念、PHP实现方式及应用场景,并通过具体代码示例展示如何在PHP中实现单例模式以及如何在实际项目中正确使用它来优化代码结构和性能。
56 2
|
2月前
|
SQL XML 监控
SpringBoot框架日志详解
本文详细介绍了日志系统的重要性及其在不同环境下的配置方法。日志用于记录系统运行时的问题,确保服务的可靠性。文章解释了各种日志级别(如 info、warn、error 等)的作用,并介绍了常用的日志框架如 SLF4J 和 Logback。此外,还说明了如何在 SpringBoot 中配置日志输出路径及日志级别,包括控制台输出与文件输出的具体设置方法。通过这些配置,开发者能够更好地管理和调试应用程序。
|
3月前
|
Java
日志框架log4j打印异常堆栈信息携带traceId,方便接口异常排查
日常项目运行日志,异常栈打印是不带traceId,导致排查问题查找异常栈很麻烦。
|
3月前
|
运维 NoSQL Java
SpringBoot接入轻量级分布式日志框架GrayLog技术分享
在当今的软件开发环境中,日志管理扮演着至关重要的角色,尤其是在微服务架构下,分布式日志的统一收集、分析和展示成为了开发者和运维人员必须面对的问题。GrayLog作为一个轻量级的分布式日志框架,以其简洁、高效和易部署的特性,逐渐受到广大开发者的青睐。本文将详细介绍如何在SpringBoot项目中接入GrayLog,以实现日志的集中管理和分析。
296 1
|
4月前
|
XML Java Maven
Spring5入门到实战------16、Spring5新功能 --整合日志框架(Log4j2)
这篇文章是Spring5框架的入门到实战教程,介绍了Spring5的新功能——整合日志框架Log4j2,包括Spring5对日志框架的通用封装、如何在项目中引入Log4j2、编写Log4j2的XML配置文件,并通过测试类展示了如何使用Log4j2进行日志记录。
Spring5入门到实战------16、Spring5新功能 --整合日志框架(Log4j2)
|
4月前
|
Java 数据库连接 数据库
后端框架的学习----mybatis框架(6、日志)
这篇文章介绍了如何在MyBatis框架中使用日志功能,包括配置MyBatis的日志实现、使用log4j作为日志工具,以及如何通过配置文件控制日志级别和输出格式。
|
4月前
|
存储 缓存 监控
【嵌入式SD NAND】基于FATFS/Littlefs文件系统的日志框架实现
综上所述,构建一个基于FATFS/Littlefs文件系统的日志框架需要对文件系统的操作有深入理解,并以此为基础设计一套完整的日志处理机制。这样的框架不仅能够确保日志数据的完整性和系统的鲁棒性,同时还能够满足嵌入式系统对于性能和资源使用的严格要求。
185 4