LibLog 类库 分析

前期思考:

  1. Microsoft.Logging 是否可用?

  2. 是否需要提供默认的 Logger 实现? 不需要。1,用户自己开启日志功能,设置开启属性,即可打印出相应的日志。

LibLog 类库分析:

类库设计方只需要安装好相应的包,然后在自己的日志类中 添加如下字段。

private static readonly ILog logger = LogProvider.GetCurrentClassLogger()

或者

private static readonly ILog Logger = LogProvider.For<YOUR_CLASS>()

无需安装其他第三方的类库,在记录日志时,只需调用 logger.Info 或者 logger.Error 这时类库的设计就算完成了。当然类库设计方可以提供给客户端一个接口假设为 EnableLogger()

客户端上,用户只需调用这个接口,即可实现类库日志的自动记录,而无需多余操作。

这里面实现的原理是什么,在客户端侧,除了调用类库的一个开启日志功能的接口,其他没有任何操作。

其实可以分析一下我们集成时的类库设计,首先是初始化 Logger 对象

// GetCurrentClassLogger
static ILog GetCurrentClassLogger()
{
    var stackFrame = new StackFrame(1, false);
    return GetLogger(stackFrame.GetMethod().DeclaringType);
}

获取当前类的日志, 初始化一个 StackFrame,这个应该是 Call Stack 中的Record Frame。下面给出官网上的描述:

A StackFrame is created and pushed on the call stack for every function call made during the execution of a thread.

然后进行 GetLogger()

static ILog GetLogger(string name)
{
    var logProvider = CurrentLogProvider ?? ResolveLogProvider();
    return logProvider == null
        ? NoOpLogger.Instance
        : (ILog)new LoggerExecutionWrapper(logProvider.GetLogger(name), () => IsDisabled);
}

重点关注 ResolveLogProvider 的这个方法,首先是用到了 Lazy Initialization

private static readonly Lazy ResolvedLogProvider = new Lazy(ForceResolveLogProvider);

然后关注这个 ForceResolveLogProvider,Lazy 方法接收的参数类型为 Func 的委托类型,也就是说,接收一个返回值为 ILogProvider 的方法。

internal static ILogProvider ForceResolveLogProvider()
{
    try
    {
        foreach (var providerResolver in LogProviderResolvers)
        {
            if (providerResolver.Item1())
            {
                return providerResolver.Item2();
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(
            "Exception occurred resolving a log provider. Logging for this assembly {0} is disabled. {1}",
            typeof(LogProvider).Assembly.FullName,
            ex);
    }
    return null;
}

该方法主要是查找当前进程中是否已经初始化某个日志类了,如果有,则放回这个类。若没有,则抛出异常。重点关注的是 LogProviderResolvers ,这是一个元祖类型 ,定义如下:

static readonly List<Tuple<IsLoggerAvailable, CreateLogProvider>> LogProviderResolvers =
                new List<Tuple<IsLoggerAvailable, CreateLogProvider>>
        {
            new Tuple<IsLoggerAvailable, CreateLogProvider>(SerilogLogProvider.IsLoggerAvailable, () => new SerilogLogProvider()),
            new Tuple<IsLoggerAvailable, CreateLogProvider>(NLogLogProvider.IsLoggerAvailable, () => new NLogLogProvider()),
            new Tuple<IsLoggerAvailable, CreateLogProvider>(Log4NetLogProvider.IsLoggerAvailable, () => new Log4NetLogProvider()),
            new Tuple<IsLoggerAvailable, CreateLogProvider>(LoupeLogProvider.IsLoggerAvailable, () => new LoupeLogProvider()),
        };

配置完 Provider 之后,其实类库已经获取到你本地配置的日志类了,当类库中需要打印日志的需求的话,通过反射来找到项目中的日志类,然后初始化来执行相关的操作。

DEMO样例:

类库:https://github.com/doublnt/dotnetcore/blob/master/LibLogSample/CommonLibLog.cs

客户端:https://github.com/doublnt/dotnetcore/blob/master/CSharpFundamental/LibLog/ConsumerLibLog.cs

posted @ 2019-06-26 19:09  BUTTERAPPLE  阅读(100)  评论(0编辑  收藏