Full Implementation 1️⃣ IAppLogger public interface IAppLogger { void Debug(string message, Exception ex = null); void Info(string message, Exception ex = null); void Warn(string message, Exception ex = null); void Error(string message, Exception ex = null); } ________________________________________ 2️⃣ NullLogger public sealed class NullLogger : IAppLogger { public void Debug(string message, Exception ex = null) { } public void Info(string message, Exception ex = null) { } public void Warn(string message, Exception ex = null) { } public void Error(string message, Exception ex = null) { } } ________________________________________ 3️⃣ Log (Facade) using System; using System.IO; using log4net; using log4net.Appender; using log4net.Config; using log4net.Layout; public static class Log { private static IAppLogger _current = new NullLogger(); public static IAppLogger Current { get => _current; set => _current = value ?? new NullLogger(); } public static void Debug(string message, Exception ex = null) => Current.Debug(message, ex); public static void Info(string message, Exception ex = null) => Current.Info(message, ex); public static void Warn(string message, Exception ex = null) => Current.Warn(message, ex); public static void Error(string message, Exception ex = null) => Current.Error(message, ex); public static void SetDisabled() { Current = new NullLogger(); } public static void SetAdminFile(string adminLogPath) { var fullPath = ResolvePath(adminLogPath); EnsureDirectoryExists(fullPath); ProbeWriteAccess(fullPath); var layout = new PatternLayout("%date %-5level %logger - %message%newline%exception"); layout.ActivateOptions(); var appender = new RollingFileAppender { File = fullPath, AppendToFile = true, RollingStyle = RollingFileAppender.RollingMode.Size, MaximumFileSize = "5MB", MaxSizeRollBackups = 3, StaticLogFileName = true, Layout = layout }; appender.ActivateOptions(); BasicConfigurator.Configure(appender); Current = new Log4NetAdapter(); } public static void SetAdminAndUserFailure(string adminLogPath, string userLogPath) { var fullAdmin = ResolvePath(adminLogPath); EnsureDirectoryExists(fullAdmin); ProbeWriteAccess(fullAdmin); var layout = new PatternLayout("%date %-5level %logger - %message%newline%exception"); layout.ActivateOptions(); var fileAppender = new RollingFileAppender { File = fullAdmin, AppendToFile = true, RollingStyle = RollingFileAppender.RollingMode.Size, MaximumFileSize = "5MB", MaxSizeRollBackups = 3, StaticLogFileName = true, Layout = layout }; fileAppender.ActivateOptions(); var memoryAppender = new MemoryAppender(); memoryAppender.ActivateOptions(); BasicConfigurator.Configure(fileAppender, memoryAppender); Current = new Log4NetAdapterWithFailureFlushWithPath(memoryAppender, userLogPath); } public static void SetUserFailureOnly(string userLogPath) { Current = new UserLogOnlyAdapter(userLogPath); } internal static string ResolvePath(string logFilePath) { return Path.GetFullPath(logFilePath); } internal static void EnsureDirectoryExists(string fullPath) { var dir = Path.GetDirectoryName(fullPath); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); } internal static void ProbeWriteAccess(string fullPath) { using (File.Open(fullPath, FileMode.Append, FileAccess.Write)) { } } } ________________________________________ 4️⃣ Log4NetAdapter using log4net; public class Log4NetAdapter : IAppLogger { private readonly ILog _logger = LogManager.GetLogger(typeof(Log4NetAdapter)); public void Debug(string message, Exception ex = null) => _logger.Debug(message, ex); public void Info(string message, Exception ex = null) => _logger.Info(message, ex); public void Warn(string message, Exception ex = null) => _logger.Warn(message, ex); public void Error(string message, Exception ex = null) => _logger.Error(message, ex); } ________________________________________ 5️⃣ Log4NetAdapterWithFailureFlushWithPath Fixes included ✔ flush only once ✔ user appender created once using System; using log4net; using log4net.Appender; using log4net.Core; using log4net.Layout; public class Log4NetAdapterWithFailureFlushWithPath : IAppLogger { private readonly ILog _logger = LogManager.GetLogger(typeof(Log4NetAdapterWithFailureFlushWithPath)); private readonly MemoryAppender _memoryAppender; private readonly RollingFileAppender _userAppender; private bool _flushed; public string UserLogPath { get; } public Log4NetAdapterWithFailureFlushWithPath( MemoryAppender memoryAppender, string userLogPath) { _memoryAppender = memoryAppender; UserLogPath = userLogPath; var fullUserPath = Log.ResolvePath(UserLogPath); Log.EnsureDirectoryExists(fullUserPath); Log.ProbeWriteAccess(fullUserPath); var layout = new PatternLayout("%date %-5level %logger - %message%newline%exception"); layout.ActivateOptions(); _userAppender = new RollingFileAppender { File = fullUserPath, AppendToFile = true, RollingStyle = RollingFileAppender.RollingMode.Size, MaximumFileSize = "5MB", MaxSizeRollBackups = 1, StaticLogFileName = true, Layout = layout }; _userAppender.ActivateOptions(); } public void Debug(string message, Exception ex = null) => _logger.Debug(message, ex); public void Info(string message, Exception ex = null) => _logger.Info(message, ex); public void Warn(string message, Exception ex = null) => _logger.Warn(message, ex); public void Error(string message, Exception ex = null) { _logger.Error(message, ex); if (_flushed) return; foreach (var loggingEvent in _memoryAppender.GetEvents()) _userAppender.DoAppend(loggingEvent); _memoryAppender.Clear(); _flushed = true; } } ________________________________________ 6️⃣ UserLogOnlyAdapter using System; using log4net.Appender; using log4net.Core; using log4net.Layout; public class UserLogOnlyAdapter : IAppLogger { private readonly RollingFileAppender _userAppender; public UserLogOnlyAdapter(string userLogPath) { var fullPath = Log.ResolvePath(userLogPath); Log.EnsureDirectoryExists(fullPath); Log.ProbeWriteAccess(fullPath); var layout = new PatternLayout("%date %-5level %logger - %message%newline%exception"); layout.ActivateOptions(); _userAppender = new RollingFileAppender { File = fullPath, AppendToFile = true, RollingStyle = RollingFileAppender.RollingMode.Size, MaximumFileSize = "5MB", MaxSizeRollBackups = 1, StaticLogFileName = true, Layout = layout }; _userAppender.ActivateOptions(); } public void Debug(string message, Exception ex = null) { } public void Info(string message, Exception ex = null) { } public void Warn(string message, Exception ex = null) { } public void Error(string message, Exception ex = null) { var loggingEvent = new LoggingEvent( typeof(UserLogOnlyAdapter), LogManager.GetRepository(), "User", Level.Error, message, ex); _userAppender.DoAppend(loggingEvent); } } ________________________________________