2015-07-01 13:46:11 +02:00
using log4net.Core ;
using log4net.Util ;
2012-07-28 01:28:39 +06:00
using System ;
2016-06-22 11:48:52 +02:00
using System.ComponentModel ;
2015-07-01 13:46:11 +02:00
using System.Runtime.Remoting.Messaging ;
2012-07-28 01:28:39 +06:00
using System.Security.Principal ;
using System.Threading ;
using System.Threading.Tasks ;
using log4net.Appender ;
namespace Umbraco.Core.Logging
{
2015-07-01 13:46:11 +02:00
/// <summary>
/// Based on https://github.com/cjbhaines/Log4Net.Async
/// which is based on code by Chris Haines http://cjbhaines.wordpress.com/2012/02/13/asynchronous-log4net-appenders/
2016-06-22 11:48:52 +02:00
/// This is an old/deprecated logger and has been superceded by ParallelForwardingAppender which is included in Umbraco and
/// also by AsyncForwardingAppender in the Log4Net.Async library.
2012-07-28 01:28:39 +06:00
/// </summary>
2016-06-22 11:48:52 +02:00
[Obsolete("This is superceded by the ParallelForwardingAppender, this will be removed in v8")]
[EditorBrowsable(EditorBrowsableState.Never)]
2012-07-28 01:28:39 +06:00
public class AsynchronousRollingFileAppender : RollingFileAppender
{
2015-07-01 13:46:11 +02:00
private RingBuffer < LoggingEvent > pendingAppends ;
private readonly ManualResetEvent manualResetEvent ;
private bool shuttingDown ;
private bool hasFinished ;
private bool forceStop ;
private bool logBufferOverflow ;
private int bufferOverflowCounter ;
private DateTime lastLoggedBufferOverflow ;
private int queueSizeLimit = 1000 ;
public int QueueSizeLimit
{
get
{
return queueSizeLimit ;
}
set
{
queueSizeLimit = value ;
}
}
2012-07-28 01:28:39 +06:00
2015-07-01 13:46:11 +02:00
public AsynchronousRollingFileAppender ()
{
manualResetEvent = new ManualResetEvent ( false );
}
2012-07-28 01:28:39 +06:00
2015-07-01 13:46:11 +02:00
public override void ActivateOptions ()
{
base . ActivateOptions ();
pendingAppends = new RingBuffer < LoggingEvent >( QueueSizeLimit );
pendingAppends . BufferOverflow += OnBufferOverflow ;
StartAppendTask ();
}
2012-07-28 01:28:39 +06:00
2015-07-01 13:46:11 +02:00
protected override void Append ( LoggingEvent [] loggingEvents )
{
Array . ForEach ( loggingEvents , Append );
}
2012-07-28 01:28:39 +06:00
2015-07-01 13:46:11 +02:00
protected override void Append ( LoggingEvent loggingEvent )
{
if ( FilterEvent ( loggingEvent ))
{
pendingAppends . Enqueue ( loggingEvent );
}
}
2012-07-28 01:28:39 +06:00
2015-07-01 13:46:11 +02:00
protected override void OnClose ()
{
shuttingDown = true ;
manualResetEvent . WaitOne ( TimeSpan . FromSeconds ( 5 ));
2012-07-28 01:28:39 +06:00
2015-07-01 13:46:11 +02:00
if (! hasFinished )
{
forceStop = true ;
base . Append ( new LoggingEvent ( new LoggingEventData
{
Level = Level . Error ,
Message = "Unable to clear out the AsyncRollingFileAppender buffer in the allotted time, forcing a shutdown" ,
TimeStamp = DateTime . UtcNow ,
Identity = "" ,
ExceptionString = "" ,
UserName = WindowsIdentity . GetCurrent () != null ? WindowsIdentity . GetCurrent (). Name : "" ,
Domain = AppDomain . CurrentDomain . FriendlyName ,
ThreadName = Thread . CurrentThread . ManagedThreadId . ToString (),
LocationInfo = new LocationInfo ( this . GetType (). Name , "OnClose" , "AsyncRollingFileAppender.cs" , "75" ),
LoggerName = this . GetType (). FullName ,
Properties = new PropertiesDictionary (),
})
);
}
2012-07-28 01:28:39 +06:00
2015-07-01 13:46:11 +02:00
base . OnClose ();
}
2013-03-05 23:49:45 +06:00
2015-07-01 13:46:11 +02:00
private void StartAppendTask ()
{
if (! shuttingDown )
{
Task appendTask = new Task ( AppendLoggingEvents , TaskCreationOptions . LongRunning );
appendTask . LogErrors ( LogAppenderError ). ContinueWith ( x => StartAppendTask ()). LogErrors ( LogAppenderError );
appendTask . Start ();
}
}
2013-03-05 23:49:45 +06:00
2015-07-01 13:46:11 +02:00
private void LogAppenderError ( string logMessage , Exception exception )
{
base . Append ( new LoggingEvent ( new LoggingEventData
{
Level = Level . Error ,
Message = "Appender exception: " + logMessage ,
TimeStamp = DateTime . UtcNow ,
Identity = "" ,
ExceptionString = exception . ToString (),
UserName = WindowsIdentity . GetCurrent () != null ? WindowsIdentity . GetCurrent (). Name : "" ,
Domain = AppDomain . CurrentDomain . FriendlyName ,
ThreadName = Thread . CurrentThread . ManagedThreadId . ToString (),
LocationInfo = new LocationInfo ( this . GetType (). Name , "LogAppenderError" , "AsyncRollingFileAppender.cs" , "152" ),
LoggerName = this . GetType (). FullName ,
Properties = new PropertiesDictionary (),
}));
}
2012-07-28 01:28:39 +06:00
2015-07-01 13:46:11 +02:00
private void AppendLoggingEvents ()
{
LoggingEvent loggingEventToAppend ;
while (! shuttingDown )
{
if ( logBufferOverflow )
{
LogBufferOverflowError ();
logBufferOverflow = false ;
bufferOverflowCounter = 0 ;
lastLoggedBufferOverflow = DateTime . UtcNow ;
}
2012-07-28 01:28:39 +06:00
2015-07-01 13:46:11 +02:00
while (! pendingAppends . TryDequeue ( out loggingEventToAppend ))
{
Thread . Sleep ( 10 );
if ( shuttingDown )
{
break ;
}
}
if ( loggingEventToAppend == null )
{
continue ;
}
2012-07-28 01:28:39 +06:00
2015-07-01 13:46:11 +02:00
try
{
base . Append ( loggingEventToAppend );
}
catch
{
}
}
2012-07-28 01:28:39 +06:00
2015-07-01 13:46:11 +02:00
while ( pendingAppends . TryDequeue ( out loggingEventToAppend ) && ! forceStop )
{
try
{
base . Append ( loggingEventToAppend );
}
catch
{
}
}
hasFinished = true ;
manualResetEvent . Set ();
}
2012-07-28 01:28:39 +06:00
2015-07-01 13:46:11 +02:00
private void LogBufferOverflowError ()
{
base . Append ( new LoggingEvent ( new LoggingEventData
{
Level = Level . Error ,
Message = string . Format ( "Buffer overflow. {0} logging events have been lost in the last 30 seconds. [QueueSizeLimit: {1}]" , bufferOverflowCounter , QueueSizeLimit ),
TimeStamp = DateTime . UtcNow ,
Identity = "" ,
ExceptionString = "" ,
UserName = WindowsIdentity . GetCurrent () != null ? WindowsIdentity . GetCurrent (). Name : "" ,
Domain = AppDomain . CurrentDomain . FriendlyName ,
ThreadName = Thread . CurrentThread . ManagedThreadId . ToString (),
LocationInfo = new LocationInfo ( this . GetType (). Name , "LogBufferOverflowError" , "AsyncRollingFileAppender.cs" , "152" ),
LoggerName = this . GetType (). FullName ,
Properties = new PropertiesDictionary (),
}));
}
2012-07-28 01:28:39 +06:00
2015-07-01 13:46:11 +02:00
private void OnBufferOverflow ( object sender , EventArgs eventArgs )
{
bufferOverflowCounter ++;
if ( logBufferOverflow == false )
{
if ( lastLoggedBufferOverflow < DateTime . UtcNow . AddSeconds (- 30 ))
{
logBufferOverflow = true ;
}
}
}
}
2012-07-28 01:28:39 +06:00
}