I am using AdoNetAppender (SQL server) in my asp.net application and would like use to RollingFileAppender incase of any connection issue with SQL. Is there any way to configure to use RollingFileAppender only when there is an issue with AdoNetAppender?
Thanks
por
There is no built in support for this kind of failover scenario in log4net, the problem being that appenders are quite isolated from each other in the log4net architecture.
A common setup though is to have both appenders logging in parallel, only that the file appender only keeps, say, a weeks worth of data. Should the AdoNetAppender fail you will always have the latest data in files.
But I definitively see the case here for an appender that could have a priority list of sub-appenders doing some simple failover in case of failure. This should not be too hard to implement either building on the AppenderSkeleton.
I've implemented such an appender and blogged about it here and here (mirror). The code can be found here.
I've extended AppenderSkeleton and created a new Appender called FailoverAppender that has two members of type AppenderSkeleton.
The actual type of the PrimaryAppender and the FailoverAppender are configured using log4net's xml configuration syntax (see an example below).
A snippet:
public class FailoverAppender : AppenderSkeleton
{
private AppenderSkeleton _primaryAppender;
private AppenderSkeleton _failOverAppender;
....
}
In the implementation of the Append method, I send by default LoggingEvents only to the PrimaryAppender and surround it with a try-catch. If the PrimaryAppender throws (fails), I signal a flag and send the LoggingEvent to the FailoverAppender. The next LoggingEvents will be sent directly and only to the FailoverAppender.
protected override void Append(LoggingEvent loggingEvent)
{
if (LogToFailOverAppender)
{
_failOverAppender?.DoAppend(loggingEvent);
}
else
{
try
{
_primaryAppender?.DoAppend(loggingEvent);
}
catch
{
ActivateFailOverMode();
Append(loggingEvent);
}
}
}
In addition, I created a custom ErrorHandler that will propagate inner-appender exceptions to signal that an appender has failed internally, which will let LoggingEvents to be sent only to the FailoverAppender.
class FailOverErrorHandler : IErrorHandler
{
public FailOverAppender FailOverAppender { get; set; }
public FailOverErrorHandler(FailOverAppender failOverAppender)
{
FailOverAppender = failOverAppender;
}
public void Error(string message, Exception e, ErrorCode errorCode)
=> FailOverAppender.ActivateFailOverMode();
public void Error(string message, Exception e)
=> FailOverAppender.ActivateFailOverMode();
public void Error(string message)
=> FailOverAppender.ActivateFailOverMode();
}
Configuration example:
<!--This custom appender handles failovers. If the first appender fails, it'll delegate the message to the back appender-->
<appender name="FailoverAppender" type="MoreAppenders.FailoverAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
</layout>
<!--This is a custom test appender that will always throw an exception -->
<!--The first and the default appender that will be used.-->
<PrimaryAppender type="MoreAppenders.ExceptionThrowerAppender" >
<ThrowExceptionForCount value="1" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
</layout>
</PrimaryAppender>
<!--This appender will be used only if the PrimaryAppender has failed-->
<FailOverAppender type="log4net.Appender.RollingFileAppender">
<file value="log.txt"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="100mb"/>
<appendToFile value="true"/>
<staticLogFileName value="true"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
</layout>
</FailOverAppender>
</appender>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With