如何知道log4net是否记录了一个错误
本文关键字:一个 错误 何知道 log4net 是否 记录 | 更新日期: 2023-09-27 17:49:25
我在控制台应用程序中使用log4net,在if/else结构中多次使用log.Error("Message to log");
。
我的应用程序必须返回一个代码,该代码指定在应用程序运行期间是否发生错误(0→ok, 1→至少发生1个错误)。
是否有一种方法可以询问log4net是否记录了错误,例如:
bool b = LogManager.AtLeastOneErrorHasBeenLogged;
如果您使用一个自定义appender,其唯一目的是跟踪是否发生错误,这看起来会很简单。
这个(未经测试的)示例使用的技术是,只有当日志级别为Error时,才使用LevelRangeFilter
调用appender,但是您也可以在Append方法或根日志记录器配置中轻松检查日志级别(或其他标准)。该示例假设您正在使用XML配置而不是编程配置,但是可以通过编程方式添加追加器,以便所有记录器都使用它们。
appender:
public namespace MyApp
{
public class ErrorFlagAppender : AppenderSkeleton
{
public bool ErrorOccurred { get; set; }
protected override void Append(LoggingEvent loggingEvent)
{
ErrorOccurred = true;
}
}
}
配置:
<appender name="ErrorFlagAppender" type="MyApp.ErrorFlagAppender,MyApp" >
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="ERROR"/>
<levelMax value="ERROR"/>
</filter>
</appender>
<root>
<appender-ref ref="[your existingappender]" />
<appender-ref ref="ErrorFlagAppender" />
</root>
然后你可以有一个扩展方法来查看是否发生了错误:
public static class LogManagerExtensions
{
public static bool AtLeastOneErrorHasBeenLogged(this LogManager logManager)
{
var flagAppenders = logManager.GetRepository()
.GetAppenders()
.OfType<ErrorFlagAppender>();
return flagAppenders.Any(f => f. ErrorOccurred);
}
}
我认为大多数人会认为询问log4net(或任何可能使用的日志框架)是否记录错误的想法是非常奇怪的。您可以控制调用log4net,因此,如果发生错误,为什么不自己跟踪呢?如果程序的用户在配置文件中关闭了日志记录,该怎么办?如果在关闭日志记录时发生了错误,并且您依赖于是否记录了错误,那么您无法知道发生了错误。Nicholas Carey建议在catch块中添加逻辑来跟踪异常是否发生。即使你不使用异常,你也可以在if/then/else逻辑中做类似的事情:
(请注意,我借用Nicholas Carey的样本作为我的答案的基础)
static int Main( string[] argv )
{
static int errorOccurred = 0;
try
{
log.Info("Begin");
if (SomeImportantPreconditionExists())
{
DoSomeStuff();
if (DoingSomeStuffWorkedRight())
{
Hooray();
}
else
{
log.Error("DoSomeStuff seems to have failed");
ErrorOccurred();
}
}
else
{
log.Error("SomeImportantPrecondition does not exist");
ErrorOccurred();
}
}
catch( Exception e )
{
log.Error("Exception of some sort", e);
ErrorOccurred();
}
return ErrorStatus();
}
private static void InitializeErrorOccurred()
{
errorOccurred = 0;
}
private static void ErrorOccurred()
{
errorOccurred = 1;
}
private static int ErrorStatus()
{
return errorOccurred;
}
在发布了这些代码之后,我不得不说我认为你可能会想出一个比我发布的更健壮的解决方案。
我最后的建议是不要让你的程序逻辑依赖于日志框架做(或不)的事情。一般来说,无论是否启用日志记录,您的程序都应该以相同的方式运行(尽管当启用日志记录时,消息将被记录)。
我不这么认为。但是使用装饰器模式装饰ILog
接口来收集该信息是很容易的。问题是,log4net实例化记录器的标准方法是让每个类通过LogManager.GetLogger(Type t)
实例化自己的特定于类的记录器实例。
然而,你不应该只是捕捉异常在你的Main()
方法,记录它和退出条件代码设置为零或1适当?
static int Main( string[] argv )
{
int cc ;
try
{
ExecApplicationCore( argv ) ;
cc = 0 ;
}
catch( Exception e )
{
ILog log = LogManager.GetLogger(this.GetType()) ;
log.Fatal(e) ;
cc = 1 ;
}
return cc ;
}
这就是异常的意义所在。如果你不能真正地处理它,你就不应该让抓住它:让它冒泡到顶部。
编辑说明:ILog
装饰和工厂示例:
using log4net;
using log4net.Core;
using log4net.Repository;
public class CountingLogger : ILog , ILogger
{
public IDictionary<Level , int> Counts { get; private set; }
private ILog Log4Net { get; set; }
public CountingLogger( ILog logger )
{
this.Log4Net = logger ;
this.Counts = this.Log4Net.Logger.Repository.LevelMap.AllLevels.Cast<Level>().ToDictionary( x => x , x => 0 ) ;
return;
}
private void Count( Level level )
{
int count;
bool success = this.Counts.TryGetValue( level , out count );
this.Counts[level] = ++count;
return;
}
public bool IsDebugEnabled { get { return Log4Net.IsDebugEnabled ; } }
public bool IsErrorEnabled { get { return Log4Net.IsErrorEnabled ; } }
public bool IsFatalEnabled { get { return Log4Net.IsFatalEnabled ; } }
public bool IsInfoEnabled { get { return Log4Net.IsInfoEnabled ; } }
public bool IsWarnEnabled { get { return Log4Net.IsWarnEnabled ; } }
public ILogger Logger { get { return this ; } }
public void Debug( object message , Exception exception ) { Count( Level.Debug ) ; Log4Net.Debug( message , exception ) ; }
public void Info( object message , Exception exception ) { Count( Level.Info ) ; Log4Net.Info( message , exception ) ; }
public void Warn( object message , Exception exception ) { Count( Level.Warn ) ; Log4Net.Warn( message , exception ) ; }
public void Error( object message , Exception exception ) { Count( Level.Error ) ; Log4Net.Error( message , exception ) ; }
public void Fatal( object message , Exception exception ) { Count( Level.Fatal ) ; Log4Net.Fatal( message , exception ) ; }
public void Debug( object message ) { Count( Level.Debug ) ; Log4Net.Debug( message ) ; }
public void Info( object message ) { Count( Level.Info ) ; Log4Net.Info( message ) ; }
public void Warn( object message ) { Count( Level.Warn ) ; Log4Net.Warn( message ) ; }
public void Error( object message ) { Count( Level.Error ) ; Log4Net.Error( message ) ; }
public void Fatal( object message ) { Count( Level.Fatal ) ; Log4Net.Fatal( message ) ; }
public void DebugFormat( IFormatProvider provider , string format , params object[] args ) { Count( Level.Debug ) ; Log4Net.DebugFormat( provider , format , args ) ; }
public void InfoFormat( IFormatProvider provider , string format , params object[] args ) { Count( Level.Info ) ; Log4Net.InfoFormat( provider , format , args ) ; }
public void WarnFormat( IFormatProvider provider , string format , params object[] args ) { Count( Level.Warn ) ; Log4Net.WarnFormat( provider , format , args ) ; }
public void ErrorFormat( IFormatProvider provider , string format , params object[] args ) { Count( Level.Error ) ; Log4Net.ErrorFormat( provider , format , args ) ; }
public void FatalFormat( IFormatProvider provider , string format , params object[] args ) { Count( Level.Fatal ) ; Log4Net.FatalFormat( provider , format , args ) ; }
public void DebugFormat( string format , object arg0 , object arg1 , object arg2 ) { Count( Level.Debug ) ; Log4Net.DebugFormat( format , arg0 , arg1 , arg2 ) ; }
public void InfoFormat( string format , object arg0 , object arg1 , object arg2 ) { Count( Level.Info ) ; Log4Net.InfoFormat( format , arg0 , arg1 , arg2 ) ; }
public void WarnFormat( string format , object arg0 , object arg1 , object arg2 ) { Count( Level.Warn ) ; Log4Net.WarnFormat( format , arg0 , arg1 , arg2 ) ; }
public void ErrorFormat( string format , object arg0 , object arg1 , object arg2 ) { Count( Level.Error ) ; Log4Net.ErrorFormat( format , arg0 , arg1 , arg2 ) ; }
public void FatalFormat( string format , object arg0 , object arg1 , object arg2 ) { Count( Level.Fatal ) ; Log4Net.FatalFormat( format , arg0 , arg1 , arg2 ) ; }
public void DebugFormat( string format , object arg0 , object arg1 ) { Count( Level.Debug ) ; Log4Net.DebugFormat( format , arg0 , arg1 ) ; }
public void InfoFormat( string format , object arg0 , object arg1 ) { Count( Level.Info ) ; Log4Net.InfoFormat( format , arg0 , arg1 ) ; }
public void WarnFormat( string format , object arg0 , object arg1 ) { Count( Level.Warn ) ; Log4Net.WarnFormat( format , arg0 , arg1 ) ; }
public void ErrorFormat( string format , object arg0 , object arg1 ) { Count( Level.Error ) ; Log4Net.ErrorFormat( format , arg0 , arg1 ) ; }
public void FatalFormat( string format , object arg0 , object arg1 ) { Count( Level.Fatal ) ; Log4Net.FatalFormat( format , arg0 , arg1 ) ; }
public void DebugFormat( string format , object arg0 ) { Count( Level.Debug ) ; Log4Net.DebugFormat( format , arg0 ) ; }
public void InfoFormat( string format , object arg0 ) { Count( Level.Info ) ; Log4Net.InfoFormat( format , arg0 ) ; }
public void WarnFormat( string format , object arg0 ) { Count( Level.Warn ) ; Log4Net.WarnFormat( format , arg0 ) ; }
public void ErrorFormat( string format , object arg0 ) { Count( Level.Error ) ; Log4Net.ErrorFormat( format , arg0 ) ; }
public void FatalFormat( string format , object arg0 ) { Count( Level.Fatal ) ; Log4Net.FatalFormat( format , arg0 ) ; }
public void DebugFormat( string format , params object[] args ) { Count( Level.Debug ) ; Log4Net.DebugFormat( format , args ) ; }
public void InfoFormat( string format , params object[] args ) { Count( Level.Info ) ; Log4Net.InfoFormat( format , args ) ; }
public void WarnFormat( string format , params object[] args ) { Count( Level.Warn ) ; Log4Net.WarnFormat( format , args ) ; }
public void ErrorFormat( string format , params object[] args ) { Count( Level.Error ) ; Log4Net.ErrorFormat( format , args ) ; }
public void FatalFormat( string format , params object[] args ) { Count( Level.Fatal ) ; Log4Net.FatalFormat( format , args ) ; }
#region ILogger implementation
bool ILogger.IsEnabledFor( Level level )
{
return this.Log4Net.Logger.IsEnabledFor( level ) ;
}
void ILogger.Log( LoggingEvent logEvent )
{
Count( logEvent.Level ) ;
this.Log4Net.Logger.Log( logEvent ) ;
return ;
}
void ILogger.Log( Type callerStackBoundaryDeclaringType , Level level , object message , Exception exception )
{
Count( level ) ;
this.Log4Net.Logger.Log( callerStackBoundaryDeclaringType , level , message , exception ) ;
return ;
}
string ILogger.Name { get { return this.Log4Net.Logger.Name ; } }
ILoggerRepository ILogger.Repository { get { return this.Log4Net.Logger.Repository ; } }
#endregion
}
static class LoggerFactory
{
public static ILog GetLogger( string name )
{
ILog log = LogManager.GetLogger( name );
ILog decoratedLogger = new CountingLogger( log );
return decoratedLogger;
}
public static ILog GetLogger( Type type )
{
ILog log = LogManager.GetLogger( type );
ILog decoratedLogger = new CountingLogger( log );
return decoratedLogger;
}
public static ILog GetLogger( string repository , string name )
{
ILog log = LogManager.GetLogger( repository , name );
ILog decoratedLogger = new CountingLogger( log );
return decoratedLogger;
}
public static ILog GetLogger( string repository , Type type )
{
ILog log = LogManager.GetLogger( repository , type );
ILog decoratedLogger = new CountingLogger( log );
return decoratedLogger;
}
public static ILog GetLogger( Assembly repositoryAssembly , string name )
{
ILog log = LogManager.GetLogger( repositoryAssembly , name );
ILog decoratedLogger = new CountingLogger( log );
return decoratedLogger;
}
public static ILog GetLogger( Assembly repositoryAssembly , Type type )
{
ILog log = LogManager.GetLogger( repositoryAssembly , type );
ILog decoratedLogger = new CountingLogger( log );
return decoratedLogger;
}
}