Files

66 lines
2.3 KiB
C#

using System.Text;
using Microsoft.Extensions.Logging;
namespace WxAgent.Service;
public static class RuntimeLog
{
private static readonly object Gate = new();
public static void Append(string path, LogLevel level, string category, string message, Exception? exception = null)
{
try
{
var fullPath = Path.GetFullPath(path);
var directory = Path.GetDirectoryName(fullPath);
if (!string.IsNullOrEmpty(directory)) Directory.CreateDirectory(directory);
var line = Format(level, category, message, exception);
lock (Gate)
{
using var stream = new FileStream(fullPath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete);
using var writer = new StreamWriter(stream, new UTF8Encoding(false));
writer.WriteLine(line);
}
}
catch
{
// Logging must not prevent the agent from starting or serving requests.
}
}
internal static string Format(LogLevel level, string category, string message, Exception? exception)
{
var line = $"{DateTimeOffset.Now:O} [{level}] {category}: {message}";
return exception is null ? line : $"{line}{Environment.NewLine}{exception}";
}
}
internal sealed class FileLoggerProvider(string path) : ILoggerProvider
{
private readonly string path = Path.GetFullPath(path);
public ILogger CreateLogger(string categoryName) => new FileLogger(this, categoryName);
public void Dispose() { }
private sealed class FileLogger(FileLoggerProvider provider, string categoryName) : ILogger
{
public IDisposable BeginScope<TState>(TState state) where TState : notnull => NoopScope.Instance;
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;
RuntimeLog.Append(provider.path, logLevel, categoryName, formatter(state, exception), exception);
}
private sealed class NoopScope : IDisposable
{
public static readonly NoopScope Instance = new();
public void Dispose() { }
}
}
}