Hello @Dani_S ,
I've reviewed your logging implementation. Overall, the architecture is solid.
A few issues and suggestions for improvement:
Unreachable code
In Program.cs, you have this problem:
private static void Main(string[] args)
{
ShowHelp();
return;
// everything below is unreachable
Console.OutputEncoding = System.Text.Encoding.UTF8;
args = EnsureDebugArgs(args);
Environment.Exit(Run(args));
}
return; should be removed so the rest of the method can execute. Or, if you intend to only show help and exit, remove the rest of the code.
The SetFile method does too many things
Your Log.SetFile method is about 80 lines long and handles multiple responsibilities.
You should break it into smaller, focused methods:
public static void SetFile(string logFilePath, string logLevel = "All")
{
if (string.IsNullOrWhiteSpace(logFilePath))
throw new ArgumentException("logFilePath cannot be null or empty.", nameof(logFilePath));
var fullPath = ResolvePath(logFilePath);
EnsureDirectoryExists(fullPath);
ProbeWriteAccess(fullPath);
var appender = CreateRollingAppender(fullPath);
var level = ParseLogLevel(logLevel);
ConfigureRepository(appender, level);
Current = new Log4NetAdapter(LogManager.GetLogger(typeof(Log)));
}
private static string ResolvePath(string logFilePath)
{
return Path.GetFullPath(logFilePath);
}
private static void EnsureDirectoryExists(string fullPath)
{
var directory = Path.GetDirectoryName(fullPath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
}
private static void ProbeWriteAccess(string fullPath)
{
try
{
using (var fs = new FileStream(fullPath, FileMode.Append, FileAccess.Write, FileShare. Read))
{
// just testing write access
}
}
catch (Exception ex)
{
throw new IOException($"Cannot write to log file path '{fullPath}'. Check permissions and that the path is valid.", ex);
}
}
private static RollingFileAppender CreateRollingAppender(string fullPath)
{
var layout = new PatternLayout
{
ConversionPattern = "%date %-5level %logger - %message%newline%exception"
};
layout.ActivateOptions();
var roller = new RollingFileAppender
{
AppendToFile = true,
File = fullPath,
Layout = layout,
MaxSizeRollBackups = 5,
MaximumFileSize = "10MB",
RollingStyle = RollingFileAppender.RollingMode. Size,
StaticLogFileName = true,
LockingModel = new FileAppender.MinimalLock(),
Encoding = System.Text.Encoding. UTF8
};
roller.ActivateOptions();
return roller;
}
private static log4net.Core. Level ParseLogLevel(string logLevel)
{
var levelMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
["ALL"] = "ALL",
["DEBUG"] = "DEBUG",
["INFO"] = "INFO",
["WARN"] = "WARN",
["ERROR"] = "ERROR",
["FATAL"] = "FATAL",
["OFF"] = "OFF"
};
var normalizedLevel = (logLevel ?? "ALL").Trim().ToUpperInvariant();
var levelName = levelMap. ContainsKey(normalizedLevel) ? levelMap[normalizedLevel] : "ALL";
var entry = Assembly.GetEntryAssembly();
var repoAssembly = (Assembly)(entry ?? Assembly.GetExecutingAssembly());
var repo = LogManager.GetRepository(repoAssembly);
var hierarchy = repo as log4net.Repository. Hierarchy.Hierarchy;
return hierarchy?. LevelMap[levelName] ?? hierarchy?.LevelMap["ALL"];
}
private static void ConfigureRepository(RollingFileAppender appender, log4net.Core.Level level)
{
var entry = Assembly.GetEntryAssembly();
var repoAssembly = (Assembly)(entry ?? Assembly.GetExecutingAssembly());
var repo = LogManager.GetRepository(repoAssembly);
var hierarchy = repo as log4net.Repository.Hierarchy.Hierarchy;
if (hierarchy != null)
{
hierarchy. ResetConfiguration();
}
log4net.Config.BasicConfigurator.Configure(repo, appender);
if (hierarchy != null)
{
hierarchy.Root.Level = level;
hierarchy.Configured = true;
}
}