一个日志框架的开源,有些不错的创意。

题外篇

曾经有段时间,在公司维护IBM ds8000系统,就是服务器。当时的工作就是分析系统的日志,查看是否有运行错误。虽然有一些脚本分析工具,但是一旦发生了问题,还是靠人力,任何工具都没有用。

当时,如果发现了问题,首先就是把最近的打包日志下载到公司的ftp,然后打开一个pad,找问题发生的时间的所有相关日志,帖在一起。

如果没有经验,就会把所有模块的日志都帖在一起,慢慢看,那简直就是sb了。有经验的工程师,就会先分析有可能出现问题的模块,然后解压日志再合并查看。

当时觉得这样的工作非常的无聊,但是又没有好的思路。现在,总算给我找到解决方法了。

前言

本框架参考了 Microsoft.Enterprise.lib, log4net,同时集成了一些比较先进的日志思想和技术,能够方便程序开发以及后期的维护。

与此技术相关的讨论区在:

http://groups.google.com/group/pixysoft

优势与特点

  1. 伪XML技术(Pesudo XML):使用伪xml结构记录日志,实现了日志的结构化存储。同时对.net的xml操作部分全部重写,使io性能接近文件流的处理,既摒弃了xml结构化带来的性能问题,又不丧失xml的结构化存储、查询的特性。
  2. 并行日志技术(Parallel Logging):采用了AOP技术,能够对某一类的入口、出口、异常进行全方位跟踪,并且记录输入参数、传出参数;实现代码运行与日志记录的平行(我称其为 Parallel Logging, 并行日志技术)。使用此技术,在项目开发中能够得心应手。
  3. 异常报告技术(Exception Report):当发生异常的时候,能够查询程序调用的堆栈,并且收集此调用过程中相关的其他日志,进行日志合并,更加方便系统debug。
  4. 日志查询技术(Log Searching):支持时间段查询、日志主键查询、日志级别查询;支持跨文件查询;支持不同模块日志合并查询,查询性能接近文件流操作。

日志片段展示

以下是一个正常的日志记录:

代码
< log  level ="info"  time ="2009-11-28 23:33:06:906"  id ="7cb203b2-b9c9-4818-aa59-4efd8ccec464" >
hello
</ log >

 

以下是关于异常的日志记录,能够捕获所有调用的堆栈:

 

代码
< log  level ="fatal"  time ="2009-11-28 23:36:39:437"  id ="339b4e11-a2f2-48c5-b6e3-f15754b36310" >
< message >
hello
</ message >
< frame  class ="Pixysoft.OpenSource.Logs.TestDriven.Hello"  method ="Helloworld"  dll ="Pixysoft.OpenSource.Logs.TestDriven.dll"  file ="E:\xxxx\xxxx\develop\Pixysoft.OpenSource.Logs\Pixysoft.OpenSource.Logs.TestDriven\testcase.cs"  line ="50"  column ="13"  id ="339b4e11-a2f2-48c5-b6e3-f15754b36310" />
< frame  class ="System.Runtime.Remoting.Messaging.Message"  method ="Dispatch"  dll ="mscorlib.dll"  file =""  line ="0"  column ="0"  id ="339b4e11-a2f2-48c5-b6e3-f15754b36310" />
< frame  class ="System.Runtime.Remoting.Messaging.StackBuilderSink"  method ="SyncProcessMessage"  dll ="mscorlib.dll"  file =""  line ="0"  column ="0"  id ="339b4e11-a2f2-48c5-b6e3-f15754b36310" />
</ log >

 

一段并行日志记录:

代码
< log  level ="info"  time ="2009-11-27 23:59:17:843"  id ="6651d0f8-cc6d-498a-a3ba-2431dedfb844" >
Pixysoft.Framework.Logs.dll::Pixysoft.Framework.Logs._testdriven.Hello.Helloworld(String para1, Hello para2, String[] paras3)
::para1 = null;
::para2 = null;
::paras3 = System.String[].Count = 0;

</ log >

 

演示代码

代码
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Pixysoft.OpenSource.Logs.TestDriven
{
    
public   class  testcase
    {
        
///   <summary>
        
///  summary:
        
///  测试写入日志
        
///  
        
///  output: 
        
///  在debug目录下面出现helloworld的目录,里面有helloworld.log的日志
        
///   </summary>
         public   void  test001()
        {
            
for  ( int  i  =   0 ; i  <   1000 ; i ++ )
            {
                Console.WriteLine(Logger.Instances[
" helloworld " ].Info( " hello " ));
            }
        }


        
///   <summary>
        
///  summary:
        
///  测试aop日志+Exception的记录
        
///  
        
///  output:
        
///  1. Hello.Nick可以显示,但是Helloworld不能显示。
        
///  2. 所有调用过程全部记录在debug/helloworld-aop目录的helloworld-aop.log里面
        
///  3. Exception的所有调用堆栈信息都被记录
        
///   </summary>
         public   void  test002()
        {
            Console.WriteLine(
new  Hello().Nick());

            
try
            {
                Console.WriteLine(
new  Hello().Helloworld( " 1 " new  Hello(),  " 2 " " 3 " ));
            }
            
catch  (Exception ex)
            {
            }
        }


        
///   <summary>
        
///  summary:
        
///  测试注册
        
///  
        
///  output:
        
///  在debug/log目录下,出现.log文件,记录了当前模块的注册信息
        
///   </summary>
         public   void  test003()
        {
            Logger.Instances[
" hello " ].Register();
        }


        
///   <summary>
        
///  summary:
        
///  测试日志的查询
        
///  
        
///  output:
        
///  正确显示日志HELLOWORLD的查询结果
        
///   </summary>
         public   void  test004()
        {
            ILogCommand command 
=  Logger.Instance[ " HELLOWORLD " ].CreateCommand();

            command.Range.From 
=  DateTime.Parse( " 2009-11-27 23:58:27 " );

            
// command.Range.To = DateTime.Now.AddDays(10);

            command.Level 
=  LogLevel.ALL;

            command.CrossFiles 
=   false ;

            ILogDocument docs 
=  command.ExecuteReader();

            
// command.SerializeReader();

            Console.WriteLine(docs.Serialize());

            
foreach  (ILogRecord record  in  docs.Records)
            {
                Console.WriteLine(record.Id);
                Console.WriteLine(record.Date);
                Console.WriteLine(record.Level);
                Console.WriteLine(record.Text);
                Console.WriteLine(record.Ip);

                
foreach  (ILogFrame frame  in  record.Frames)
                {
                    Console.WriteLine(frame.Dll);
                    Console.WriteLine(frame.Class);
                    Console.WriteLine(frame.File);
                    Console.WriteLine(frame.Path);
                    Console.WriteLine(frame.Line);
                    Console.WriteLine(frame.Column);
                }
            }
        }


        
///   <summary>
        
///  summary:
        
///  测试根据id获取日志的信息
        
///  
        
///  output:
        
///  成功获取日志helloworld信息
        
///   </summary>
         public   void  test005()
        {
            ILogRecord record 
=  Logger.Instances[ " helloworld " ].GetRecord( " 7cb203b2-b9c9-4818-aa59-4efd8ccec464 " false );

            Console.WriteLine(record.Text);
        }


        
///   <summary>
        
///  summary:
        
///  测试生成报告
        
///  
        
///  output:
        
///  获取日志id对应的日志的报告
        
///   </summary>
         public   void  test006()
        {
            ILogReport report 
=  Logger.Instances[ " helloworld " ].GetReport( " 7cb203b2-b9c9-4818-aa59-4efd8ccec464 " 20 );

            Console.WriteLine(
" report record id =  "   +  report.Id);
            Console.WriteLine(
" report record timespan =  "   +  report.TimeSpan);
            Console.WriteLine(
" report record timefrom =  "   +  report.TimeFrom);
            Console.WriteLine(
" report record timeto =  "   +  report.TimeTo);
            Console.WriteLine(
" report record createdate =  "   +  report.CreateDate);
            Console.WriteLine(
" report document.record.count =  "   +  report.Document.Records.Count);
            Console.WriteLine(
" report framedocument.count =  "   +  report.FrameDocuments.Length);
        }

    }

    [Logger(
" helloworld-aop " )]
    
class  Hello : ContextBoundObject
    {
        
public   string  Helloworld( string  para1, Hello para2,  params   string [] paras3)
        {
            
throw   new  Exception( " hello " );
        }

        
public   string  Nick()
        {
            
return   " 1 " ;
        }

    }
}

 

测试代码下载

 

http://www.boxcn.net/shared/r34b6299p9

 

核心技术说明

日志系统最关键的就是效率,xml虽然实现了结构化的存储,但是性能非常的差。

考虑到日志的特性:增量追加+不修改,我就使用了伪xml技术去提高xml的存储、读取性能。

  • xml的存储直接使用了File.Open(xxx,Mode.Append),因此性能 == 文件流的操作
  • xml的读取使用xmlreader,因此又~=文件流的操作

开源说明

编译后的代码可以随意使用,没有任何的使用限制。

为了保证源码质量,如果希望加入开发小组,获取源码,符合以下2点的即可:

  • 在博客园、csdn的博龄大于1年。
  • 针对本框架,提出您的改进方案,方案要求可行、有简要的技术实现。 

请在以下讨论区提交您的改进方案。

我们根据您的需求,提供svn进行源码下载,维护。

技术联系

[email protected]

http://zc22.cnblogs.com/

 

你可能感兴趣的:(框架)