我的编程空间,编程开发者的网络收藏夹
学习永远不晚

.NetCore日志记录之日志配置

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

.NetCore日志记录之日志配置

一、前言

在项目的开发维护阶段,有时候我们关注的问题不仅仅在于功能的实现,甚至需要关注系统发布上线后遇到的问题能否及时的查找并解决。所以我们需要有一个好的解决方案来及时的定位错误的根源并做出正确及时的修复,这样才能不影响系统正常的运行状态。

这个时候我们发现,其实在asp.net core中已经内置了日志系统,并提供了各种内置和第三方日志记录提供程序的日志记录接口,在进行应用开发中,可以进行统一配置,并且利用第三方日志框架相结合,更加有效的实现日志记录。所以在这个系列中,主要是对内置日志记录系统的学习,以及后续使用第三方日志框架集成我们需要的日志系统。

二、说明

在这一篇中主要是对日志记录的配置进行说明,从开始配置日志,以及后续使用配置进行日志处理。

在新建项目成功之后,我们都会看到一个命名为appsettings.json配置,打开一看,短短的几行配置,

  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },

然后启动运行的时候,程序会在调试面板和控制台中分别输出显示来源如下:

在控制台中:

在调试面板中:

这里的日志配置,在系统中到底都起来什么作用?让我们来一探究竟吧!

三、开始

3.1 默认配置

我们查看源代码发现,在程序的入口点中发现,在初始化时候,通过CreateDefaultBuilder方法来实现日志记录的默认配置。

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

所以下面我们看一下CreateDefaultBuilder在源码中都对日志做了哪些默认配置?

        public static IHostBuilder CreateDefaultBuilder(string[] args)
        {
            var builder = new HostBuilder();

            builder.UseContentRoot(Directory.GetCurrentDirectory());
            builder.ConfigureHostConfiguration(config =>
            {
                config.AddEnvironmentVariables(prefix: "DOTNET_");
                if (args != null)
                {
                    config.AddCommandLine(args);
                }
            });
            builder.ConfigureAppConfiguration((hostingContext, config) =>
            {
                var env = hostingContext.HostingEnvironment;

                config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                      .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

                if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName))
                {
                    var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
                    if (appAssembly != null)
                    {
                        config.AddUserSecrets(appAssembly, optional: true);
                    }
                }
                config.AddEnvironmentVariables();

                if (args != null)
                {
                    config.AddCommandLine(args);
                }
            })
            .ConfigureLogging((hostingContext, logging) =>
            {
                var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
                if (isWindows)
                {
                    logging.AddFilter<EventLogLoggerProvider>(level => level >= LogLevel.Warning);
                } logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                logging.AddConsole();
                logging.AddDebug();
                logging.AddEventSourceLogger();
                if (isWindows)
                {
                    logging.AddEventLog();
                }
            })
            .UseDefaultServiceProvider((context, options) =>
            {
                var isDevelopment = context.HostingEnvironment.IsDevelopment();
                options.ValidateScopes = isDevelopment;
                options.ValidateOnBuild = isDevelopment;
            });
            return builder;
        }

通过上面这一段源码我们可以看到一个命名为ConfigureLogging的对象,我们根据命名的意思大致可以看出,这是一个配置日志的方法,继续查看ConfigureLogging源码

    public static IHostBuilder ConfigureLogging(this IHostBuilder hostBuilder, Action<HostBuilderContext, ILoggingBuilder> configureLogging)
    {
        return hostBuilder.ConfigureServices((context, collection) => collection.AddLogging(builder => configureLogging(context, builder)));
    }

通过IServiceCollection注册服务集合容器,将日志服务添加到这个服务容器,使用AddLogging方法实现对日志服务的注册。

    public static IServiceCollection AddLogging(this IServiceCollection services, Action<ILoggingBuilder> configure)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        services.AddOptions();
        services.TryAdd(ServiceDescriptor.Singleton<ILoggerFactory, LoggerFactory>());
        services.TryAdd(ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(Logger<>)));

        services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<LoggerFilterOptions>>(
            new DefaultLoggerLevelConfigureOptions(LogLevel.Information)));

        configure(new LoggingBuilder(services));
        return services;
    }

通过AddLogging添加到服务集合容器,先通过添加所需的配置AddOptions,通过注入的方式实现默认的ILoggerFactory,ILogger ( 这个会在后续的篇章中进行说明),再后通过LoggingBuilder完成日志对象的创建,

public interface ILoggingBuilder
{
    IServiceCollection Services { get; }
}
internal class LoggingBuilder : ILoggingBuilder
{
    public LoggingBuilder(IServiceCollection services)
    {
        Services = services;
    }

    public IServiceCollection Services { get; }
}

对日志系统的配置,用于提供程序的接口,ILoggingBuilder后面可以对该对象进行拓展使用。

通过以上的流程CreateDefaultBuilder方法,实现对预先配置的默认值初始化,因此也发现了其中的ConfigureLogging也是其中要进行默认初始化的值,也就是系统默认的日志配置。

单独把ConfigureLogging这一块的源码拎出来再看看:

        .ConfigureLogging((hostingContext, logging) =>
        {
            var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
            if (isWindows)
            {
                logging.AddFilter<EventLogLoggerProvider>(level => level >= LogLevel.Warning);
            }
            logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
            logging.AddConsole();
            logging.AddDebug();
            logging.AddEventSourceLogger();

            if (isWindows)
            {
                logging.AddEventLog();
            }
        })

在asp.net core启动中,根据操作系统平台适应不同的服务,在windows服务中,将EventLogLoggerProvider的默认值设置为警告或者更高的级别。

AddConfiguration : 添加系统日志的全局配置。

在配置中,可以根据提供的不同类型程序来针对实现日志记录的输出方式。而这里默认实现的AddConsole()AddDebug() 和AddEventSourceLogger()分别是将日志输出到控制台、调试窗口中,以及提供写入事件源。

AddConsole : 添加控制台到工厂方法中,用来将日志记录到控制台中。

AddDebug : 添加Debug窗口到工厂方法中,用来将日志记录到窗口中。

说明:asp.net core 内置的日志接口中,实现了多种内置的日志提供器,除了上面默认实现的ConsoleDebugEventSource,还包括下面的这几个

EventLog :

TraceSource

AzureAppServicesFile

AzureAppServicesBlob

ApplicationInsights

还记得上面提到的appsettings.json配置吗?在这里,我们来看看

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "Microsoft": "Information"
    },
    "Console": {
      "LogLevel": {
        "Default": "Debug",
        "System": "Warning"
      }
    }
  }
}

AddConfiguration中,

logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));

获取配置文件的Logging数据,实现全局配置,

        public static ILoggingBuilder AddConfiguration(this ILoggingBuilder builder, IConfiguration configuration)
        {
            builder.AddConfiguration();
            builder.Services.AddSingleton<IConfigureOptions<LoggerFilterOptions>>(new LoggerFilterConfigureOptions(configuration));
            builder.Services.AddSingleton<IOptionsChangeTokenSource<LoggerFilterOptions>>(new ConfigurationChangeTokenSource<LoggerFilterOptions>(configuration));
            builder.Services.AddSingleton(new LoggingConfiguration(configuration));
            return builder;
        }
internal class LoggerFilterConfigureOptions : IConfigureOptions<LoggerFilterOptions>
{
    private const string LogLevelKey = "LogLevel";
    private const string DefaultCategory = "Default";
    private readonly IConfiguration _configuration;

    public LoggerFilterConfigureOptions(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public void Configure(LoggerFilterOptions options)
    {
        LoadDefaultConfigValues(options);
    }

    private void LoadDefaultConfigValues(LoggerFilterOptions options)
    {
        if (_configuration == null)
        {
            return;
        }

        options.CaptureScopes = _configuration.GetValue(nameof(options.CaptureScopes), options.CaptureScopes);

        foreach (var configurationSection in _configuration.GetChildren())
        {
            if (configurationSection.Key.Equals(LogLevelKey, StringComparison.OrdinalIgnoreCase))
            {
                // Load global category defaults
                LoadRules(options, configurationSection, null);
            }
            else
            {
                var logLevelSection = configurationSection.GetSection(LogLevelKey);
                if (logLevelSection != null)
                {
                    // Load logger specific rules
                    var logger = configurationSection.Key;
                    LoadRules(options, logLevelSection, logger);
                }
            }
        }
    }
    private void LoadRules(LoggerFilterOptions options, IConfigurationSection configurationSection, string logger)
    {
        foreach (var section in configurationSection.AsEnumerable(true))
        {
            if (TryGetSwitch(section.Value, out var level))
            {
                var category = section.Key;
                if (category.Equals(DefaultCategory, StringComparison.OrdinalIgnoreCase))
                {
                    category = null;
                }
                var newRule = new LoggerFilterRule(logger, category, level, null);
                options.Rules.Add(newRule);
            }
        }
    }
}

以上是AddConfiguration实现的整体流程源码,默认注册实现LoggerFilterConfigureOptions对配置数据的读取,其中定义的 LogLevelKey = "LogLevel" 、DefaultCategory = "Default" 默认字符串,以此来获取默认全局配置数据。

在默认配置的文本格式appsettings.json中,Logging属性可以具有LogLevel和日志提供程序属性。Logging 下的 LogLevel 属性指定了用于记录所选类别的最低级别。在本例中, Microsoft 类别在 Information 级别记录,其他均在 Debug 级别记录。

日志级别说明:每一个日志都有指定的日志级别值,日志级别判断指示严重性或重要性。使用日志等级可以很好的过滤想要的日志,记录日志记录问题的同时,甚至为我们提供非常详细的日志信息。

LogLevel 严重性:Trace < Debug < Information < Warning < Error < Critical < None。

日志级别常用场景
Trace = 0记录一些对程序员调试问题有帮助的信息, 其中可能包含一些敏感信息, 所以应该避免在 生产环境中启用Trace日志,因此不应该用于生产环境。默认应禁用。
Debug = 1记录一些在开发和调试阶段有用的短时变 量(Short-term usefulness), 所以除非为了临时排除生产环境的 故障,开发人员应该尽量避免在生产环境中启用Debug日志,默认情况下这是最详细的日志。
Information = 2记录跟踪应用程序的一些流程, 例如,记录当前api请求的url。
Warning = 3记录应用程序中发生出现错误或其它导致程序停止的流程异常信息。 这些信息中可能包含错误消息或者错误产生的条件, 可供后续调查,例如, 文件未找到
Error = 4记录应用程序中某个操作产生的错误和异常信息。这些消息应该指明当前活动或操作(比如当前的 HTTP 请求),而不是应用程序范围的故障。
Critical = 5记录一些需要立刻修复,急需被关注的问题,应当记录关键级别的日志。例如数据丢失,磁盘空间不足等。

日志级别只需要简单的通过 AddFilter 对日志的过滤级别配置一下就行了。同时也可以通过自定义在

在 Logging.{providername}.LogLevel 中指定了级别,则这些级别将重写 Logging.LogLevel 中设置的所有内容。(在下文自定义中说明)

由此可以看出,日志记录提供程序配置由一个或多个配置提供程序提供,如文件格式(系统自带的appsettings.json)或者通过(已安装或已创建的)自定义提供程序(下文会说明自定义方式)。

3.2 自定义配置

看完了上面实现的默认配置之后,我们也清楚了可以修改默认配置实现不同等级日志的输出,因此,我们也可以通过自定义的方式,对默认配置的修改,实现我们想要的日志记录方式。

可以通过自行选择添加提供程序来替换默认配置的提供的程序。这样就实现自定义。自定义的方式有很多,比如

3.2.1 代码添加提供程序

调用ClearProviders,清除默认之后,可添加所需的提供程序。如下:

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args) //可以看出在使用模板创建项目的时候,默认添加了控制台和调试日志组件,并从appsettings.json中读取配置。
        .ConfigureLogging((hostingContext, logging) =>
        {
            logging.ClearProviders(); //去掉默认添加的日志提供程序
            //添加控制台输出
            logging.AddConsole();
            //添加调试输出
            logging.AddDebug();
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {  
            webBuilder.UseStartup<Startup>();
        });
}

由上可以发现我们可以通过在入口程序中直接对添加ConfigureLogging(在上文中源码可以看出)拓展方法来实现我们的自定义配置。

3.2.2 代码添加过滤器

过滤器AddFilter,添加过滤规则,可以为不同的日志提供者指定不同的过滤器,实现有效的自定义日志的输出。如下代码:

.ConfigureLogging(logging =>
    logging.AddFilter("System", LogLevel.Debug)
           .AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Trace))

添加指定了全局的过滤器,作用于所有日志提供者,示例中的第二个 AddFilter 使用类型名称来指定调试提供程序。 第一个 AddFilter 应用于全部提供程序,因为它未指定提供程序类型。

这里的AddFilter其实于之前读取配置文件信息添加配置AddConfiguration的作用相似,只是从配置文件的逻辑改成了以代码的方式实现过滤筛选,到最终也是对ConfigureOptions 的配置。

3.2.3 配置文件自定义

ASP.NET Core默认会从appSetting.json中的Logging属性读取日志的配置(当然你也可以从其他文件中读取配置),这里设置了不同的日志提供器产生的最低的日志级别,配置样例如下。

{
  "Logging": {
    "Debug": {
      "LogLevel": {
        "Default": "Information"
      }
    },
    "Console": {
      "LogLevel": {
        "Microsoft.AspNetCore.Mvc.Razor.Internal": "Warning",
        "Microsoft.AspNetCore.Mvc.Razor.Razor": "Debug",
        "Microsoft.AspNetCore.Mvc.Razor": "Error",
        "Default": "Information"
      }
    },
    "LogLevel": {
      "Default": "Debug"
    }
  }
}

此 JSON 将创建 6 条筛选规则:Debug中1 条用于调试提供程序,Console中 4 条用于控制台提供程序,最后一条LogLevel 用于所有提供程序。 创建 ILogger 对象时,为每个提供程序选择一个规则。

四、问题

虽然在这一节中只是对日志记录的配置进行了说明,但是在后续中也会对日志内部的核心运行机制进行说明介绍。所以,在这一篇中留下几个疑问

  • 日志记录的输出可以在哪里查看?而又由什么实现决定的呢?
  • 如何管理输出不同的日志呢?都有哪些方式呢?

以上的这些内容,会在下一篇进行介绍说明。

好了,今天的日志配置内容就说到这里了,希望能给大家在使用Core开发项目中对日志系统有进一步的认识。

五、总结

  • 本篇主要是对net core3.1中内置的系统日志进行配置使用,不管是基于默认配置的输出方式,还是自定义形式的配置,都是为了有效的输出日志记录,便于我们查找发现问题。
  • 关于日志配置,其实都是在对ConfigureOptions的配置,只是在形式上是直接读取配置文件或通过代码的方式实现自定义来实现日志配置。
  • 后续会对内置的日志系统进一步说明,以及内部运行的主要核心机制。
  • 如果有不对的或不理解的地方,希望大家可以多多指正,提出问题,一起讨论,不断学习,共同进步。
  • 官方源码 和 参考资料

到此这篇关于.Net Core日志记录之日志配置的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

.NetCore日志记录之日志配置

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

如何在python中配置日志记录

如何在python中配置日志记录?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。python的数据类型有哪些?python的数据类型:1. 数字类型,包括int(整型)、lo
2023-06-14

Laravel中的日志记录怎么配置

本篇内容介绍了“Laravel中的日志记录怎么配置”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Laravel 是一个开源 PHP web
2023-07-05

PHP 日志记录和监控的配置

php 日志记录和监控的配置对于应用程序稳定性至关重要。使用 monolog 记录事件,sentry 分析错误,prometheus 监控度量数据,可以让开发人员快速诊断问题,提高应用程序性能。PHP 日志记录和监控的配置日志记录和监控对
PHP 日志记录和监控的配置
2024-05-01

python 日志记录

周海汉 /文http://blog.csdn.net/ablo_zhou2010.3.20 一、我写的log4py介绍 在写<汉字大全>时,自己实现了简单的log系统:#!/bin/env python#--*-- coding=utf8
2023-01-31

怎么在python中配置日志记录器

怎么在python中配置日志记录器?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Python主要用来做什么Python主要应用于:1、Web开发;2、数据科学研究;3、网络爬虫
2023-06-14

MongoDB的审计与日志记录怎么配置

在MongoDB中,审计和日志记录可以通过配置审计功能和启用慢查询日志来实现。配置审计功能:在MongoDB中,可以通过修改数据库的配置文件(mongod.conf)来启用审计功能。在配置文件中添加以下配置项:auditLog:desti
MongoDB的审计与日志记录怎么配置
2024-05-07

C#配置log4net实现将日志分类记录到不同的日志文件中

使用log4net配置C#应用程序,将不同日志类别记录到单独日志文件中。这有助于组织日志文件,简化故障排除和分析。通过XML配置文件和附加程序,可以将日志记录器与不同的日志文件相关联。该示例提供了将两个日志记录器配置为写入不同日志文件的详细步骤和代码示例。这样,不同的日志消息就会被分类记录,便于应用程序的维护和调试。
C#配置log4net实现将日志分类记录到不同的日志文件中
2024-04-02

日志记录模块logging

在python中,日志记录显示有两种方式,一种是保存在文件和打印屏幕上,一种保存在文件中。第一种,直接保存在文件中。 1 import logging #日志模块,方便记录日志 2 3 # 下面是配置日志记录格式 4 logging.b
2023-01-30

JavaScript怎么记录日志

这篇文章主要介绍了JavaScript怎么记录日志的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇JavaScript怎么记录日志文章都会有所收获,下面我们一起来看看吧。console.log()在浏览器中使用c
2023-07-06

Mariadb之日志相关配置 - Linux

前面我们聊到了mariadb的事务,以及事务隔离级别,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13198186.html;今天我们来聊一聊mariadb的日志相关话题;mariadb日志有6种,分别是查询日志(ge
Mariadb之日志相关配置 - Linux
2017-09-14

Python开发之日志记录模块:logg

最近在开发一个应用软件,为方便调试和后期维护,在代码中添加了日志,用的是Python内置的logging模块,看了许多博主的博文,颇有所得。不得不说,有许多博主大牛总结得确实很好。似乎我再写关于logging的博文有些多余,但不写总结又总觉
2023-01-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录