Jinlog 之 LogLevel 的实现

作者在 2011-10-24 21:37:19 发布以下内容

Jinlog是我对Log4cplus进行仿制的一个项目,现在我说说我的LogLevel实现方案。

 

log4cplusLogLevel实际上是int类型的别名,并且定义了一些常用的日志级别。按照日志事件程度,最低的日志级别为TRACE_LOG_LEVEL,意味着这是追踪式的日志,会有频繁的日志事件。最高的日志级别为FATAL_LOG_LEVEL,意味着这是非常严重的日志,基本上该日志事件在人品很差的情况下出现。另外还有开关式的日志级别,不作为日志事件来使用,那就是OFF_LOG_LEVELNOT_SET_LOG_LEVEL。所有这些日志级别都有一个常量值,比如OFF_LOG_LEVEL的值为60000,而NOT_SET_LOG_LEVEL的值为-1

 

Log4cplus设置这些日志级别的值只有最基本的需求,那就是比较大小越严重的日志事件值越高。这很对,但是在面对把这些日志级别转换到字符串时log4cplus就显得很蛋疼,它需要遍历单向链表。其实每一个LogLevel都对应一个字符串,这和数组与下标不是同一种情况吗?对,使用数组来解决遍历单向链表的问题,这就是我的解决方案。

 

首先,我规定LogLevel的取值范围在-128~127,也就是一个char的取值范围。有两个理由:

1、很少有人定义超过100个(或更多)的日志级别,一般都是直接使用已定义的日志级别(就是那几个而已)。

2、节省一些内存,一个256个元素的char*数组就可以储存所有的日志级别的字符串名称。

 

这样我就可以定义如下的日志级别:

   enum

   {

      UNKNOWN_LOG = -1,

      TRACE_LOG = 0,

      DEBUG_LOG = 20,

      INFO_LOG = 40,

      WARN_LOG = 60,

      ERROR_LOG = 80,

      FATAL_LOG = 100,

      OFF_LOG = 127,

      NOTSET_LOG = -128,

      STR_TABLE_SIZE = 256

   };

这些日志级别的值我不是随便设定的,从0126是可输出的日志事件,就是你在输出日志时看到这条日志是WARN还是ERROR。在上面我只定义了6个可输出的日志事件,如果使用一个值为6的日志级别,那么你会得到一个UNKNOWN的字符串。除非你自定义了该值的日志级别。

 

我觉得只有代码可以说清:

struct LogLevel

{

   enum

   {

      UNKNOWN_LOG = -1,

      TRACE_LOG = 0,

      DEBUG_LOG = 20,

      INFO_LOG = 40,

      WARN_LOG = 60,

      ERROR_LOG = 80,

      FATAL_LOG = 100,

      OFF_LOG = 127,

      NOTSET_LOG = -128,

      STR_TABLE_SIZE = 256

   };

   LogLevel(Int _level = NOTSET_LOG) : level(_level)

   {

   }

   operator Int (void) const

   {

      return level;

   }



   Char level;



   static Cstr* GetStrTableS(void);

   static Cstr ToStrS(const LogLevel& _loglvl);

   static LogLevel FromStrS(Cstr _llstr);

};



/* static */

Cstr* LogLevel::GetStrTableS(void)

{

   struct _StrTable

   {

      _StrTable(void)

      {

         for (Int i = 0; i< STR_TABLE_SIZE; ++i)

            table[i] = "UNKNOWN";

         table[TRACE_LOG]   = "TRACE";

         table[DEBUG_LOG]   = "DEBUG";

         table[INFO_LOG]    = "INFO";

         table[WARN_LOG]    = "WARN";

         table[ERROR_LOG]   = "ERROR";

         table[FATAL_LOG]   = "FATAL";

         table[OFF_LOG]     = "OFF";

         table[(Byte)NOTSET_LOG]  = "NOTSET";

      }

      Cstr table[STR_TABLE_SIZE];

   };

   static _StrTable st;

   return st.table;

}

/* static */

Cstr LogLevel::ToStrS(const LogLevel& _loglvl)

{

   return LogLevel::GetStrTableS()[(Byte)_loglvl];

}

/* static */

LogLevel LogLevel::FromStrS(Cstr _llstr)

{

   if (!_llstr)

      return UNKNOWN_LOG;



   static Cstr* table = LogLevel::GetStrTableS();

   for (Int i = 0; i < STR_TABLE_SIZE; ++i)

   {

      if (_stricmp(table[i], _llstr) == 0)

         return i;

   }

   return UNKNOWN_LOG;

}

很简单的实现,如果要自定义一个日志级别,比如在DEBUGINFO之间,那么我们应该这样:

// 先定义一个日志级别常量,注意不要冲突和越界。

enum{ TEST_LOG = LogLevel::DEBUG_LOG+1 };

// 获取字符串表,256个元素

Cstr* strtable = LogLevel::GetStrTableS();

// 设置该日志级别的字符串名称

Strtable[TEST_LOG] = “TEST”;



// 以后就可以这样返回日志级别的字符串名称

Cstr* s = LogLevel::ToStrS(TEST_LOG);



// 通过字符串可以返回对应的日志级别

LogLevel l = LogLevel::FromStrS(“TEST”);


 

好了就到这吧,有空再写。

 

系统辅助 | 阅读 1128 次
文章评论,共0条
游客请输入验证码
浏览14399次