在 asp.net 核心(或其他库)中有一个 ILogger,我可以设置我的代码将日志写入 azure 或数据库或控制台等,但我想知道这个 ILogger 是同步的。在 docs.microsoft 上,我读到他们说“记录器应该是同步的,考虑将日志写入某个队列并让后台工作人员将这些日志拉到您的数据库中”。现在,我有几个问题。
也许我在问一个愚蠢的问题或一个宽泛的问题,但这对我来说是一个宽泛的话题,我并不真正理解。请帮忙。我也想看一些代码示例(一些 github repos 或其他东西)
最佳答案
Microsoft 在实现 ConsoleLogger
时所做的事情正在使用将排队的消息写入控制台的后台线程。
我刚刚实现了类似的东西,但使用的是 EF Core 上下文。
原始实现可以在这里找到:
https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
我的实现看起来像这样:
public class RequestLogProcessor : IDisposable
{
private readonly BlockingCollection<RequestLog> _queue;
private readonly Thread _writingThread;
private readonly DbContext _context;
public RequestLogProcessor(DbContext context, RequestLoggerConfiguration configuration)
{
_queue = new BlockingCollection<RequestLog>(configuration.Buffer);
_context = context;
_writingThread = new Thread(WriteQueue)
{
IsBackground = true,
Name = "RequestLogProcessor Thread"
};
_writingThread.Start();
}
private void WriteQueue()
{
try
{
foreach (var message in _queue.GetConsumingEnumerable())
{
WriteMessage(message);
}
}
catch
{
try
{
_queue.CompleteAdding();
}
catch { }
}
}
public void Enqueue(RequestLog log)
{
if (!_queue.IsAddingCompleted)
{
try
{
_queue.Add(log);
return;
}
catch (InvalidOperationException) { }
}
try
{
WriteMessage(log);
}
catch (Exception) { }
}
private void WriteMessage(RequestLog log)
{
_context.RequestLogs.Add(log);
_context.SaveChanges();
}
public void Dispose()
{
_queue.CompleteAdding();
try
{
_writingThread.Join(1500);
}
catch (ThreadStateException) { }
}
}
您将在 ILogger
的实现中使用此类小号 Log<TState>
像这样的功能:public class RequestLogger : ILogger
{
private readonly RequestLoggerConfiguration _config;
private readonly RequestLogProcessor _processor;
public RequestLogger(
RequestLoggerConfiguration config,
RequestLogProcessor processor)
{
_config = config;
_processor = processor;
}
public IDisposable BeginScope<TState>(TState state)
=> default;
public bool IsEnabled(LogLevel logLevel)
=> logLevel <= _config.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;
if (state is not RequestLog log)
return;
log.Exception ??= exception?.ToString();
log.Level = logLevel.ToString();
_processor.Enqueue(log); // this is the line
}
}
这在我的 ASP.NET Core 应用程序中运行良好,尽管您可以通过批量插入日志来调整它的性能。我确实调用 SaveChanges()
对于每个可能非常慢的条目。在您的情况下,您可以使用异步函数委托(delegate)创建线程:
new Thread(async() => await WriteQueue())
并使用 _context.SaveChangesAsync()
.编辑(根据评论):
public class RequestLoggerConfiguration
{
public LogLevel LogLevel { get; set; } = LogLevel.Error;
public int Buffer { get; set; } = 1024;
}
关于c# - 在 asp.net 核心应用程序中应该如何实现对数据库的异步日志记录?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59919244/