Jinlog是我对Log4cplus进行仿制的一个项目,现在我说说我的LogLevel实现方案。
在log4cplus中LogLevel实际上是int类型的别名,并且定义了一些常用的日志级别。按照日志事件程度,最低的日志级别为TRACE_LOG_LEVEL,意味着这是追踪式的日志,会有频繁的日志事件。最高的日志级别为FATAL_LOG_LEVEL,意味着这是非常严重的日志,基本上该日志事件在人品很差的情况下出现。另外还有开关式的日志级别,不作为日志事件来使用,那就是OFF_LOG_LEVEL和NOT_SET_LOG_LEVEL。所有这些日志级别都有一个常量值,比如OFF_LOG_LEVEL的值为60000,而NOT_SET_LOG_LEVEL的值为-1。
Log4cplus设置这些日志级别的值只有最基本的需求,那就是比较大小越严重的日志事件值越高。这很对,但是在面对把这些日志级别转换到字符串时log4cplus就显得很蛋疼,它需要遍历单向链表。其实每一个LogLevel都对应一个字符串,这和数组与下标不是同一种情况吗?对,使用数组来解决遍历单向链表的问题,这就是我的解决方案。
首先,我规定LogLevel的取值范围在-128~127,也就是一个char的取值范围。有两个理由:
1、很少有人定义超过100个(或更多)的日志级别,一般都是直接使用已定义的日志级别(就是那几个而已)。
2、节省一些内存,一个256个元素的char*数组就可以储存所有的日志级别的字符串名称。
这样我就可以定义如下的日志级别:
{
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
};
这些日志级别的值我不是随便设定的,从0到126是可输出的日志事件,就是你在输出日志时看到这条日志是WARN还是ERROR。在上面我只定义了6个可输出的日志事件,如果使用一个值为6的日志级别,那么你会得到一个UNKNOWN的字符串。除非你自定义了该值的日志级别。
我觉得只有代码可以说清:
{
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;
}
很简单的实现,如果要自定义一个日志级别,比如在DEBUG和INFO之间,那么我们应该这样:
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”);
好了就到这吧,有空再写。