ASP.NET核心:构建线程安全日志记录到数据库中

时间:2017-03-02 00:31:16

标签: c# multithreading logging asp.net-core entity-framework-core

在我的ASP.NET核心应用程序的Startup.cs中,我想配置LoggingFactory,以便它登录到数据库。 因此,我创建了以下DBLoggerExtensions类来添加上下文:

public static class DBLoggerExtensions
{
    public static ILoggerFactory AddContext(this ILoggerFactory factory, Func<string, LogLevel, bool> filter = null)
    {
        factory.AddProvider(new DBLoggerProvider(filter));
        return factory;
    }

    public static ILoggerFactory AddContext(this ILoggerFactory factory, LogLevel minLevel)
    {
        return AddContext(
            factory,
            (_, logLevel) => logLevel >= minLevel);
    }
}

这将在Startup.cs的Configure方法中调用,如下所示:

loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();
        loggerFactory.AddContext(LogLevel.Information);

AddContext方法添加我的自定义LoggerProvider:

public class DBLoggerProvider : ILoggerProvider
{
    private readonly Func<string, LogLevel, bool> _filter;

    public DBLoggerProvider(Func<string, LogLevel, bool> filter)
    {
        _filter = filter;
    }
    public ILogger CreateLogger(string categoryName)
    {
        return new DBLogger(categoryName, _filter);
    }

    public void Dispose()
    {

    }
}

哪些登录数据库:

public class DBLogger : ILogger
{
    private string _categoryName;
    private Func<string, LogLevel, bool> _filter;
    private LoggerContext _context;
    private bool _selfException = false;

    public DBLogger(string categoryName, Func<string, LogLevel, bool> filter)
    {
        _categoryName = categoryName;
        _filter = filter;
        _context = new LoggerContext();
    }

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        if (!IsEnabled(logLevel))
        {
            return;
        }
        if (_selfException)
        {
            _selfException = false;
            return;
        }
        _selfException = true;
        if (formatter == null)
        {
            throw new ArgumentNullException(nameof(formatter));
        }
        var message = formatter(state, exception);
        if (string.IsNullOrEmpty(message))
        {
            return;
        }

        if (exception != null)
        {
            message += "\n" + exception.ToString();
        }

        try
        {
            var maxMessageLength = 2000;
            message = maxMessageLength != null && message.Length > maxMessageLength ? message.Substring(0, (int)maxMessageLength) : message;
            _context.EventLogs.Add(new EventLog { Message = message, EventId = eventId.Id, LogLevel = logLevel.ToString(), CreatedTime = DateTime.UtcNow });
            _context.SaveChanges();
            _selfException = false;
        }
        catch (Exception ex)
        {
            var test = ex;
        }
    }

    public bool IsEnabled(LogLevel logLevel)
    {
        return (_filter == null || _filter(_categoryName, logLevel));
    }

    public IDisposable BeginScope<TState>(TState state)
    {
        return null;
    }

}

但我的问题是这不是线程安全的。 如何在LoggingFactory不在不同线程中共享DbContext的数据库中完成日志记录?

由于

0 个答案:

没有答案
相关问题