AsyncLocalT在链路追踪中的应用

前言

在项目生产中日志的记录是必不可少的,在.net项目中,要说日志组件,log4net绝对可有一席之地,随着公司业务的发展,微服务则必定无可避免。在跨服务中通过日志进行分析性能或者排查故障点,如何快速定位日志尤为关键。链路追踪技术的出现正是解决这些痛点的。
分布式链路追踪需要收集单次请求所经过的所有服务,而且为了知道请求细节,还需要将具体的业务日志进行串联,而这一切的基础就是要通过一个traceid从头传到尾,相当于将该次请求过程产生的所有日志都关联其traceid,事后排查问题只需要知道traceid,就可以在日志中拉出与之关联的所有日志。

当然不是所有的公司都需要链路追踪,对于一些小公司,就几个单体系统,压根不需要这些。比如我们使用log4net时,会在日志模板中加入ThreadId,例如这样的模板

"%date [%thread] %-5level - %message%newline"

虽然并发高时我们多个用户的请求日志都掺杂在一起,但是我们依然可以根据线程号将该次请求的日志进行串联。这在大多时候都很好地解决了我们的问题。

老传统做法

即使在体量不大的系统中上面的线程号很好用了,但是哪有一点不用多线程的业务场景呢,当一次请求进来后可能会开多个异步线程去执行,那上面的线程号就显得力不从心了,就是说没法一下将相干日志提取出来了。

但是这难不倒我们,我们可以在业务开始时自定义一个随便字符串作为该次请求的唯一标识,然后将该变量通过参数传给下游方法,下游方法也将其一层一层接力传下去,在打印日志时都将该字段进行输出,这个办法很多人都用过吧。

AspNetCore的TraceIdentifier

难道没有一种优雅的方式能将我们某次请求的过程(包括多线程)进行串联起来的唯一标识吗?
ASPNetCore中其实一直有个不起眼的属性HttpContext.TraceIdentifier,可以说他就是框架给我们提供的traceid,我们可以在所需要的地方都注入HttpContext来获取该参数,当然不许那么麻烦,只需要给日志组件获取到该值,在任何leave的日志输出时日志组件将其输出即可,这个完全没问题,大家可以去深入研究,有些日志组件可以直接配置就可以输出该TraceIdentifier值到每一条日志中,也可以将其使用到跨应用调用时传递到下游服务,如http请求可以通过header携带该值,下游从header中获取并作为它自己的TraceIdentifier继续传递。

AsyncLocal在链路追踪的应用

ThreadLoacl倒是熟悉,是每个线程之间隔离的,每个线程操作的都是自己线程的对象,能做到各个线程或不影响。AsyncLocal并不是一个新特性,只是用的场景不多,很少被使用

定义

Represents ambient data that is local to a given asynchronous control flow, such as an asynchronous method.

表示对于给定异步控制流(如异步方法)是本地数据的环境数据。

示例

using System;
using System.Threading;
using System.Threading.Tasks;class Example
{static AsyncLocal<string> _asyncLocalString = new AsyncLocal<string>();static ThreadLocal<string> _threadLocalString = new ThreadLocal<string>();static async Task AsyncMethodA(){// Start multiple async method calls, with different AsyncLocal values.// We also set ThreadLocal values, to demonstrate how the two mechanisms differ._asyncLocalString.Value = "Value 1";_threadLocalString.Value = "Value 1";var t1 = AsyncMethodB("Value 1");_asyncLocalString.Value = "Value 2";_threadLocalString.Value = "Value 2";var t2 = AsyncMethodB("Value 2");// Await both callsawait t1;await t2;}static async Task AsyncMethodB(string expectedValue){Console.WriteLine("Entering AsyncMethodB.");Console.WriteLine("   Expected '{0}', AsyncLocal value is '{1}', ThreadLocal value is '{2}'", expectedValue, _asyncLocalString.Value, _threadLocalString.Value);await Task.Delay(100);Console.WriteLine("Exiting AsyncMethodB.");Console.WriteLine("   Expected '{0}', got '{1}', ThreadLocal value is '{2}'", expectedValue, _asyncLocalString.Value, _threadLocalString.Value);}static async Task Main(string[] args){await AsyncMethodA();}
}
// The example displays the following output:
//   Entering AsyncMethodB.
//      Expected 'Value 1', AsyncLocal value is 'Value 1', ThreadLocal value is 'Value 1'
//   Entering AsyncMethodB.
//      Expected 'Value 2', AsyncLocal value is 'Value 2', ThreadLocal value is 'Value 2'
//   Exiting AsyncMethodB.
//      Expected 'Value 2', got 'Value 2', ThreadLocal value is ''
//   Exiting AsyncMethodB.
//      Expected 'Value 1', got 'Value 1', ThreadLocal value is ''

简单理解,就是对该变量赋值后,只影响自己个自己的子线程,即当前线程发起的其他线程,包括线程池中的线程,都能获取到该值,而子线程修改该值,对父线程来说是无影响的。而这种特性貌似就是我们寻找那种能够优雅标记出同一次请求的特性。定义一个全局变量,在每次请求的起点对该变量赋值一个随机字符串,然后本次请求涉及到的所有线程访问该值,都是我们在入口赋的值。

项目应用

我们可以在任意地方定义一个全局变量,最好是放到LogHelper之中

AspNet4

public static class LogHelper{public static AsyncLocal<string> Traceid = new AsyncLocal<string>();...
}

在授权过滤器中对该值进行赋值,一般授权过滤最先执行,可作为请求的入口点

LogHelper.TraceId.Value = Guid.NewGuid().ToString();

log4net的LogHelper中使用,日志模板为

"%date [%property{trace}] [%thread] %-5level - %message%newline"
public static void Info(object message)
{ThreadContext.Properties["trace"] = TraceId.Value;Loger.Info(message);
}
...

AspNetCore

注册中间件进行设置值,将自己的中间件注册靠前点

app.Use(delegate (HttpContext ctx, RequestDelegate next)
{LogHelper.TraceId.Value = ctx.TraceIdentifier;return next(ctx);
});

经验证与预期符合,该实现方式不依赖AspnetCore框架HttpContext.TraceIdentifier,提供一种实现链路追踪中传递TraceId的一种思路,如有不正确之处欢迎指正,如果该思路对您有帮助,请点赞分享。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/288306.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows运行命令大全

要打开Windows XP系统自带的程序,菜鸟一般是用鼠标点开始/程序(或桌面、快速启动)里的快捷方式,老鸟喜欢按下Win+R并输入运行命令。Windows XP的开始运行命令大全,其实都是C:\WINDOWS\system32下面的程序,只要在开始/运行/输入相应的程序名(命令)即可。对于常用运行命令…

【转】js老生常谈之this,constructor ,prototype

前言 javascript中的this,constructor ,prototype&#xff0c;都是老生常谈的问题&#xff0c;深入理解他们的含义至关重要。在这里&#xff0c;我们再来复习一下吧&#xff0c;温故而知新&#xff01; this this表示当前对象&#xff0c;如果在全局作用范围内使用this&#xf…

Linux+Oracle+12c+RAC+安装配置详细-GI安装

IP地址主机名用途实例名192.168.12.58oracle-rac03-db03 Public ip (节点1&#xff09;192.168.12.59oracle-rac04-db04Public ip(节点2&#xff09;192.168.12.73 rac03-db03-vipvip(节点1&#xff09;racdb3 asm1192.168.12.74rac04-db04-vipvip(节点2&#xff09;racdb4 …

android auto answer,Incoming call auto answer in android 4.0.3

问题I am working in Android technology last 1 years. Currently I want develop an application incoming call auto answer in Android 4.0.3 but in this version I am not getting any solution or cant find any api for this (ITelephony.aidl). Please suggest me.回答…

剑指offer之判断二叉树是不是平衡二叉树

1 问题 判断二叉树是不是平衡二叉树 平衡二叉搜索树&#xff08;Self-balancing binary search tree&#xff09;又被称为AVL树&#xff08;有别于AVL算法&#xff09;&#xff0c;且具有以下性质&#xff1a;它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1&#x…

主成分分析法_数学建模 || 葡萄酒的评价(1)主成分分析法

首先要说一下&#xff0c;这篇文章我在其他的平台发过&#xff0c;也是本人亲自写的&#xff0c;如果大家觉得眼熟的话放弃轻松&#xff0c;没有抄袭&#xff0c;主要是因为与我这 “葡萄酒的评价” 题目成系列了&#xff0c;因此在这里再把这个贴出来。2012 年 A 题葡萄酒的评…

微信jssdk开发,PHP,必要步骤

微信的文档几个重叠在一起&#xff0c;有点乱&#xff0c;自己用到就统计一下&#xff0c;减少字数直接上&#xff0c;毕竟懒。 一般说明步骤一&#xff1a;微信jssdk使用必须在微信公众平台进入其公众号设置&#xff0c;打开配置安全域名才可以。 安全域名则是请求调用微信接…

imagePreview接口调用微信自带图片播放器

2019独角兽企业重金招聘Python工程师标准>>> 在微信浏览器中&#xff0c;出现在网页上的图片通过点按一小段时间&#xff0c;可以调出微信隐藏的图片播放器&#xff0c;在播放器中看图可以随意放大缩小&#xff0c;体验更炫酷。不过这个功能默认只对通过微信后台编辑…

使用IdentityServer出现过SameSite Cookie这个问题吗?

原文作者&#xff1a;Sebastian Gingter原文链接&#xff1a;https://reurl.cc/Dygrgd译者&#xff1a;沙漠尽头的狼译文链接&#xff1a;https://reurl.cc/1ZYNoQ本文是作者2019年的一篇分享&#xff0c;里面的一些观点和使用的技术&#xff0c;对我们现在的开发依然有效&…

windows下sc create命令行添加/创建/修改服务

C:\Users\Administrator>HELP SC 描述: SC 是用于与服务控制管理器和服务进行通信的命令行程序。 用法: sc <server> [command] [service name] <option1> <option2>... 选项 <server> 的格式为 "\\ServerName"…

TypeError: 'MongoClient' object is not callable

在声明数据库的时候&#xff0c;将中括号[ ]换成了圆括号&#xff08;&#xff09;错误&#xff1a;修改完成后的代码&#xff1a;client pymongo.MongoClient(localhost)db client[my_database]#注意这里用中括号&#xff01;&#xff01; 之后再运行程序&#xff0c;就能存…

微信JSSDK分享页面自定义当前链接最简单示例

这个是使用微信原本的Deom修改 但是一定要注意几个注意事项&#xff0c;代码很简单&#xff0c;却让我一周mmp 在微信开发者工具调试&#xff0c;有时候你代码正确但是会报错 一定要真机调试 appid和secret一定要正确 一定要在在微信公众号后台设置正确的安全目录&#xff0c;…

信息系统开发有管理

做了一套题&#xff0c;又总结了下《信息系统开发与管理》。感觉又有了新的认识。这本书应该说总体的设计都是非常具有逻辑性的。内容设计的有些水到渠成。要说结构的话&#xff0c;应该算是总—分结构吧。一開始就以一篇概述全面的介绍了此书。我总结了以下的图。 信息、系统、…

C语言之字符数组在if{}里面赋值给char *引发的问题

1 问题 我的buff在if{}里面&#xff0c;然后对buff进行内存操作&#xff0c;最后赋值给char *类型的url,发现url最后没有得到数据 如下代码 #include <stdio.h> #define TRUE 1void set_value(char *p) {*p c;*(p 1) h;*(p 2) e;*(p 3) n; }int main() {char *…

python编译器如何设置中文_如何使setup.py test使用特定的fortran编译器?

我正在尝试测试一个包含一些f90文件的package。如果我构建或安装并指定fortran编译器&#xff0c;它可以正常工作。但是&#xff0c;当我尝试测试时&#xff0c;会出现以下错误&#xff1a;C:\Users\jsalvatier\workspace\scikits.bvp_solver>python setup.py config_fc --f…

memwatch内存泄露检测工具

工具介绍 官网 http://www.linkdata.se/sourcecode/memwatch/ 其功能如下官网介绍&#xff0c;挑选重点整理&#xff1a; 1、 号称功能&#xff1a; 内存泄露检测 &#xff08;检测未释放内存&#xff0c; 即 动态内存开辟未释放的情况&#xff09; 2、 检测 多次调用free&…

Windows命令大全

C:\Users\Administrator>help 有关某个命令的详细信息,请键入 HELP 命令名 ASSOC 显示或修改文件扩展名关联。 ATTRIB 显示或更改文件属性。 BREAK 设置或清除扩展式 CTRL+C 检查。 BCDEDIT 设置启动数据库中的属性以控制启动加载。 CACL…

command not found Operation not permitted

mysql -uroot -p 报错误:command not found因为苹果在OS X 10.11中引入的SIP特性使得即使加了sudo&#xff08;也就是具有root权限&#xff09;也无法修改系统级的目录&#xff0c;其中就包括了/usr/bin。要解决这个问题有两种做法&#xff1a;比较不安全的就是关闭SIP&#x…

Main 和 静态构造函数 到底谁先执行?

最近被问到一个很有意思的问题&#xff0c;到底是 Main函数 先执行还是 静态构造函数 先执行&#xff1f;参考如下代码&#xff1a;class Program{static Program(){Console.WriteLine("我是 静态构造 函数&#xff01;");}static void Main(string[] args){Console.…

c 正则提取html,c – 正则表达式以获取HTML表格内容

确实没有可能的正则表达式解决方案适用于任意数量的表数据,并将每个单元格放入单独的后向引用中.这是因为通过反向引用,您需要为要创建的每个backref创建一个独特的开放式窗口,并且您不知道自己有多少个单元格.使用一种或另一种循环来提取数据没有任何问题.例如,在最后一个,在P…