IbatisNet中的Common Logging(转)
自从apache的jakarta Commons项目中添加了logging组件,logging就成为java开发最通用的日志组件。我认为Logging组件的出现最主要的有两个:
1. 统一接口。
java社区中的日志服务组件比较多,log4j,jdk log,LogKit,其他很多项目都提供了自己的日志组件例如Avalon。这些组件没有统一的接口和配置,加大了我们选择使用哪种log组件的难度。Logging组件统一了这些接口,使我们只关注与Logging提供的日志接口,而具体使用那种日志组件可以灵活选择。
2. 可以灵活的决定是否需要日志,使用什么样的日志实现。
虽然logj4j等日志组件提供的功能十分强大,但同时这些组件的系统消耗也是比较大的,这些日志操作有可能会极大地影响系统的性能。所以系统在上线后,很多原先用于调试的日志功能将不再需要,或者所有的应用程序日志都不需要,或需要我们自己订制的日志服务。Logging组件首先提供了空实现的日志,也就是说只要使用这种日志实现,我们可以在不改变程序的情况下去掉所有日志输出。当然我们还可以扩展Logging,实现自己的log日志服务,并在需要的时候部署我们的日志服务。
DotNet中现在主要的日志功能是Framework提供的系统日志和移植于java的log4j的Log4Net。其次DotNet中还没有一个类似于Commons Logging的组件(最少我还不知道)。所以IbatisNet在common项目中实现了一个类似Commons Logging的公共服务。
主接口介绍
IbatisNet的日志功能是通过适配器
IbatisNet的日志功能的主接口是ILog,它定义了日志服务的主要功能,这些功能和log4net提供的应该是一样的,分为7个级别,在public enum LogLevel中定义:
public enum LogLevel
{
All = 0 ,
Debug = 1 ,
Info = 2 ,
Warn = 3 ,
Error = 4 ,
Fatal = 5 ,
Off = 6 ,
}
对于从1到5的每一个级别分别定义了2个方法和一个只读bool属性,例如Debug级别:
void Debug( object message ); |
void Debug( object message, Exception exception ); |
bool IsDebugEnabled { get ; } |
这些我们应该都比较熟悉,不多介绍。
另一个重要的接口是public interface ILoggerFactoryAdapter,它是适配器工厂,具体实现用于生成适配不同日志实现的IbatisNet Common 中的ILog实现(话说得比较别扭,看看具体例子就清楚了)。ILoggerFactoryAdapter定义如下:
namespace IBatisNet.Common.Logging
{
public interface ILoggerFactoryAdapter
{
ILog GetLogger( Type type );
ILog GetLogger( string name );
}
}
IbaitsNet中现在提供的实现有ConsoleOutLoggerFA,NoOpLoggerFA,TraceLoggerFA和IBatisNet.Common.Logging.Impl中的Log4NetLoggerFA 。对于前三种适配工厂都是生成Ibatis自定义的log服务的ILog服务;对于IBatisNet.Common.Logging.Impl中的Log4NetLoggerFA 主要用于生成适配log4Net日志服务的ILog实现。我们看一下ConsoleOutLoggerFA的实现。
public ILog GetLogger(Type type)
{
return GetLogger( type.FullName );
}
public ILog GetLogger( string name)
{
// 略作修改,省略了缓存
ILog log = new ConsoleOutLogger( name, _Level, _showDateTime, _showLogName,
return log;
}
我们可以看到这个适配工厂其实就是构造并返回了一个实现了ILog接口的具体类ConsoleOutLogger。当然该类的构造函数用传入的属性数组初始化了该ConsoleOutLogger。现面是ConsoleOutLogger的部分实现:
public class ConsoleOutLogger: ILog // 实现了ILog接口
构造函数设置了LogLevel和其他相关的参数bool showDateTime, bool showLogName, string dateTimeFormat。
public ConsoleOutLogger( string logName, LogLevel logLevel, bool showDateTime, bool showLogName, string dateTimeFormat)
{
_logName = logName;
_currentLogLevel = logLevel;
_showDateTime = showDateTime;
_showLogName = showLogName;
_dateTimeFormat = dateTimeFormat;
if (_dateTimeFormat != null && _dateTimeFormat.Length > 0 )
{
_hasDateTimeFormat = true ;
}
}
IsDebugEnabled通过构造时的LogLevel判断Debug开关状态。
public bool IsDebugEnabled
{
get { return IsLevelEnabled( LogLevel.Debug ); }
}
对于debug输出
public void Debug( object message)
{
Debug( message, null );
}
public void Debug( object message, Exception e)
{
if ( IsLevelEnabled( LogLevel.Debug ) )
{
Write( LogLevel.Debug, message, e );
}
}
Write方法构造日志信息,并输出到System.Console.Out
private void Write( LogLevel level, object message, Exception e )
另外public sealed class NoOpLogger: ILog 是一个不产生任何输出的缺省日志ILog实现类。
二.使用
上面简单的介绍了Ibatis Common Logging的主要接口,现在看看它的使用。Logging的使用很简单。程序中需要日志的类或方法可以类似下面的方式实现:
1.通过LogManager获取一个实现了ILog接口的日志实现类,关于使用那种具体实现在配置文件中配置。
private static readonly ILog _logger = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType );
或
private static readonly ILog _logger = LogManager.GetLogger( typeof (具体类名));
推荐使用第一种。
2.使用ILog的模式
if (_logger.IsDebugEnabled)
{
_logger.Debug( " Dao Proxy call to " + invocation.Method.Name);
}
3. 配置Logging使用简单,关键在于配置。配置是通过ConfigurationSectionHandler 处理的,public class ConfigurationSectionHandler: IConfigurationSectionHandler ,其中实现的create方法根据配置生成了LogSetting。LogSetting封装了FactoryAdapterType和Properties。这些信息是从配置中获取的。
public Type FactoryAdapterType{ get { return _factoryAdapterType; }}
public NameValueCollection Properties{ get { return _properties; }}
Common 测试包中自带的配置例子如下:
< configSections >
< sectionGroup name ="iBATIS" >
< section name ="logging" type ="IBatisNet.Common.Logging.ConfigurationSectionHandler, IBatisNet.Common" />
</ sectionGroup >
</ configSections >
上面的配置告诉我们对于iBATIS 配置组中的logging配置节,使用IBatisNet.Common.Logging.ConfigurationSectionHandler。
< iBATIS >
< logging >
< logFactoryAdapter type ="IBatisNet.Common.Logging.Impl.ConsoleOutLoggerFA, IBatisNet.Common" >
< arg key ="showLogName" value ="true" />
< arg key ="showDateTime" value ="true" />
< arg key ="level" value ="All" />
< arg key ="dateTimeFormat" value ="yyyy/MM/dd HH:mm:ss:SSS" />
< /logFactoryAdapter >
</ logging >
</ iBATIS >
上面的配置节是Ibatis commons Logging使用的,我们通过LogManger的GetLogger方法获取ILog时,LogManger会首先去看配置文件中是否已经配置了上面的logging节,如果没有配置就会构造ConsoleOutLoggerFA 适配工厂类的实例(BuildDefaultLoggerFactoryAdapter()),也就是说common logging会使用ConsoleOutLogger。否则如果有配置但logFactoryAdapter中定义的type不是ILoggerFactoryAdapter实现,则也会使用ConsoleOutLogger。否则会按照type指定的类型通过反射生成一个具体ILoggerFactoryAdapter实现类的子类,并有这个类生成实现了ILog接口的log组件。