代码之家  ›  专栏  ›  技术社区  ›  Gary Smith

使用自定义ILogger类识别ILogger和Logger<Type>调用方

  •  0
  • Gary Smith  · 技术社区  · 1 年前

    我想更好地识别调用记录器的进程。我的老朋友。Net框架的实现允许我通过log4net为每个类创建一个记录器(或者传入一个现有的记录器来使用现有的记录器)。这种选择对我们来说不再可行。

    我已经为这个过程创建了一个客户记录器实现。

    #static main inline code:
    
    ILogger<LoggerTesting.LoggerTest> logger = loggerFactory.CreateLogger<LoggerTesting.LoggerTest>();
    LoggerTesting.LoggerTest lt = new LoggerTesting.LoggerTest(logger);
    await lt.GenerateLogEntry("Test");
    
    
    internal class LoggerTest
    {
        ILogger _logger;
    
        public LoggerTest(ILogger<LoggerTest> logger)
        {
            _logger = logger;
        }
    
        public async Task GenerateLogEntry(string message)
        {
            _logger.LogInformation(message);
            _logger.LogWarning(message);
            _logger.LogError(message);
            _logger.LogCritical(message);
            _logger.LogDebug(message);
    
        }
    }
    

    更新 以反映蘑菇的建议。我使用的示例代码对原始categoryName没有任何作用。现在我得到了预期的结果。

    public class DbLogger : ILogger
    {
        /// <summary>
        /// Instance of <see cref="DbLoggerProvider" />.
        /// </summary>
        private readonly DbLoggerProvider _dbLoggerProvider;
        private readonly string _appName;
    
        /// <summary>
        /// Creates a new instance of <see cref="FileLogger" />.
        /// </summary>
        /// <param name="fileLoggerProvider">Instance of <see cref="FileLoggerProvider" />.</param>
        public DbLogger(DbLoggerProvider dbLoggerProvider, string appName)
        {
            _dbLoggerProvider = dbLoggerProvider;
            _appName = appName ?? "Default";
            System.Diagnostics.Debug.WriteLine($"Created instance of {appName}");
        }
    
        public IDisposable BeginScope<TState>(TState state)
        {
            return null;
        }
    
        /// <summary>
        /// Whether to log the entry.
        /// </summary>
        /// <param name="logLevel"></param>
        /// <returns></returns>
        public bool IsEnabled(LogLevel logLevel)
        {
            return logLevel != LogLevel.None;
        }
    
    
        /// <summary>
        /// Used to log the entry.
        /// </summary>
        /// <typeparam name="TState"></typeparam>
        /// <param name="logLevel">An instance of <see cref="LogLevel"/>.</param>
        /// <param name="eventId">The event's ID. An instance of <see cref="EventId"/>.</param>
        /// <param name="state">The event's state.</param>
        /// <param name="exception">The event's exception. An instance of <see cref="Exception" /></param>
        /// <param name="formatter">A delegate that formats </param>
        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            if (!IsEnabled(logLevel))
            {
                // Don't log the entry if it's not enabled.
                return;
            }
    
            var threadId = Thread.CurrentThread.ManagedThreadId; // Get the current thread ID to use in the log file. 
    
            // Store record.
            using (var connection = new SqlConnection(_dbLoggerProvider.Options.ConnectionString))
            {
                connection.Open();
    
                using (var command = new SqlCommand())
                {
                    command.Connection = connection;
                    command.CommandType = System.Data.CommandType.Text;
    
                    command.CommandText = $@"INSERT INTO {_dbLoggerProvider.Options.LogTable} 
    (
    Application
    ,LogLevel
    ,ThreadId
    ,EventId
    ,EventName
    ,Message
    ,ExceptionMessage
    ,ExceptionStackTrace
    ,ExceptionSource
    ) VALUES(
    @Application
    ,@LogLevel
    ,@ThreadId
    ,@EventId
    ,@EventName
    ,@Message
    ,@ExceptionMessage
    ,@ExceptionStackTrace
    ,@ExceptionSource
    )";
    
                    var values = new JObject();
                    command.Parameters.Add(new SqlParameter("@Application", _appName));
                    command.Parameters.Add(new SqlParameter("@LogLevel", logLevel.ToString()));
                    command.Parameters.Add(new SqlParameter("@ThreadId", threadId));
                    command.Parameters.Add(new SqlParameter("@EventId", eventId.Id));
                    command.Parameters.Add(new SqlParameter("@EventName", !string.IsNullOrWhiteSpace(eventId.Name) ? eventId.Name : (object)DBNull.Value));
                    command.Parameters.Add(new SqlParameter("@Message", !string.IsNullOrWhiteSpace(formatter(state, exception)) ? formatter(state, exception) : (object)DBNull.Value));
                    if (exception != null)
                    {
                        command.Parameters.Add(new SqlParameter("@ExceptionMessage", !string.IsNullOrWhiteSpace(exception.Message) ? exception?.Message : (object)DBNull.Value));
                        command.Parameters.Add(new SqlParameter("@ExceptionStackTrace", !string.IsNullOrWhiteSpace(exception.StackTrace) ? exception?.StackTrace : (object)DBNull.Value));
                        command.Parameters.Add(new SqlParameter("@ExceptionSource", !string.IsNullOrWhiteSpace(exception.Source) ? exception?.Source : (object)DBNull.Value));
                    }
                    else
                    {
                        command.Parameters.Add(new SqlParameter("@ExceptionMessage", (object)DBNull.Value));
                        command.Parameters.Add(new SqlParameter("@ExceptionStackTrace", (object)DBNull.Value));
                        command.Parameters.Add(new SqlParameter("@ExceptionSource", (object)DBNull.Value));
                    }
    
    
                    command.ExecuteNonQuery();
                }
    
                connection.Close();
            }
        }
    }
    
    [ProviderAlias("Database")]
    public class DbLoggerProvider : ILoggerProvider
    {
        public readonly DbLoggerOptions Options;
    
        public DbLoggerProvider(IOptions<DbLoggerOptions> _options)
        {
            Options = _options.Value; // Stores all the options.
        }
    
        /// <summary>
        /// Creates a new instance of the db logger.
        /// </summary>
        /// <param name="categoryName"></param>
        /// <returns></returns>
        public ILogger CreateLogger(string categoryName)
        {
            return new DbLogger(this, categoryName);
        }
    
        public void Dispose()
        {
        }
    }
    

    我想在某个地方我可以看到LoggerTesting。LoggerTest位于记录器应用程序中的某个位置,因为这是为此目的创建的记录器类型,但事实并非如此。

    有没有一种特定的方法可以从我的自定义实现中检索派生类型?

    目标是用LoggerTest替换代码中的ApplicationNameHere。Logger测试值。

    请注意,我只是在试验这个代码。它非常简单和粗糙,因此没有适当的优化或验证。

    1 回复  |  直到 1 年前
        1
  •  1
  •   Mushroomator    1 年前

    您还需要实施 ILoggerProvider 哪个有方法 CreateLogger(string categoryName): ILogger .

    这个 categoryName 是应该为其创建记录器的类的名称,因此正是您想要的。现在,您只需要返回的一个新实例 ILogger 实现并将其传递给 类别名称 作为参数。

    public class DbLoggerProvider : ILoggerProvider
    {
        public ILogger CreateLogger(string categoryName)
        {
            return new DbLogger(categoryName); // pass the category name here
        }
    
        public void Dispose()
        {
    
        }
    }
    
    

    在您的 ILogger 实现,您可以将其存储为 readonly 字段和使用 ILogger 必要时实施。

    public class DbLogger : ILogger
    {
        private readonly string _categoryName;
        
        public DbLogger(string categoryName)
        {
            _categoryName = categoryName;
        }
    
        // Omitted: Some implementations of other necessary methods defined in ILogger...
        
        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            // use the _categoryName here now
            Console.WriteLine($"Logged with category {_categoryName}");
        }
    

    然后,您还需要使用DI注册日志记录提供商

    builder.Services.AddSingleton<ILoggerProvider, DbLoggerProvider>();