185 lines
5.6 KiB
C#
185 lines
5.6 KiB
C#
using System.Diagnostics;
|
|
using Microsoft.Extensions.Logging;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
|
|
namespace SteUp.Maui.Core.Logger;
|
|
|
|
public class FileLogger : ILogger
|
|
{
|
|
private readonly string _path;
|
|
private readonly string _fileNamePrefix;
|
|
private readonly string _categoryName;
|
|
private readonly Lock _lock = new();
|
|
private readonly int _retentionDays;
|
|
private string? _currentFileName;
|
|
private DateTime _currentFileDate;
|
|
private DateTime _lastCleanupDate;
|
|
|
|
public FileLogger(string path, string fileNamePrefix, string categoryName, int retentionDays = 60)
|
|
{
|
|
_path = path;
|
|
_fileNamePrefix = fileNamePrefix;
|
|
_retentionDays = retentionDays;
|
|
_lastCleanupDate = DateTime.MinValue;
|
|
_categoryName = categoryName;
|
|
|
|
if (!Directory.Exists(path))
|
|
Directory.CreateDirectory(path);
|
|
|
|
UpdateCurrentFileName();
|
|
TryCleanOldLogs();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elimina i log più vecchi di <see cref="_retentionDays"/> giorni.
|
|
/// Viene eseguita al massimo una volta al giorno.
|
|
/// </summary>
|
|
private void ClearOldLogs()
|
|
{
|
|
try
|
|
{
|
|
var cutoff = DateTime.Now.Date.AddDays(-_retentionDays);
|
|
var logFiles = Directory.GetFiles(_path, $"{_fileNamePrefix}-*.log");
|
|
|
|
foreach (var file in logFiles)
|
|
{
|
|
try
|
|
{
|
|
var fileName = Path.GetFileNameWithoutExtension(file);
|
|
|
|
var datePart = fileName[(_fileNamePrefix.Length + 1)..];
|
|
|
|
if (!DateTime.TryParseExact(datePart, "yyyy-MM-dd",
|
|
CultureInfo.InvariantCulture,
|
|
DateTimeStyles.None,
|
|
out var fileDate) || fileDate >= cutoff) continue;
|
|
File.Delete(file);
|
|
Debug.WriteLine($"[FileLogger] Log eliminato: {file}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine($"[FileLogger] Errore durante l'eliminazione del file {file}: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine($"[FileLogger] Errore durante la pulizia dei log: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Esegue la pulizia dei log solo se non è già stata eseguita oggi.
|
|
/// </summary>
|
|
private void TryCleanOldLogs()
|
|
{
|
|
var today = DateTime.Now.Date;
|
|
if (_lastCleanupDate == today) return;
|
|
_lastCleanupDate = today;
|
|
ClearOldLogs();
|
|
}
|
|
|
|
private void UpdateCurrentFileName()
|
|
{
|
|
var today = DateTime.Now.Date;
|
|
if (_currentFileName != null && _currentFileDate == today) return;
|
|
_currentFileDate = today;
|
|
_currentFileName = $"{_fileNamePrefix}-{today:yyyy-MM-dd}.log";
|
|
}
|
|
|
|
public IDisposable? BeginScope<TState>(TState state) => null;
|
|
|
|
public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None;
|
|
|
|
public void Log<TState>(
|
|
LogLevel logLevel,
|
|
EventId eventId,
|
|
TState state,
|
|
Exception? exception,
|
|
Func<TState, Exception?, string> formatter)
|
|
{
|
|
if (!IsEnabled(logLevel))
|
|
return;
|
|
|
|
try
|
|
{
|
|
lock (_lock)
|
|
{
|
|
UpdateCurrentFileName();
|
|
TryCleanOldLogs();
|
|
|
|
if (_currentFileName == null) return;
|
|
|
|
var fullPath = Path.Combine(_path, _currentFileName);
|
|
var logEntry = BuildLogEntry(logLevel, eventId, state, exception, formatter);
|
|
|
|
File.AppendAllText(fullPath, logEntry + Environment.NewLine + Environment.NewLine);
|
|
Debug.WriteLine($"[FileLogger] {logEntry}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine($"[FileLogger] Errore durante la scrittura del log: {ex}");
|
|
}
|
|
}
|
|
|
|
private string BuildLogEntry<TState>(
|
|
LogLevel logLevel,
|
|
EventId eventId,
|
|
TState state,
|
|
Exception? exception,
|
|
Func<TState, Exception?, string> formatter)
|
|
{
|
|
var sb = new StringBuilder();
|
|
|
|
sb.Append($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}]");
|
|
sb.Append($" [{GetLogLevelShort(logLevel)}]");
|
|
sb.Append($" [{_categoryName}]");
|
|
|
|
if (eventId.Id != 0 || !string.IsNullOrEmpty(eventId.Name))
|
|
sb.Append($" [{eventId}]");
|
|
|
|
sb.Append($" {formatter(state, exception)}");
|
|
|
|
if (exception != null)
|
|
AppendException(sb, exception);
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
private static void AppendException(StringBuilder sb, Exception exception, int depth = 0)
|
|
{
|
|
while (true)
|
|
{
|
|
var indent = depth == 0 ? "" : " Inner ";
|
|
sb.AppendLine();
|
|
sb.Append($"{indent}Exception: {exception.GetType().FullName}: {exception.Message}");
|
|
if (!string.IsNullOrWhiteSpace(exception.StackTrace))
|
|
{
|
|
sb.AppendLine();
|
|
sb.Append($"{indent}StackTrace: {exception.StackTrace.Trim()}");
|
|
}
|
|
|
|
if (exception.InnerException != null)
|
|
{
|
|
exception = exception.InnerException;
|
|
depth += 1;
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
private static string GetLogLevelShort(LogLevel level) => level switch
|
|
{
|
|
LogLevel.Trace => "TRC",
|
|
LogLevel.Debug => "DBG",
|
|
LogLevel.Information => "INF",
|
|
LogLevel.Warning => "WRN",
|
|
LogLevel.Error => "ERR",
|
|
LogLevel.Critical => "CRT",
|
|
_ => "???"
|
|
};
|
|
} |