Author: bodewig
Date: Sun Oct 16 10:32:49 2016
New Revision: 1765136

URL: http://svn.apache.org/viewvc?rev=1765136&view=rev
Log:
LOG4NET-511 Implement flushing of appenders that buffer data

Patch by @JJoe2

closes #37

Added:
    logging/log4net/trunk/src/Appender/IFlushable.cs   (with props)
Modified:
    logging/log4net/trunk/src/Appender/BufferingAppenderSkeleton.cs
    logging/log4net/trunk/src/Appender/DebugAppender.cs
    logging/log4net/trunk/src/Appender/RemotingAppender.cs
    logging/log4net/trunk/src/Appender/TextWriterAppender.cs
    logging/log4net/trunk/src/Appender/TraceAppender.cs
    logging/log4net/trunk/src/LogManager.cs
    logging/log4net/trunk/src/Repository/LoggerRepositorySkeleton.cs
    logging/log4net/trunk/src/log4net.vs2008.csproj
    logging/log4net/trunk/src/log4net.vs2010.csproj
    logging/log4net/trunk/src/log4net.vs2012.csproj

Modified: logging/log4net/trunk/src/Appender/BufferingAppenderSkeleton.cs
URL: 
http://svn.apache.org/viewvc/logging/log4net/trunk/src/Appender/BufferingAppenderSkeleton.cs?rev=1765136&r1=1765135&r2=1765136&view=diff
==============================================================================
--- logging/log4net/trunk/src/Appender/BufferingAppenderSkeleton.cs (original)
+++ logging/log4net/trunk/src/Appender/BufferingAppenderSkeleton.cs Sun Oct 16 
10:32:49 2016
@@ -68,7 +68,7 @@ namespace log4net.Appender
        /// </remarks>
        /// <author>Nicko Cadell</author>
        /// <author>Gert Driesen</author>
-       public abstract class BufferingAppenderSkeleton : AppenderSkeleton
+    public abstract class BufferingAppenderSkeleton : AppenderSkeleton, 
IFlushable
        {
                #region Protected Instance Constructors
 
@@ -261,6 +261,17 @@ namespace log4net.Appender
 
                #region Public Methods
 
+        /// <summary>
+        /// Flushes any buffered log data.
+        /// </summary>
+        /// <param name="millisecondsTimeout">The maximum time to wait for 
logging events to be flushed.</param>
+        /// <returns><c>True</c> if all logging events were flushed 
successfully, else <c>false</c>.</returns>
+        public virtual bool Flush(int millisecondsTimeout)
+        {
+            Flush();
+            return true;
+        }
+
                /// <summary>
                /// Flush the currently buffered events
                /// </summary>

Modified: logging/log4net/trunk/src/Appender/DebugAppender.cs
URL: 
http://svn.apache.org/viewvc/logging/log4net/trunk/src/Appender/DebugAppender.cs?rev=1765136&r1=1765135&r2=1765136&view=diff
==============================================================================
--- logging/log4net/trunk/src/Appender/DebugAppender.cs (original)
+++ logging/log4net/trunk/src/Appender/DebugAppender.cs Sun Oct 16 10:32:49 2016
@@ -40,7 +40,7 @@ namespace log4net.Appender
        /// </para>
        /// </remarks>
        /// <author>Nicko Cadell</author>
-       public class DebugAppender : AppenderSkeleton
+    public class DebugAppender : AppenderSkeleton, IFlushable
        {
                #region Public Instance Constructors
 
@@ -102,6 +102,23 @@ namespace log4net.Appender
 
                #endregion Public Instance Properties
 
+
+            /// <summary>
+            /// Flushes any buffered log data.
+            /// </summary>
+            /// <param name="millisecondsTimeout">The maximum time to wait for 
logging events to be flushed.</param>
+            /// <returns><c>True</c> if all logging events were flushed 
successfully, else <c>false</c>.</returns>
+            public bool Flush(int millisecondsTimeout)
+            {
+                // Nothing to do if ImmediateFlush is true
+                if (m_immediateFlush) return true;
+
+                // System.Diagnostics.Debug is thread-safe, so no need for 
lock(this).
+                System.Diagnostics.Debug.Flush();
+
+                return true;
+            }
+
                #region Override implementation of AppenderSkeleton
 
                /// <summary>

Added: logging/log4net/trunk/src/Appender/IFlushable.cs
URL: 
http://svn.apache.org/viewvc/logging/log4net/trunk/src/Appender/IFlushable.cs?rev=1765136&view=auto
==============================================================================
--- logging/log4net/trunk/src/Appender/IFlushable.cs (added)
+++ logging/log4net/trunk/src/Appender/IFlushable.cs Sun Oct 16 10:32:49 2016
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace log4net.Appender
+{
+    /// <summary>
+    /// Interface that can be implemented by Appenders that buffer logging 
data and expose a <see cref="Flush"/> method.
+    /// </summary>
+    public interface IFlushable
+    {
+        /// <summary>
+        /// Flushes any buffered log data.
+        /// </summary>
+        /// <remarks>
+        /// Appenders that implement the <see cref="Flush"/> method must do so 
in a thread-safe manner: it can be called concurrently with
+        /// the <see cref="log4net.Appender.IAppender.DoAppend"/> method.
+        /// <para>
+        /// Typically this is done by locking on the Appender instance, e.g.:
+        /// <code>
+        /// <![CDATA[
+        /// public bool Flush(int millisecondsTimeout)
+        /// {
+        ///     lock(this)
+        ///     {
+        ///         // Flush buffered logging data
+        ///         ...
+        ///     }
+        /// }
+        /// ]]>
+        /// </code>
+        /// </para>
+        /// <para>
+        /// The <paramref name="millisecondsTimeout"/> parameter is only 
relevant for appenders that process logging events asynchronously,
+        /// such as <see cref="RemotingAppender"/>.
+        /// </para>
+        /// </remarks>
+        /// <param name="millisecondsTimeout">The maximum time to wait for 
logging events to be flushed.</param>
+        /// <returns><c>True</c> if all logging events were flushed 
successfully, else <c>false</c>.</returns>
+        bool Flush(int millisecondsTimeout);
+    }
+}

Propchange: logging/log4net/trunk/src/Appender/IFlushable.cs
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: logging/log4net/trunk/src/Appender/RemotingAppender.cs
URL: 
http://svn.apache.org/viewvc/logging/log4net/trunk/src/Appender/RemotingAppender.cs?rev=1765136&r1=1765135&r2=1765136&view=diff
==============================================================================
--- logging/log4net/trunk/src/Appender/RemotingAppender.cs (original)
+++ logging/log4net/trunk/src/Appender/RemotingAppender.cs Sun Oct 16 10:32:49 
2016
@@ -218,6 +218,17 @@ namespace log4net.Appender
                        }
                }
 
+               /// <summary>
+               /// Flushes any buffered log data.
+               /// </summary>
+               /// <param name="millisecondsTimeout">The maximum time to wait 
for logging events to be flushed.</param>
+               /// <returns><c>True</c> if all logging events were flushed 
successfully, else <c>false</c>.</returns>
+               public override bool Flush(int millisecondsTimeout)
+               {
+                       base.Flush();
+                       return 
m_workQueueEmptyEvent.WaitOne(millisecondsTimeout, false);
+               }
+
                #endregion
 
                /// <summary>

Modified: logging/log4net/trunk/src/Appender/TextWriterAppender.cs
URL: 
http://svn.apache.org/viewvc/logging/log4net/trunk/src/Appender/TextWriterAppender.cs?rev=1765136&r1=1765135&r2=1765136&view=diff
==============================================================================
--- logging/log4net/trunk/src/Appender/TextWriterAppender.cs (original)
+++ logging/log4net/trunk/src/Appender/TextWriterAppender.cs Sun Oct 16 
10:32:49 2016
@@ -42,7 +42,7 @@ namespace log4net.Appender
        /// <author>Nicko Cadell</author>
        /// <author>Gert Driesen</author>
        /// <author>Douglas de la Torre</author>
-       public class TextWriterAppender : AppenderSkeleton
+    public class TextWriterAppender : AppenderSkeleton, IFlushable
        {
                #region Public Instance Constructors
 
@@ -481,5 +481,24 @@ namespace log4net.Appender
            private readonly static Type declaringType = 
typeof(TextWriterAppender);
 
            #endregion Private Static Fields
+
+            /// <summary>
+            /// Flushes any buffered log data.
+            /// </summary>
+            /// <param name="millisecondsTimeout">The maximum time to wait for 
logging events to be flushed.</param>
+            /// <returns><c>True</c> if all logging events were flushed 
successfully, else <c>false</c>.</returns>
+            public bool Flush(int millisecondsTimeout)
+            {
+                // Nothing to do if ImmediateFlush is true
+                if (m_immediateFlush) return true;
+
+                // lock(this) will block any Appends while the buffer is 
flushed.
+                lock (this)
+                {
+                    m_qtw.Flush();
+                }
+
+                return true;
+            }
        }
 }

Modified: logging/log4net/trunk/src/Appender/TraceAppender.cs
URL: 
http://svn.apache.org/viewvc/logging/log4net/trunk/src/Appender/TraceAppender.cs?rev=1765136&r1=1765135&r2=1765136&view=diff
==============================================================================
--- logging/log4net/trunk/src/Appender/TraceAppender.cs (original)
+++ logging/log4net/trunk/src/Appender/TraceAppender.cs Sun Oct 16 10:32:49 2016
@@ -51,7 +51,7 @@ namespace log4net.Appender
        /// <author>Nicko Cadell</author>
        /// <author>Gert Driesen</author>
     /// <author>Ron Grabowski</author>
-       public class TraceAppender : AppenderSkeleton
+       public class TraceAppender : AppenderSkeleton, IFlushable
        {
                #region Public Instance Constructors
 
@@ -206,5 +206,24 @@ namespace log4net.Appender
         private PatternLayout m_category = new PatternLayout("%logger");
 
                #endregion Private Instance Fields
-       }
+
+        /// <summary>
+        /// Flushes any buffered log data.
+        /// </summary>
+        /// <param name="millisecondsTimeout">The maximum time to wait for 
logging events to be flushed.</param>
+        /// <returns><c>True</c> if all logging events were flushed 
successfully, else <c>false</c>.</returns>
+        public bool Flush(int millisecondsTimeout)
+        {
+            // Nothing to do if ImmediateFlush is true
+            if (m_immediateFlush) return true;
+
+            // System.Diagnostics.Trace and System.Diagnostics.Debug are 
thread-safe, so no need for lock(this).
+#if NETCF
+                       System.Diagnostics.Debug.Flush();
+#else
+            System.Diagnostics.Trace.Flush();
+#endif
+            return true;
+        }
+    }
 }

Modified: logging/log4net/trunk/src/LogManager.cs
URL: 
http://svn.apache.org/viewvc/logging/log4net/trunk/src/LogManager.cs?rev=1765136&r1=1765135&r2=1765136&view=diff
==============================================================================
--- logging/log4net/trunk/src/LogManager.cs (original)
+++ logging/log4net/trunk/src/LogManager.cs Sun Oct 16 10:32:49 2016
@@ -751,6 +751,25 @@ namespace log4net
                        return LoggerManager.GetAllRepositories();
                }
 
+            /// <summary>
+            /// Flushes logging events buffered in all configured appenders in 
the default repository.
+            /// </summary>
+            /// <param name="millisecondsTimeout">The maximum time in 
milliseconds to wait for logging events from asycnhronous appenders to be 
flushed,
+            /// or <see cref="Timeout.Infinite"/> to wait indefinitely.</param>
+            /// <returns><c>True</c> if all logging events were flushed 
successfully, else <c>false</c>.</returns>
+            public static bool Flush(int millisecondsTimeout)
+            {
+                Appender.IFlushable flushableRepository = 
LoggerManager.GetRepository(Assembly.GetCallingAssembly()) as 
Appender.IFlushable;
+                if (flushableRepository == null)
+                {
+                    return false;
+                }
+                else
+                {
+                    return flushableRepository.Flush(millisecondsTimeout);
+                }
+            }
+
                #endregion Domain & Repository Manager Methods
 
                #region Extension Handlers

Modified: logging/log4net/trunk/src/Repository/LoggerRepositorySkeleton.cs
URL: 
http://svn.apache.org/viewvc/logging/log4net/trunk/src/Repository/LoggerRepositorySkeleton.cs?rev=1765136&r1=1765135&r2=1765136&view=diff
==============================================================================
--- logging/log4net/trunk/src/Repository/LoggerRepositorySkeleton.cs (original)
+++ logging/log4net/trunk/src/Repository/LoggerRepositorySkeleton.cs Sun Oct 16 
10:32:49 2016
@@ -23,6 +23,7 @@ using log4net.ObjectRenderer;
 using log4net.Core;
 using log4net.Util;
 using log4net.Plugin;
+using System.Threading;
 
 namespace log4net.Repository
 {
@@ -40,7 +41,7 @@ namespace log4net.Repository
        /// </remarks>
        /// <author>Nicko Cadell</author>
        /// <author>Gert Driesen</author>
-       public abstract class LoggerRepositorySkeleton : ILoggerRepository
+       public abstract class LoggerRepositorySkeleton : ILoggerRepository, 
Appender.IFlushable
        {
                #region Member Variables
 
@@ -573,5 +574,59 @@ namespace log4net.Repository
                {
                        OnConfigurationChanged(e);
                }
+
+        private static int GetWaitTime(DateTime startTimeUtc, int 
millisecondsTimeout)
+        {
+            if (millisecondsTimeout == Timeout.Infinite) return 
Timeout.Infinite;
+            if (millisecondsTimeout == 0) return 0;
+
+            int elapsedMilliseconds = (int)(DateTime.UtcNow - 
startTimeUtc).TotalMilliseconds;
+            int timeout = millisecondsTimeout - elapsedMilliseconds;
+            if (timeout < 0) timeout = 0;
+            return timeout;
+        }
+
+        /// <summary>
+        /// Flushes all configured Appenders that implement <see 
cref="log4net.Appender.IFlushable"/>.
+        /// </summary>
+        /// <param name="millisecondsTimeout">The maximum time in milliseconds 
to wait for logging events from asycnhronous appenders to be flushed,
+        /// or <see cref="Timeout.Infinite"/> to wait indefinitely.</param>
+        /// <returns><c>True</c> if all logging events were flushed 
successfully, else <c>false</c>.</returns>
+        public bool Flush(int millisecondsTimeout)
+        {
+            if (millisecondsTimeout < -1) throw new 
ArgumentOutOfRangeException("millisecondsTimeout", "Timeout must be -1 
(Timeout.Infinite) or non-negative");
+
+            // Assume success until one of the appenders fails
+            bool result = true;
+
+            // Use DateTime.UtcNow rather than a System.Diagnostics.Stopwatch 
for compatibility with .NET 1.x
+            DateTime startTimeUtc = DateTime.UtcNow;
+
+            // Do buffering appenders first.  These may be forwarding to other 
appenders
+            foreach(var appender in GetAppenders())
+            {
+                log4net.Appender.IFlushable flushable = appender as 
log4net.Appender.IFlushable;
+                if (flushable == null) continue;
+                if (appender is Appender.BufferingAppenderSkeleton)
+                {
+                    int timeout = GetWaitTime(startTimeUtc, 
millisecondsTimeout);
+                    if (!flushable.Flush(timeout)) result = false;
+                }
+            }
+
+            // Do non-buffering appenders.
+            foreach (var appender in GetAppenders())
+            {
+                log4net.Appender.IFlushable flushable = appender as 
log4net.Appender.IFlushable;
+                if (flushable == null) continue;
+                if (!(appender is Appender.BufferingAppenderSkeleton))
+                {
+                    int timeout = GetWaitTime(startTimeUtc, 
millisecondsTimeout);
+                    if (!flushable.Flush(timeout)) result = false;
+                }
+            }
+
+            return result;
+        }
        }
 }

Modified: logging/log4net/trunk/src/log4net.vs2008.csproj
URL: 
http://svn.apache.org/viewvc/logging/log4net/trunk/src/log4net.vs2008.csproj?rev=1765136&r1=1765135&r2=1765136&view=diff
==============================================================================
--- logging/log4net/trunk/src/log4net.vs2008.csproj (original)
+++ logging/log4net/trunk/src/log4net.vs2008.csproj Sun Oct 16 10:32:49 2016
@@ -148,6 +148,9 @@
     <Compile Include="Appender\IBulkAppender.cs">
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="Appender\IFlushable.cs">
+      <SubType>Code</SubType>
+    </Compile>
     <Compile Include="Appender\LocalSyslogAppender.cs">
       <SubType>Code</SubType>
     </Compile>

Modified: logging/log4net/trunk/src/log4net.vs2010.csproj
URL: 
http://svn.apache.org/viewvc/logging/log4net/trunk/src/log4net.vs2010.csproj?rev=1765136&r1=1765135&r2=1765136&view=diff
==============================================================================
--- logging/log4net/trunk/src/log4net.vs2010.csproj (original)
+++ logging/log4net/trunk/src/log4net.vs2010.csproj Sun Oct 16 10:32:49 2016
@@ -166,6 +166,9 @@
     <Compile Include="Appender\IBulkAppender.cs">
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="Appender\IFlushable.cs">
+      <SubType>Code</SubType>
+    </Compile>
     <Compile Include="Appender\LocalSyslogAppender.cs">
       <SubType>Code</SubType>
     </Compile>

Modified: logging/log4net/trunk/src/log4net.vs2012.csproj
URL: 
http://svn.apache.org/viewvc/logging/log4net/trunk/src/log4net.vs2012.csproj?rev=1765136&r1=1765135&r2=1765136&view=diff
==============================================================================
--- logging/log4net/trunk/src/log4net.vs2012.csproj (original)
+++ logging/log4net/trunk/src/log4net.vs2012.csproj Sun Oct 16 10:32:49 2016
@@ -166,6 +166,9 @@
     <Compile Include="Appender\IBulkAppender.cs">
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="Appender\IFlushable.cs">
+      <SubType>Code</SubType>
+    </Compile>
     <Compile Include="Appender\LocalSyslogAppender.cs">
       <SubType>Code</SubType>
     </Compile>


Reply via email to