zoukankan      html  css  js  c++  java
  • ASP.NET Core 中的日志记录

    内置日志的使用

    Logger 是 asp .net core 的内置 service,所以我们就不需要在ConfigureService里面注册了。同时在asp.net core 2.0版本及以后,系统已经在CreateDefaultBuilder方法里默认配置了输出到Console和Debug窗口的Logger。

    .ConfigureLogging(delegate(WebHostBuilderContext hostingContext, ILoggingBuilder logging)
    {
    	logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
    	logging.AddConsole();
    	logging.AddDebug();
    })
    

    所以我们可以Controller里面直接注入ILoggerFactory然后再创建具体的Logger。

    private readonly ILogger _logger;
    public HomeController(ILoggerFactory logger)
    {
        _logger = logger.CreateLogger<HomeController>();
    }
    

    但是还有更好的方式,Container可以直接提供一个ILogger的实例,这时候呢Logger就会使用T的名字作为日志的类别:

    private readonly ILogger _logger;
    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }
    

    然后在【Output】窗口中可以看到输出的日志:

    LogDemo> info: LogDemo.Controllers.HomeController[0]
    LogDemo>       Return Index view
    

    Log到Debug窗口或者Console窗口还是比较方便的,但是正式生产环境中这肯定不够用。正式环境应该Log到文件或者数据库等。接下来试下Nlog。

    使用Nlog

    1. NuGet添加 NLog.Web.AspNetCore

      <PackageReference Include="Microsoft.AspNetCore.App" />
      
    2. 添加配置文件

      新建一个文件nlog.config(建议全部小写,linux系统中要注意), 并右键点击其属性,将其“复制到输出目录”设置为“始终复制”。文件内容如下

      <?xml version="1.0" encoding="utf-8" ?>
      <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            autoReload="true"
            internalLogLevel="info"
            internalLogFile="c:	empinternal-nlog.txt">
      
        <!-- enable asp.net core layout renderers -->
        <extensions>
          <add assembly="NLog.Web.AspNetCore"/>
        </extensions>
      
        <!-- the targets to write to -->
        <targets>
          <!-- write logs to file  -->
          <target xsi:type="File" name="allfile" fileName="c:	emp
      log-all-${shortdate}.log"
                  layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" />
      
          <!-- another file log, only own logs. Uses some ASP.NET core renderers -->
          <target xsi:type="File" name="ownFile-web" fileName="c:	emp
      log-own-${shortdate}.log"
                  layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />
        </targets>
      
        <!-- rules to map from logger name to target -->
        <rules>
          <!--All logs, including from Microsoft-->
          <logger name="*" minlevel="Trace" writeTo="allfile" />
      
          <!--Skip non-critical Microsoft logs and so log only own logs-->
          <logger name="Microsoft.*" maxLevel="Info" final="true" />
          <!-- BlackHole without writeTo -->
          <logger name="*" minlevel="Trace" writeTo="ownFile-web" />
        </rules>
      </nlog>
      
          <Content Update="nlog.config">
            <CopyToOutputDirectory>Always</CopyToOutputDirectory>
          </Content>
      
    3. 修改Program.cs文件

      添加引用 NLog.Web 和 Microsoft.Extensions.Logging。
      在 .UseStartup() 后添加一句 .UseNLog()

      如果要禁用默认的输出框日志,可以调用logging.ClearProviders()

      public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
          WebHost.CreateDefaultBuilder(args)
              .UseStartup<Startup>()
              .ConfigureLogging(logging =>
              {
                  logging.ClearProviders();
                  logging.SetMinimumLevel(LogLevel.Trace);
              })
              .UseNLog();
      
    4. 输出到数据库

      除了把日志输出到文件之外,也可以保存到SQL Server, PostgreSQL, MySQL, Elasticsearch等。下面是保存到SQL Server的一个示例配置:

      <?xml version="1.0" encoding="utf-8" ?>
      <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            autoReload="true"
            internalLogLevel="info"
            internalLogFile="d:	emplogsinternal-nlog.txt">
      
        <!-- enable asp.net core layout renderers -->
        <extensions>
          <add assembly="NLog.Web.AspNetCore"/>
        </extensions>
      
        <!-- the targets to write to -->
        <targets>
          <!-- write logs to file  -->
          <target xsi:type="File" name="allfile" fileName="d:	emplogsall-${shortdate}.log"
                  layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" />
      
          <target name="blackhole" xsi:type="Null" />
      
          <target name="database" xsi:type="Database" dbProvider="System.Data.SqlClient">
            <connectionString>
              Server=.;Database=Log;Trusted_Connection=True
            </connectionString>
            <commandText>
                    insert into dbo.Log (
                    Application, Logged, Level, Message,
                    Logger, CallSite, Exception
                    ) values (
                    @Application, @Logged, @Level, @Message,
                    @Logger, @Callsite, @Exception
                    );
                </commandText>
       
                <parameter name="@application" layout="Application" />
                <parameter name="@logged" layout="${date}" />
                <parameter name="@level" layout="${level}" />
                <parameter name="@message" layout="url: ${aspnet-request-url} | action: ${aspnet-mvc-action} | ${message}" />
       
                <parameter name="@logger" layout="${logger}" />
                <parameter name="@callSite" layout="${callsite:filename=true}" />
                <parameter name="@exception" layout="${exception:tostring}" />
          </target>
        </targets>
      
        <!-- rules to map from logger name to target -->
        <rules>
          <!--All logs, including from Microsoft-->
          <logger name="*" minlevel="Info" writeTo="allfile" />
          
          <!--Skip non-critical Microsoft logs and so log only own logs-->
          <logger name="Microsoft.*" maxLevel="Info" final="true" />
          <!-- BlackHole without writeTo -->
          <logger name="*" minlevel="Info" writeTo="database" />
        </rules>
      </nlog>
      
    5. 配置简要说明

      targets:用于配置输出相关内容,比如 type 属性可选项为File、Mail、Console等,用于设置输出目标,layout属性用于设置输出信息的组成元素及格式。
      rules: 其实是一个“路由表”,日志是从上到下匹配的。 logger name="Microsoft." maxlevel="Info" final="true" 一句话的 final="true" 过滤掉了"Microsoft." Info级别以下的日志。

    6. 全局异常中间件

      除了输出日志外,可以写一个中间件来处理全局的异常。

      public class GlobalErrorHandlingMiddleware
      {
          private readonly RequestDelegate next;
          private readonly ILogger<GlobalErrorHandlingMiddleware> _logger;
      
          public GlobalErrorHandlingMiddleware(RequestDelegate next, ILogger<GlobalErrorHandlingMiddleware> logger)
          {
              this.next = next;
              this._logger = logger;
          }
      
          public async Task Invoke(HttpContext context)
          {
              try
              {
                  await next(context);
              }
              catch (Exception ex)
              {
      
                  var Request = context.Request;
                  ///访问路径
                  string visit_url = Request.Path;
                  ///URL 请求方法
                  string method = Request.Method.ToUpper();
                  ///URL 请求的参数
                  string url_paramters = string.Empty;
      
                  if (method == "GET") url_paramters = Request.QueryString.Value;
      
      
                  if (method == "POST")
                  {
                      foreach (var item in Request.Form)
                          url_paramters = url_paramters + item.Key + "=" + item.Value + "&";
                  }
      
                  ///错识信息
                  string err_msg = ex.Message;//ex.StackTrace;
      
                  ///日志格式内容
                  var logs_msg = $"{visit_url}#{method}#{url_paramters}#{err_msg}";
      
                  _logger.LogError(logs_msg);
      
                  var statusCode = context.Response.StatusCode;
      
                  var msg = $"Status Code: {statusCode}, Message: {ex.Message}";
      
                  await HandleExceptionAsync(context, msg);
              }
          }
      
          private static Task HandleExceptionAsync(HttpContext context, string msg)
          {
              //var data = new Result { Title = "异常中间件返回", Msg = msg };
              //var result = JsonConvert.SerializeObject(data);
              //context.Response.ContentType = "application/json;charset=utf-8";
              return context.Response.WriteAsync(msg);
          }
      }
      
      public static class GlobalErrorHandlingMiddlewareExtensions
      {
          public static IApplicationBuilder UseGlobalErrorHandlingMiddleware(
              this IApplicationBuilder builder)
          {
              return builder.UseMiddleware<GlobalErrorHandlingMiddleware>();
          }
      }
      

    集成ELK

    1. ELK简介

      ELK是三个开源软件的缩写,分别表示:Elasticsearch , Logstash, Kibana , 它们都是开源软件。现在新增了一个FileBeat,它是一个轻量级的日志收集处理工具。

      • Logstash: 是动态数据收集管道,能够同时从多个来源采集数据、转换数据、然后将数据存到数据库中。
      • Elastaicsearch: 分布式搜索和分析引擎,提供搜集、分析、存储数据三大功能。。
      • Kibana:数据可视化Web。
      • Beats: 轻量型采集器的平台,从边缘机器向 Logstash 和 Elasticsearch 发送数据。

      ELK

    2. 环境快速搭建

      这里使用docker-compose一键搭建ELK测试环境:

      1. 请确保已经安装Docker-compose

        docker-compose --version
        
      2. 下载代码从 The ELK stack powered by Docker and Compose 从并运行:

        git clone https://github.com/deviantony/docker-elk.git
        cd docker-elk
        docker-compose up -d
        
      3. 浏览器上访问安装服务器的ip:5601 可以打开 kibana 管理后台

        • 5000: Logstash TCP input.
        • 9200: Elasticsearch HTTP
        • 9300: Elasticsearch TCP transport
        • 5601: Kibana
    3. 修改nlog配置文件

      <target xsi:type="Network"
              name="ownLog-tcp"
              keepConnection="false"
              address="tcp://IP:5000"
              layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />
      
      

      启动项目测试,进入 kibana 后台配置并添加 index pattern。

    4. 其他写入Elasticsearch的方法

      把日志写入Elasticsearch的方法可以有多种:

      • Logstash:如上面的例子。它的优势是灵活性和诸多插件,它的问题是性能以及资源消耗。
      • Filebeat:轻量级的日志传输工具,可以将将日志直接传输存储到 Elasticsearch,也可经过Logstash或者Kafka/Redis。
      • .Net Core logger provider:如果仅限于 .Net Core的话,可以基于Elasticsearch的 .Net Core SDK封装一个日志提供程序直接写入Elasticsearch。

    参考

  • 相关阅读:
    C# 小规模查找集合性能测试
    高级前端开发不可或缺的知识
    移动前端开发-单页应用(spa)模型
    移动开发之用视频做背景
    纯CSS打造忙碌光标
    移动前端开发之数据库操作篇
    如何从源码中学习javascript
    Deffered.js的实现原理
    Codeforces Round #381 (Div. 2)
    2017 ZSTU寒假排位赛 #6
  • 原文地址:https://www.cnblogs.com/royzshare/p/9454625.html
Copyright © 2011-2022 走看看