本节主要介绍解决方案中的Microsoft.Framework.Logging.Abstractions、Microsoft.Framework.Logging俩个工程。

这俩个工程中所有类的关系如下图所示:

首先我们可以发现处于核心的是中间的四个接口:ILogger、ILoggerFactory、ILoggerProvider、ILogValues。

  • ILogger:记录日志的接口,所以写日志的类都该实现该接口,工程中有俩个类实现了该接口:Logger、Logger<T>
  • ILoggerFactory:创建ILogger的工厂。负责创建工厂的逻辑,但是一般不直接创建,而是调用内部ILoggerProvider去完成。
  • ILoggerProvider:能够直接创建ILogger实例,做为属性添加到ILoggerFactory中,ILogger的具体逻辑受控制ILoggerFactory。
  • ILogValues:在Logger的扩展方法中作为特殊类型的object传入,作为日志的数据源。

接口的定义源码如下:

    public interface ILogger
{
void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter); bool IsEnabled(LogLevel logLevel); IDisposable BeginScopeImpl(object state);
}

ILogger

    public interface ILoggerFactory
{
LogLevel MinimumLevel { get; set; } ILogger CreateLogger(string categoryName); void AddProvider(ILoggerProvider provider);
}

ILoggerFactory

    public interface ILoggerProvider
{
ILogger CreateLogger(string name);
}

ILoggerProvider

    public interface ILogValues
{
IEnumerable<KeyValuePair<string, object>> GetValues();
}

ILogValues

ILogger以及实现类

ILogger接口、ILogger<TCategoryName>(没有任何定义)、Logger<T>这种泛型继承是否有相识之感,之前的博客文章中已经对于这种情况有所介绍([Asp.net 5] Localization-resx资源文件的管理IStringLocalizer 、IStringLocalizer<T> StringLocalizer<TResourceSource>是一致的)。实际Logger<T>中T是ILogger的实例子类,实际就是使用代理模式,内部包含ILogger实例,并且所有对外的方法都仅仅是内部ILogger实例的封装。

    public class Logger<T> : ILogger<T>
{
private readonly ILogger _logger; /// <summary>
/// Creates a new <see cref="Logger{T}"/>.
/// </summary>
/// <param name="factory">The factory.</param>
public Logger(ILoggerFactory factory)
{
_logger = factory.CreateLogger<T>();
} IDisposable ILogger.BeginScopeImpl(object state)
{
return _logger.BeginScopeImpl(state);
} bool ILogger.IsEnabled(LogLevel logLevel)
{
return _logger.IsEnabled(logLevel);
} void ILogger.Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
_logger.Log(logLevel, eventId, state, exception, formatter);
}
}

Logger

Logger类同样实现了ILogger接口,也同样使用了代理模式,不过不同于Logger<T>泛型,Logger类有自己的内部逻辑。而是在内部封装了 ILogger[] _loggers对象。使得Logger更像LoggerManage。但是由于Logger同样实现Logger接口,所以Logger类是管理其它Logger类的代理。而Logger内部的_loggers是通过LoggerFactory对象封装的。当记录日志时,依次遍历内部的 _loggers对象,进行写日志操作。

    internal class Logger : ILogger
{
private readonly LoggerFactory _loggerFactory;
private readonly string _name;
private ILogger[] _loggers = new ILogger[]; public Logger(LoggerFactory loggerFactory, string name)
{
_loggerFactory = loggerFactory;
_name = name; var providers = loggerFactory.GetProviders();
_loggers = new ILogger[providers.Length];
for (var index = ; index != providers.Length; index++)
{
_loggers[index] = providers[index].CreateLogger(name);
}
} public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
if (logLevel >= _loggerFactory.MinimumLevel)
{
foreach (var logger in _loggers)
{
logger.Log(logLevel, eventId, state, exception, formatter);
}
}
} public bool IsEnabled(LogLevel logLevel)
{
if (logLevel < _loggerFactory.MinimumLevel)
{
return false;
}
foreach (var logger in _loggers)
{
if (logger.IsEnabled(logLevel))
{
return true;
}
}
return false;
} public IDisposable BeginScopeImpl(object state)
{
var loggers = _loggers;
var scope = new Scope(loggers.Length);
for (var index = ; index != loggers.Length; index++)
{
scope.SetDisposable(index, loggers[index].BeginScopeImpl(state));
}
return scope;
} internal void AddProvider(ILoggerProvider provider)
{
var logger = provider.CreateLogger(_name);
_loggers = _loggers.Concat(new[] { logger }).ToArray();
} private class Scope : IDisposable
{
private bool _isDisposed; private IDisposable _disposable0;
private IDisposable _disposable1;
private readonly IDisposable[] _disposable; public Scope(int count)
{
if (count > )
{
_disposable = new IDisposable[count - ];
}
} public void SetDisposable(int index, IDisposable disposable)
{
if (index == )
{
_disposable0 = disposable;
}
else if (index == )
{
_disposable1 = disposable;
}
else
{
_disposable[index - ] = disposable;
}
} protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
if (_disposable0 != null)
{
_disposable0.Dispose();
}
if (_disposable1 != null)
{
_disposable1.Dispose();
}
if (_disposable != null)
{
var count = _disposable.Length;
for (var index = ; index != count; ++index)
{
if (_disposable[index] != null)
{
_disposable[index].Dispose();
}
}
}
} _isDisposed = true;
}
} // This code added to correctly implement the disposable pattern.
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
// TODO: tell GC not to call its finalizer when the above finalizer is overridden.
// GC.SuppressFinalize(this);
} internal void Add(IDisposable disposable)
{
throw new NotImplementedException();
}
}
}

Logger

ILoggerFactory以及实现类

ILoggerFactory主要有俩个作用,添加新的ILoggerProvider,创建ILogger。而ILoggerFactory的唯一实现类LoggerFactory,简单实现了上面两个功能,并且在LoggerFactory内部额外维护_loggers副本,该处loggers都是Logger类型(非泛型),只是categoryName不同。所以通过LoggerFactory创建的Logger如下图所示:

    public class LoggerFactory : ILoggerFactory
{
private readonly Dictionary<string, Logger> _loggers = new Dictionary<string, Logger>(StringComparer.Ordinal);
private ILoggerProvider[] _providers = new ILoggerProvider[];
private readonly object _sync = new object(); public ILogger CreateLogger(string categoryName)
{
Logger logger;
lock (_sync)
{
if (!_loggers.TryGetValue(categoryName, out logger))
{
logger = new Logger(this, categoryName);
_loggers[categoryName] = logger;
}
}
return logger;
} public LogLevel MinimumLevel { get; set; } = LogLevel.Verbose; public void AddProvider(ILoggerProvider provider)
{
lock (_sync)
{
_providers = _providers.Concat(new[] { provider }).ToArray();
foreach (var logger in _loggers)
{
logger.Value.AddProvider(provider);
}
}
} internal ILoggerProvider[] GetProviders()
{
return _providers;
}
}

LoggerFactory

[Asp.net 5] Logging-日志系统的基本架构(上)的更多相关文章

  1. Python logging日志系统

    写我小小的日志系统 配置logging有以下几种方式: 1)使用Python代码显式的创建loggers, handlers和formatters并分别调用它们的配置函数: 2)创建一个日志配置文件, ...

  2. ASP.NET Core分布式日志系统ELK实战演练

    一.ELK简介  ELK是Elasticsearch.Logstash和Kibana首字母的缩写.这三者均是开源软件,这三套开源工具组合起来形成了一套强大的集中式日志管理平台. •  Elastics ...

  3. Elasticsearch,Kibana,Logstash,NLog实现ASP.NET Core 分布式日志系统

    Elasticsearch - 简介 Elasticsearch 作为核心的部分,是一个具有强大索引功能的文档存储库,并且可以通过 REST API 来搜索数据.它使用 Java 编写,基于 Apac ...

  4. Asp.net core logging 日志

    1 基本概念 Dotnet core 一个重要的特征是 Dependency injection ,中文一般是依赖注入,可以简单理解为一个集合,在应用程序启动时,定义各种具体的实现类型并将其放到集合中 ...

  5. [Asp.net 5] Logging-日志系统的基本架构(下)

    接上节内容,我们继续讲解日志的其他部分. ILoggerProvider以及扩展类 我们在上节的架构图上并没有看到有直接实现该接口的实现类.那么如果将Logger类直接使用会有什么结果呢? var f ...

  6. [Asp.net 5] Logging-其他日志系统的实现

    Microsoft.Framework.Logging.NLog 使用Nlog扩展日志系统:按照我们上节说的,对于扩展的日志系统都要实现俩个接口ILogger.ILoggerProvider.所以在当 ...

  7. [Asp.net 5] Logging-新日志系统目录

    楼主有个美好的愿望——把asp.net 5所有能看懂的代码一一呈现给大家(比如C++,楼主就看不懂).现在已经做完了依赖注入.多语言.配置文件三部分,比较基础的日志就成为了楼主的下一个目标.下面是楼主 ...

  8. Python logging(日志)模块

    python日志模块 内容简介 1.日志相关概念 2.logging模块简介 3.logging模块函数使用 4.logging模块日志流处理流程 5.logging模块组件使用 6.logging配 ...

  9. pyhton——logging日志模块的学习

    https://www.cnblogs.com/yyds/p/6901864.html 本节内容 日志相关概念 logging模块简介 使用logging提供的模块级别的函数记录日志 logging模 ...

随机推荐

  1. 升级为iOS9后,默认请求类型为https,如何使用http进行请求会报错(引用他人的)

    升级为iOS9后,默认请求类型为https,如何使用http进行请求会报错 The resource could not be loaded because the App Transport Sec ...

  2. RPC 的概念模型与实现解析

    今天分布式应用.云计算.微服务大行其道,作为其技术基石之一的 RPC 你了解多少?一篇 RPC 的技术总结文章,数了下 5k+ 字,略长,可能也不适合休闲的碎片化时间阅读,可以先收藏抽空再细读:) 全 ...

  3. ABP理论学习之仓储

    返回总目录 本篇目录 IRepository接口 查询 插入 更新 删除 其他 关于异步方法 仓储实现 管理数据库连接 仓储的生命周期 仓储最佳实践 Martin Fowler对仓储的定义 位于领域层 ...

  4. A*寻路算法

    对于初学者而言,A*寻路已经是个比较复杂的算法了,为了便于理解,本文降低了A*算法的难度,规定只能横竖(四方向)寻路,而无法直接走对角线,使得整个算法更好理解. 简而言之,A*寻路就是计算从起点经过该 ...

  5. 再谈使用Emit把Datatable转换为对象集合(List<T>)

    一.前因和存在的问题 前面我写了一篇<使用Emit把Datatable转换为对象集合(List<T>)>的博文,其实起源于我自己编写的一个orm工具(见前面几篇博文有介绍),里 ...

  6. 基于JQuery的浮动DIV显示提示信息并自动隐藏

    /** * 浮动DIV定时显示提示信息,如操作成功, 失败等 * @param string tips (提示的内容) * @param int height 显示的信息距离浏览器顶部的高度 * @p ...

  7. 链接(extern、static关键词\头文件\静态库\共享库)

    原文链接:http://www.orlion.ga/781/ 一. 多目标文件的链接 假设有两个文件:stack.c: /* stack.c */ char stack[512]; int top = ...

  8. px、dp与sp的区别以及换算

    1.px 即像素,1px代表屏幕上的一个物理像素点. 2.dp dip:device independent pixels(设备独立像素),dp与dip一样,不同的设备有不同的显示效果,一般为了支持W ...

  9. ASP.NET WebAPi之断点续传下载(上)

    前言 之前一直感觉断点续传比较神秘,于是想去一探究竟,不知从何入手,以为就写写逻辑就行,结果搜索一番,还得了解相关http协议知识,又花了许久功夫去看http协议中有关断点续传知识,有时候发觉东西只有 ...

  10. EntityFramework之异步、事务及性能优化(九)

    前言 本文开始前我将循序渐进先了解下实现EF中的异步,并将重点主要是放在EF中的事务以及性能优化上,希望通过此文能够帮助到你. 异步 既然是异步我们就得知道我们知道在什么情况下需要使用异步编程,当等待 ...