Log4net - dynamically switch appender between AdoNetAppender and RollingFileAppender

故事扮演 提交于 2019-12-18 16:27:12

问题


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


回答1:


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.




回答2:


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.

  • A default appender called "PrimaryAppender" - used by default, until it fails.
  • A failover appender called "FailoverAppender" - used only after the primary fails.

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>


来源:https://stackoverflow.com/questions/836385/log4net-dynamically-switch-appender-between-adonetappender-and-rollingfileappe

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!