100 lines
3.0 KiB
C#
100 lines
3.0 KiB
C#
using System.IO;
|
|
using System.Text;
|
|
|
|
namespace UtopiaCanteenSystem.Services.Logging;
|
|
|
|
/// <summary>
|
|
/// Thread-safe daily file logger. Never throws to callers.
|
|
/// </summary>
|
|
public static class FileLogger
|
|
{
|
|
private static readonly object Lock = new();
|
|
private static FileLogTarget? _target;
|
|
|
|
public static bool IsConfigured => _target.HasValue;
|
|
|
|
public static void ConfigureBackend() => Configure(FileLogTarget.Backend);
|
|
|
|
public static void ConfigureClient() => Configure(FileLogTarget.Client);
|
|
|
|
public static void Configure(FileLogTarget target)
|
|
{
|
|
_target = target;
|
|
var dir = GetLogsDirectory();
|
|
try
|
|
{
|
|
Directory.CreateDirectory(dir);
|
|
}
|
|
catch
|
|
{
|
|
// Ignore
|
|
}
|
|
|
|
Info("FileLogger", $"Logging initialized. Directory={dir}");
|
|
}
|
|
|
|
public static string GetLogsDirectory() =>
|
|
_target == FileLogTarget.Client
|
|
? LogPaths.ClientLogsDirectory
|
|
: LogPaths.BackendLogsDirectory;
|
|
|
|
public static void Debug(string component, string message) => Write("DEBUG", component, message, null);
|
|
|
|
public static void Info(string component, string message) => Write("INFO", component, message, null);
|
|
|
|
public static void Warn(string component, string message, Exception? ex = null) =>
|
|
Write("WARN", component, message, ex);
|
|
|
|
public static void Error(string component, string message, Exception? ex = null) =>
|
|
Write("ERROR", component, message, ex);
|
|
|
|
private static void Write(string level, string component, string message, Exception? ex)
|
|
{
|
|
if (!_target.HasValue)
|
|
return;
|
|
|
|
try
|
|
{
|
|
var dir = GetLogsDirectory();
|
|
var prefix = _target == FileLogTarget.Client ? "client" : "backend";
|
|
var file = Path.Combine(dir, $"{prefix}-{DateTime.Now:yyyy-MM-dd}.log");
|
|
var line = FormatLine(level, component, message, ex);
|
|
|
|
lock (Lock)
|
|
{
|
|
Directory.CreateDirectory(dir);
|
|
File.AppendAllText(file, line, Encoding.UTF8);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// Never crash the app because logging failed.
|
|
}
|
|
}
|
|
|
|
private static string FormatLine(string level, string component, string message, Exception? ex)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.Append($"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} [{level}] [{component}] {message}");
|
|
if (ex != null)
|
|
{
|
|
sb.AppendLine();
|
|
sb.Append($"Exception: {ex.GetType().Name}: {ex.Message}");
|
|
if (!string.IsNullOrWhiteSpace(ex.StackTrace))
|
|
{
|
|
sb.AppendLine();
|
|
sb.Append(ex.StackTrace);
|
|
}
|
|
|
|
if (ex.InnerException != null)
|
|
{
|
|
sb.AppendLine();
|
|
sb.Append($"InnerException: {ex.InnerException.GetType().Name}: {ex.InnerException.Message}");
|
|
}
|
|
}
|
|
|
|
sb.AppendLine();
|
|
return sb.ToString();
|
|
}
|
|
}
|