zoukankan      html  css  js  c++  java
  • 给微软的日志框架写一个基于委托的日志提供者

    动手造轮子:给微软的日志框架写一个基于委托的日志提供者

    Intro

    微软的日志框架现在已经比较通用,有时候我们不想使用外部的日志提供者,但又希望提供一个比较简单的委托就可以实现日志记录,于是就有了后面的探索和实现。

    Solution

    基于委托的 LoggerProvider 实现代码:

    自定义 Logger

    微软的日志框架中记录日志是通过 ILogger 来做的,扩展支持其他日志框架的时候也需要实现相应的 ILogger 来适配

    ILoggerProvider 会需要实现创建 ILogger 的接口 CreateLogger(string categoryName) ,所以我们可以先来实现对应的 ILogger,实现如下:

    这里的实现简单化处理,默认处理所有级别的日志,如果要设定日志级别可以通过日志的 Fliter 来做,这里就不做检查和限制了

    private class DelegateLogger : ILogger
    {
        private readonly string _categoryName;
        private readonly Action<string, LogLevel, Exception, string> _logAction;
    
        public DelegateLogger(string categoryName, Action<string, LogLevel, Exception, string> logAction)
        {
            _categoryName = categoryName;
            _logAction = logAction;
        }
    
        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            if (null != _logAction)
            {
                var msg = formatter(state, exception);
                _logAction.Invoke(_categoryName, logLevel, exception, msg);
            }
        }
    
        public bool IsEnabled(LogLevel logLevel)
        {
            return true;
        }
    
        public IDisposable BeginScope<TState>(TState state)
        {
            return NullScope.Instance;
        }
    }
    

    自定义 ILoggerProvider

    有了 ILogger 之后接着我们来定义我们的 ILoggerProvider,这里我们针对 Logger 名称(CategoryName)做了区分,如果不关注 Logger 名称的话也可以使用同一个
    Logger 这样就不需要下面的并发字典了,只用一个 ILogger 对象就可以了,可以根据自己的需要进行定制

    实现代码如下:

    [ProviderAlias("Delegate")]
    public class DelegateLoggerProvider : ILoggerProvider
    {
        private readonly Action<string, LogLevel, Exception, string> _logAction;
        private readonly ConcurrentDictionary<string, DelegateLogger> _loggers = new ConcurrentDictionary<string, DelegateLogger>();
    
        public DelegateLoggerProvider(Action<string, LogLevel, Exception, string> logAction)
        {
            _logAction = logAction;
        }
    
        public void Dispose()
        {
            _loggers.Clear();
        }
    
        public ILogger CreateLogger(string categoryName)
        {
            return _loggers.GetOrAdd(categoryName, category => new DelegateLogger(category, _logAction));
        }
    }
    

    定义扩展方法

    为了方便使用,我们需要定义两个扩展方法来优化我们使用的方式:

    定义 ILoggerFactory 的扩展方法:

    /// <summary>
    /// AddDelegateLoggerProvider
    /// </summary>
    /// <param name="loggerFactory">loggerFactory</param>
    /// <param name="logAction">logAction</param>
    /// <returns>loggerFactory</returns>
    public static ILoggerFactory AddDelegateLogger(this ILoggerFactory loggerFactory, Action<string, LogLevel, Exception, string> logAction)
    {
        loggerFactory.AddProvider(new DelegateLoggerProvider(logAction));
        return loggerFactory;
    }
    

    定义 ILoggingBuilder 的扩展方法:

    public static ILoggingBuilder AddDelegateLogger(this ILoggingBuilder loggingBuilder,
        Action<string, LogLevel, Exception, string> logAction)
    {
        return loggingBuilder.AddProvider(new DelegateLoggerProvider(logAction));
    }
    

    使用示例

    ILoggerFactory loggerFactory = new LoggerFactory();
    //loggerFactory.AddConsole();
    loggerFactory.AddDelegateLogger(
        (category, logLevel, exception, msg) =>
        {
            Console.WriteLine($"{category}:[{logLevel}] {msg}
    {exception}");
        }
    );
    

    日志输出效果如下:

    Reference

  • 相关阅读:
    Spring Cloud 模块简介2
    Eureka简介
    Spring Cloud 模块简介
    成神之路-基础篇 转
    Java面试题无答案
    java程序猿常用Linux命令
    Java工程师成神之路 转
    大型网站技术架构 大纲
    Mockito 相关资料
    webApp路由控制-vue-router2.0
  • 原文地址:https://www.cnblogs.com/weihanli/p/delegate-logger-provider-for-microsoft-logging.html
Copyright © 2011-2022 走看看