Nlog 在.net core中 记录请求上下文的标识符

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/phker/article/details/87714802

由于做接口平台需要,清楚的记录下每个请求的日志,
当多个请求同时来访问的时候, 都记录在数据库里面, 会导致日志相互之间混淆.
所以日志在记录的时候还需要增加一个字段用来区分当前请求 “活动唯一标识符” 也就是ActivityId

先看参考答案, 后面是我自己的说明

Currently there is no built in support for CorrelationManager.ActivityId.
However you can create your own layout render which outputs it:

[LayoutRenderer("activityid")]
public class ActivityIdLayoutRenderer : LayoutRenderer
{
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
        builder.Append(Trace.CorrelationManager.ActivityId.ToString());
    }
}

You also need to register it with:

 ConfigurationItemFactory.Default.LayoutRenderers
      .RegisterDefinition("activityid", typeof(ActivityIdLayoutRenderer));

Then you can use it in your target definition with:

<target xsi:type="Mongo">
      <!-- ... -->
      <field name="ActivityId" layout="${activityid}" />
</target>

As an alternative solution you can also you the Event Context Layout Renderer to output any custom property like the ActivityId but in this case you have to include it every time when you log something.

//上面的看懂了应该也就明白了, 但是一些具体的细节上面没说清楚.
下面是我自己写的.

对于这个问题需要解决3个小问题.
一,如何在每个请求上下文中,保存唯一的标识符.
二,何时创建这个唯一的标识符
三,唯一标识符 什么规则才能不重复(很简单GUID)
四,如何自动写入到日志中, 而不需要每次自己在Log.Error的时候自己拼装成message

首先 针对这第一个问题 "如何在每个请求上下文中,保存唯一的标识符. "
这个很简单,.net已经为我们提供了这么个属性.

	//初始化唯一标识符
	Trace.CorrelationManager.ActivityId = Guid.NewGuid();

第二个问题, 何时创建这个唯一的标识符
实际上可以在请求开始的任何一个地方, 一般放在页面函数入口第一句话.进行初始化, 只要在日志记录之前就可以了. 也可以写在其它的地方. 反正上下文都是通用的. 一般都是写在中间件里面的.

第四个问题, 如何自动写入到日志中, 而不需要每次自己在Log.Error的时候自己拼装成message

首先需要一个能够取得 “唯一标识符” 的类, 这个类是扩展了Nlog, 相关文档是Nlog的. 如果你是logger4net 的, 那么看一下logger4net 是怎么取的就可以了.

using NLog;
using NLog.Config;
using NLog.LayoutRenderers;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WSI
{
    /// <summary>
    /// The trace correlation activity id.
    /// </summary>
    [LayoutRenderer("activityid")]
    [ThreadAgnostic]
    public class TraceActivityIdLayoutRenderer : LayoutRenderer
    { 

        protected override void Append(StringBuilder builder, LogEventInfo logEvent)
        {
            builder.Append(Trace.CorrelationManager.ActivityId.ToString("D", CultureInfo.InvariantCulture));
        }
    }
}

有了这个类还不行, 还需要再启用这个类. 也就是注册一下告诉Nlog 我有这么个类下次遇到${activityid} 这个变量就用我写的TraceActivityIdLayoutRenderer这个类来解析

 //这句话我一般都在Startup.cs 类中的 ConfigureServices方法中第一句话执行.
 public void ConfigureServices(  IServiceCollection services )
 {
	 ConfigurationItemFactory.Default.LayoutRenderers
      .RegisterDefinition("activityid", typeof(TraceActivityIdLayoutRenderer));
}
      

到这一步基本用过Nlog的都知道怎么用的了. 不知道的看下面.
最后一步, 在Nlog.config中. 配置输出这个数值

我的Nlog.config 是这么写的

<?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"
      xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
      autoReload="true"
      throwExceptions="false" 
      internalLogLevel="Error"
      internalLogFile="nlog.log"
      >

<!-- 
internalLogLevel="Trace"  Trace|Debug|Info|Warn|Error|Fatal决定内部日志的级别  Off=关闭
internalLogFile="nlog.log"
internalLogFile="nlog.log" 这个开了会写很多的内部信息,用来调试Nlog用. 这里用不到就关闭了
-->
  
  <!-- optional, add some variables
  https://github.com/nlog/NLog/wiki/Configuration-file#variables
  -->
  <variable name="variable1" value="
            ${newline}message:	${message}   
            ${newline}callsite:	${callsite}
            ${newline}stacktrace: ${stacktrace}${newline} 
            ${newline}counter:	${counter}
            ${newline}machinename:	${machinename}
            ${newline}appdomain:	${appdomain}
            ${newline}assembly-version:	${assembly-version}
            ${newline}basedir:	${basedir}
            ${newline}callsite-linenumber:	${callsite-linenumber}
            ${newline}nlogdir:	${nlogdir}
            ${newline}processid:	${processid}
            ${newline}processname:	${processname}
            ${newline}specialfolder:	${specialfolder}" />
  
  <!--
  See https://github.com/nlog/nlog/wiki/Configuration-file
  for information on customizing logging rules and outputs.
   -->
  <targets>
    <!--  <target name="log_file"
            xsi:type="File"
            fileName="${basedir}/LogInformation/${level}_${shortdate}.txt"
            layout="${variable1}" />-->
    <target name="blackhole" xsi:type="Null"  />

    <!--
    sql server 这么写
    <target
      name="log_database"
      xsi:type="Database"
      connectionString="Data Source=.;Initial Catalog=数据库名;Persist Security Info=True;User ID=sa;Password=密码">-->
    
    <!-- my sql 这么写 -->
    
    <target name="log_mysql_database" 
              xsi:type="Database"
              dbProvider="MySql.Data.MySqlClient.MySqlConnection, MySql.Data"
              connectionString="server=127.0.0.1;Database=wsi5;user id=root;password=123456;SslMode=none" >
       
      <commandText>
        INSERT INTO `ws_log` (
        `Date`,
        `Origin`,
        `Level`,
        `Message`,
        `Detail`,
        `Logger`,
        `Threadid`,
        `Processid`,
        `Activityid`
        ) VALUES (
        now(),
        @origin,
        @logLevel,
        @message,
        @detail,
        @logger,
        @threadid,
        @processid,
        @activityid
        );
      </commandText>
      <!--日志来源-->
      <parameter name="@origin" layout="${callsite}" />
      <!--日志等级-->
      <parameter name="@logLevel" layout="${level}" />
      <!-- 线程id -->
      <parameter name="@threadid" layout="${threadid}" /> 
      <!--日志类-->
      <parameter name="@logger" layout="${logger}" />
      
      <!--日志消息-->
      <parameter name="@message" layout="${message}" />

      <!--System.Diagnostics trace correlation id -->
      <parameter name="@activityid" layout="${activityid}" /> 就是这里用到了.
      
      <!--引用variable1信息-->
      <parameter name="@detail" layout="${variable1}" />
      <parameter name="@processid" layout="${processid}" />

    </target>


    <!-- sqlite 这么写 但是sqlite有并发访问问题 -->
    <!--<target name="log_sqlite_database" xsi:type="Database" keepConnection="false"
              useTransactions="true"
              dbProvider="System.Data.SQLite.SQLiteConnection, System.Data.SQLite" 
              connectionString="Data Source=../WSIConfig.db;Version=3;">


      <commandText>
        INSERT INTO ws_log (
        Date,
        Origin,
        Level,
        Message,
        Detail,
        Logger,
        Threadid,
        Processid
        ) VALUES (
        datetime('now', 'localtime' ),
        @origin,
        @logLevel,
        @message,
        @detail,
        @logger,
        @threadid,
        @processid
        )
      </commandText>
      日志来源 
      <parameter name="@origin" layout="${callsite}" />
       日志等级 
      <parameter name="@logLevel" layout="${level}" />
      线程id 
      <parameter name="@threadid" layout="${threadid}" />
      日志类 
      <parameter name="@logger" layout="${logger}" />

      日志消息
      <parameter name="@message" layout="${message}" />

      引用variable1信息
      <parameter name="@detail" layout="${variable1}" />
      <parameter name="@processid" layout="${processid}" />

    </target>-->
  </targets> 
  
  <rules>
    <logger name="Microsoft.*" minlevel="Trace" writeTo="blackhole" final="true" />
    <logger name="*" writeTo="log_mysql_database" />
  </rules>
</nlog>

展开阅读全文

.Net Core 的http请求问题

12-20

使用 vs for mac 生成的.net站点,其中rnrnStartup.cs:rnnamespace vs_core_webrnrn public class Startuprn rn // This method gets called by the runtime. Use this method to add services to the container.rn // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940rn public void ConfigureServices(IServiceCollection services)rn rn rnrn // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.rn public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)rn rn loggerFactory.AddConsole();rnrn if (env.IsDevelopment())rn rn app.UseDeveloperExceptionPage();rn rnrn app.Run(async (context) =>rn rn await (new testClass()).OutPutString(context); // 此处是会返回当前 testClass 类初始化的次数rn );rn rn rnrnrnrnnamespace vs_core_webrnrn public class testClassrn rn static int runtimes = 0;rn public testClass()rn rn runtimes++;rn rnrn public Task OutPutString(HttpContext context)rn rn return context.Response.WriteAsync("Hello World!"+ runtimes.ToString());rn rn rnrnrnawait (new testClass()).OutPutString(context); 这一个部分的代码,请求一次http,会触发两次,是什么情况,有人知道么?rn干净的新项目也是一样这个问题...rnrn求教~rnrn页面请求的结果(多次):rnHello World!1rnHello World!3rnHello World!5rnHello World!7rn.....rnrn尾数永远是单数 论坛

没有更多推荐了,返回首页