124 lines
3.6 KiB
C#
124 lines
3.6 KiB
C#
namespace Logger;
|
|
|
|
/// <summary>
|
|
/// Logger implementation that writes to file with rotation support
|
|
/// </summary>
|
|
public class FileLogger : ILogger
|
|
{
|
|
private readonly FileLoggerOptions _options;
|
|
private readonly object _lockObject = new();
|
|
|
|
public FileLogger(FileLoggerOptions options)
|
|
{
|
|
_options = options ?? throw new ArgumentNullException(nameof(options));
|
|
EnsureLogDirectory();
|
|
}
|
|
|
|
public void Trace(string message) => Log(LogLevel.Trace, message);
|
|
public void Debug(string message) => Log(LogLevel.Debug, message);
|
|
public void Info(string message) => Log(LogLevel.Info, message);
|
|
public void Warning(string message) => Log(LogLevel.Warning, message);
|
|
public void Error(string message) => Log(LogLevel.Error, message);
|
|
public void Fatal(string message) => Log(LogLevel.Fatal, message);
|
|
|
|
public void Log(LogLevel level, string message)
|
|
{
|
|
if (level < _options.MinimumLevel)
|
|
return;
|
|
|
|
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
|
var formattedMessage = $"[{timestamp}] [{level}] {message}";
|
|
|
|
lock (_lockObject)
|
|
{
|
|
try
|
|
{
|
|
RotateFileIfNeeded();
|
|
var logPath = GetLogFilePath();
|
|
File.AppendAllText(logPath, formattedMessage + Environment.NewLine);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.Error.WriteLine($"Error writing to log file: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
|
|
private void EnsureLogDirectory()
|
|
{
|
|
try
|
|
{
|
|
if (!Directory.Exists(_options.LogDirectory))
|
|
{
|
|
Directory.CreateDirectory(_options.LogDirectory);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.Error.WriteLine($"Error creating log directory: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private void RotateFileIfNeeded()
|
|
{
|
|
var logPath = GetLogFilePath();
|
|
|
|
if (!File.Exists(logPath))
|
|
return;
|
|
|
|
var fileInfo = new FileInfo(logPath);
|
|
if (fileInfo.Length >= _options.MaxFileSizeBytes)
|
|
{
|
|
ArchiveCurrentLog(logPath);
|
|
}
|
|
}
|
|
|
|
private void ArchiveCurrentLog(string currentLogPath)
|
|
{
|
|
try
|
|
{
|
|
var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(_options.FileName);
|
|
var fileExtension = Path.GetExtension(_options.FileName);
|
|
var timestamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
|
|
var archivePath = Path.Combine(_options.LogDirectory,
|
|
$"{fileNameWithoutExtension}_{timestamp}{fileExtension}");
|
|
|
|
File.Move(currentLogPath, archivePath, overwrite: true);
|
|
|
|
CleanupOldBackups();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.Error.WriteLine($"Error archiving log file: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private void CleanupOldBackups()
|
|
{
|
|
try
|
|
{
|
|
var directory = new DirectoryInfo(_options.LogDirectory);
|
|
var pattern = $"{Path.GetFileNameWithoutExtension(_options.FileName)}_*";
|
|
|
|
var backupFiles = directory.GetFiles(pattern)
|
|
.OrderByDescending(f => f.CreationTime)
|
|
.Skip(_options.MaxBackupFiles)
|
|
.ToList();
|
|
|
|
foreach (var file in backupFiles)
|
|
{
|
|
file.Delete();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.Error.WriteLine($"Error cleaning up old backup files: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private string GetLogFilePath()
|
|
{
|
|
return Path.Combine(_options.LogDirectory, _options.FileName);
|
|
}
|
|
}
|