
在.Net Core中,该系统带有集成的日志记录系统. 让我们看看如何使用它:
第一步是添加LogProvider. 这是告诉容器我们日志输出的来源. LogProvider的目的是创建一个Logger. 在Asp.Net Core中,默认情况下添加了三个提供程序:
.ConfigureLogging((hostingContext, logging) => { logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); logging.AddConsole(); logging.AddDebug(); logging.AddEventSourceLogger(); })
此处添加的LoggerProvider最终将注入到LoggerFactory中以创建ILogger.
在上面的代码中也可以看到
AddConfiguration,它是通过配置添加日志过滤条件的. 我待会儿解释.
添加提供程序后,您可以从容器中获取日志对象. 当您获得它时,有两种类型:

这是最简单的示例. 实际记录日志的位置通常不在以下结构中:
public class HomeController : Controller { public HomeController(ILogger<HomeController> loggerT, ILoggerFactory loggerFactory) { var testLog = loggerFactory.CreateLogger("Test"); loggerT.LogInformation("Info"); testLog.LogInformation("Info"); } }
谈到这一点,您可能会有一些问题: 我添加了多个LogProvider,自然会生成多个ILogger. 那么,这里的工厂类生成的ILogger是哪一个?答案是: 没有一个!工厂在此处生成的ILogger是Microsoft.Extensions.Logging.Logger系统的默认实现. 在Logger的默认实现中,有一个LoggerInformation数组. LoggerInformation包含由这些LogProvider生成的ILogger和一些过滤条件. 在不添加任何过滤条件的情况下,以上代码将同时记录到3个不同的位置.
添加了多少个LogProvider,这个LoggerInformation数组的长度就为多少。LoggerInformation和LogProvider一一对应。
此外,如果要通过注入获取ILogger,它将无法工作,因为在初始化期间,仅在ILoggerFactory和ILogger
在谈论日志过滤时,我们必须首先弄清日志过滤的过滤条件:
这些参数和ILogger(由LogProvider生成)将一起保存在LoggerInformation对象中. LoggerInformation中还有另一个属性,该属性也用于日志过滤:

public Func<string, string, LogLevel, bool> Filter { get; set; }
这是一个委托,它需要三个参数,分别代表Category,ProviderType和LogLevel,并返回一个布尔值,指示是否启用日志类型. 有了这些信息,每当使用ILogger(系统的Logger的默认实现)进行日志写入时,它将循环遍历LoggerInformation数组对象,以便可以独立控制每个LogProvider生成的ILogger对象. LogLevel确定是否需要输出日志.
下一个问题是,如何配置过滤规则?配置过滤规则的唯一方法是配置LoggerFilterOptions对象. 有关如何自行配置Option对象的信息,请参阅本系列的上一篇文章.
系统提供了一系列扩展方法来帮助我们配置此对象. 有关详细信息,请参阅: 还有基于配置的扩展. 核心代码是: 这是什么LoggerFilterOptions?看一下源代码: <
public class LoggerFilterOptions { /// <summary> /// Gets or sets the minimum level of log messages if none of the rules match. /// </summary> public LogLevel MinLevel { get; set; } /// <summary> /// Gets the collection of <see cref="LoggerFilterRule"/> used for filtering log messages. /// </summary> public IList<LoggerFilterRule> Rules { get; } = new List<LoggerFilterRule>(); }
系统提供的所有扩展方法是将Rule添加到该对象的Rule中,然后在创建ILogger(由LogProvider创建)规则时根据某些规则匹配属于该ILogger(由LogProvider创建)的扩展方法. ,分配给LoggerInformation的Filter属性. 也就是说,即使有很多规则,最终也只会找到最符合条件的规则. 如果未找到,则使用MinLevel. 默认情况下,MinLevel为Information. LoggerFilterRule中包含的属性是上述过滤条件:
public class LoggerFilterRule { public LoggerFilterRule(string providerName, string categoryName, LogLevel? logLevel, Func<string, string, LogLevel, bool> filter) { ProviderName = providerName; CategoryName = categoryName; LogLevel = logLevel; Filter = filter; } /// <summary> /// Gets the logger provider type or alias this rule applies to. /// </summary> public string ProviderName { get; } /// <summary> /// Gets the logger category this rule applies to. /// </summary> public string CategoryName { get; } /// <summary> /// Gets the minimum <see cref="LogLevel"/> of messages. /// </summary> public LogLevel? LogLevel { get; } /// <summary> /// Gets the filter delegate that would be applied to messages that passed the <see cref="LogLevel"/>. /// </summary> public Func<string, string, LogLevel, bool> Filter { get; } public override string ToString() { return $"{nameof(ProviderName)}: '{ProviderName}', {nameof(CategoryName)}: '{CategoryName}', {nameof(LogLevel)}: '{LogLevel}', {nameof(Filter)}: '{Filter}'"; } }

查找规则有哪些匹配规则?核心代码如下(稍后可以直接查看说明):
internal class LoggerRuleSelector { public void Select(LoggerFilterOptions options, Type providerType, string category, out LogLevel? minLevel, out Func<string, string, LogLevel, bool> filter) { filter = null; minLevel = options.MinLevel; // Filter rule selection: // 1. Select rules for current logger type, if there is none, select ones without logger type specified // 2. Select rules with longest matching categories // 3. If there nothing matched by category take all rules without category // 3. If there is only one rule use it's level and filter // 4. If there are multiple rules use last // 5. If there are no applicable rules use global minimal level var providerAlias = ProviderAliasUtilities.GetAlias(providerType); LoggerFilterRule current = null; foreach (var rule in options.Rules) { if (IsBetter(rule, current, providerType.FullName, category) || (!string.IsNullOrEmpty(providerAlias) && IsBetter(rule, current, providerAlias, category))) { current = rule; } } if (current != null) { filter = current.Filter; minLevel = current.LogLevel; } } private static bool IsBetter(LoggerFilterRule rule, LoggerFilterRule current, string logger, string category) { // Skip rules with inapplicable type or category if (rule.ProviderName != null && rule.ProviderName != logger) { return false; } if (rule.CategoryName != null && !category.StartsWith(rule.CategoryName, StringComparison.OrdinalIgnoreCase)) { return false; } if (current?.ProviderName != null) { if (rule.ProviderName == null) { return false; } } else { // We want to skip category check when going from no provider to having provider if (rule.ProviderName != null) { return true; } } if (current?.CategoryName != null) { if (rule.CategoryName == null) { return false; } if (current.CategoryName.Length > rule.CategoryName.Length) { return false; } } return true; } }
在配置规则时,默认情况下ProviderName应该是该类的全名,而上面提到的ProviderAlias是指该类的昵称. 将ProviderAliasAttribute添加到该类中,以为其定义昵称,以方便配置.
让我们再次看看IsBetter方法:
如果传递的规则应用于特定的提供程序,并且与当前的日志提供程序不一致,则它会直接返回False,因为它不匹配. 如果传递的规则应用于特定的类别(默认为类)全名,并且与当前Log的类别不匹配,则返回False,因为它不匹配如果将当前规则应用于特定的Provider,并且传入的规则未应用于特定的Provider,它返回False,因为当前优先级更高. 如果当前规则未应用于特定的提供者,而传入规则被应用于特定的提供者(由于存在第一点,则传入规则提供者必须为,并且由于存在第二点,如果传入的规则包含“类别”,则它必须与当前Log相同),然后返回Truenet日志分类记录源码,因为如果将当前规则应用于特定的“特定类别”,则传入的优先级更高,而传递的规则不应用于特定类别,它会返回False,因为当前优先级更高. 如果当前规则应用于特定类别,并且当前传递的规则也应用于特定类别,但是当前匹配度更高(字符串长度越长),则返回Falsenet日志分类记录源码,因为当前优先级更高,并且其余的返回True
然后最终的规则匹配度从低到高应该是:
ProviderName: 空,CategoryName: nullProviderName: 空,CategoryName: 匹配(匹配长度越长,匹配越多)ProviderName: 已匹配,CategoryName: nullProviderName: 匹配,CategoryName: 匹配(匹配长度越长,匹配越多)

CategoryName的匹配程度是指字符串的长度. 如果未找到规则,则使用MinLevel.
使用配置文件配置日志过滤条件. 注意: 使用配置文件时,只能设置特定提供程序和类别的LogLevel,并且不能指定委托类型Filter. 如果要使用过滤器,则只能通过编码进行配置. 让我们看一个日志配置示例:
"Logging": { "LogLevel": { "Default": "Debug" }, "Console": { "LogLevel": { "Default": "Warning", "CoreLogging.Controllers": "Error", "CoreLogging.Controllers.HomeController": "Info" } } }
在LogLevel下配置,LogLevel下的直接子节点表示Proivder为空,子节点的名称表示Category,值表示LogLevel.
对于“记录”下的其他直接子节点,节点名称表示ProviderName. LogLevel子节点下面的子节点,名称代表类别,值代表LogLevel.
此外,Category的值为Default,并且在最终解析时它将被解析为null. 它不区分大小写.
此处的控制台可以用Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider替换,因为ConsoleLoggerProvider具有特殊的性别名称Console,所以您不能写全名. [ProviderAlias(“控制台”)]
最后,此配置将解释为:
对于非控制台日志记录,仅记录日志级别高于DebugConsole的日志. 如果类别不是以CoreLogging.Controllers开头,则仅记录控制台级别高于“警告”的日志,如果类别以CoreLogging.Controllers开头但以CoreLogging.Controllers.HomeController开头,则仅记录级别高于“错误”的控制台日志. 如果Category以CoreLogging.Controllers.HomeController开头,则仅记录级别高于Info的日志
本文提到的源代码全在
转载于:
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-232408-1.html
这家公司演变成三鹿