66 lines
2.3 KiB
C#
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() { }
|
|
}
|
|
}
|
|
}
|