这篇文章主要介绍了ASP.NetCore中日志与分布式链路追踪的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。最简单的日志,就是控制台输出,利用Console.WriteLine()
函数直接输出信息。下面时一个简单的信息输出,当程序调用SayHello
函数时,SayHello
会打印信息。通过控制台,我们可以看到,为了记录日志,我们必须在函数内编写输入日志的代码,优缺点这些就不多说了,我们可以通过 AOP 框架,实现切面编程,同一记录日志。这里可以使用笔者开源的 CZGL.AOP 框架,Nuget 中可以搜索到。编写统一的切入代码,这些代码将在函数被调用时执行。Before
会在被代理的方法执行前或被代理的属性调用时生效,你可以通过AspectContext
上下文,获取、修改传递的参数。After 在方法执行后或属性调用时生效,你可以通过上下文获取、修改返回值。改造 Hello 类,代码如下:然后创建代理类型:启动程序,会输出:你完全不需要担心 AOP 框架会给你的程序带来性能问题,因为 CZGL.AOP 框架采用 EMIT 编写,并且自带缓存,当一个类型被代理过,之后无需重复生成。CZGL.AOP 可以通过 .NET Core 自带的依赖注入框架和 Autofac 结合使用,自动代理 CI 容器中的服务。这样不需要AopInterceptor.CreateProxyOfClass
手动调用代理接口。CZGL.AOP 代码是开源的,可以参考笔者另一篇博文:https://www.byun.com/article/238462.htm有些公司无技术管理规范,不同的开发人员使用不同的日志框架,一个产品中可能有.txt
、NLog
、Serilog
等,并且没有同一的封装。.NET Core 中的日志组件有很多,但是流行的日志框架基本都会实现Microsoft.Extensions.Logging.Abstractions
,因此我们可以学习Microsoft.Extensions.Logging
。Microsoft.Extensions.Logging.Abstractions
是官方对日志组件的抽象,如果一个日志组件并不支持Microsoft.Extensions.Logging.Abstractions
那么这个组件很容易跟项目糅合的,后续难以模块化以及降低耦合程度。Microsoft.Extensions.Logging
软件包中包含 Logging API ,这些 Logging API 不能独立运行。它与一个或多个日志记录提供程序一起使用,这些日志记录提供程序将日志存储或显示到特定输出,例如 Console, Debug, TraceListeners。下图是 .NET Core 中 Loggin API 的层次结构:说实话,Microsoft.Extensions.Logging
刚开始是学着很懵,配置感觉很复杂。因此,有一张清晰的结构图很重要,可以帮助大家理解里面的 Logging API。.NET Core 中很多标准接口都实践了工厂模式的思想,ILoggerFactory 正是工厂模式的接口,而 LoggerFactory 是工厂模式的实现。其定义如下:ILoggerFactory 工厂接口的作用是创建一个 ILogger 类型的实例,即CreateLogger
接口。通过实现ILoggerProvider
接口可以创建自己的日志记录提供程序,表示可以创建 ILogger 实例的类型。其定义如下:ILogger 接口提供了将日志记录到基础存储的方法,其定义如下:logging providers 称为日志记录程序。Logging Providers 将日志显示或存储到特定介质,例如 console, debugging event, event log, trace listener 等。Microsoft.Extensions.Logging
提供了以下类型的 logging providers,我们可以通过 Nuget 获取。Microsoft.Extensions.Logging.ConsoleMicrosoft.Extensions.Logging.AzureAppServicesMicrosoft.Extensions.Logging.DebugMicrosoft.Extensions.Logging.EventLogMicrosoft.Extensions.Logging.EventSourceMicrosoft.Extensions.Logging.TraceSource而 Serilog 则有 File、Console、Elasticsearch、Debug、MSSqlServer、Email等。这些日志提供程序有很多,我们不必细究;如果一个日志组件,不提供兼容Microsoft.Extensions.Logging
的实现,那么根本不应该引入他。实际上,很多程序是直接File.Write("Log.txt")
,这种产品质量能好到哪里去呢?前面,介绍了Microsoft.Extensions.Logging
的组成,这里将学习如何使用 Logging Provider 输入日志。起码提到,它只是提供了一个 Logging API,因此为了输出日志,我们必须选择合适的 Logging Provider 程序,这里我们选择Microsoft.Extensions.Logging.Console
,请在 Nuget 中引用这个包。下图是 Logging Provider 和 ConsoleLogger 结合使用的结构图:从常规方法来弄,笔者发现,没法配置呀。。。所以只能使用以下代码快速创建工厂:或者:当然工厂中可以添加其它日志提供程序,示例:然后获取 ILogger 实例:记录日志:Logging API 中,规定了 7 种日志等级,其定义如下:我们可以通过 ILogger 中的函数,输出以下几种等级的日志:关于Microsoft.Extensions.Logging
这里就不再赘述,读者可以等级以下链接,了解更多相关知识:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/logging/?view=aspnetcore-5.0#log-exceptionshttps://www.tutorialsteacher.com/core/fundamentals-of-logging-in-dotnet-corehttps://docs.microsoft.com/en-us/archive/msdn-magazine/2016/april/essential-net-logging-with-net-coreDebug 、Trace 这两个类的命名空间为System.Diagnostics
,Debug 、Trace 提供一组有助于调试代码的方法和属性。读者可以参考笔者的另一篇文章://www.byun.com/article/242562.htm输出到控制台:链路追踪可以帮助开发者快速定位分布式应用架构下的性能瓶颈,提高微服务时代的开发诊断效率。前面提到的 Trace 、Debug 是 .NET Core 中提供给开发者用于诊断程序和输出信息的 API,而接着提到的 trace 只 OpenTracing API 中的 链路跟踪(trace)。普通的日志记录有很大的缺点,就是每个方法记录一个日志,我们无法将一个流程中被调用的多个方法联系起来。当一个方法出现异常时,我们很难知道是哪个任务过程出现的异常。我们只能看到哪个方法出现错误,已经它的调用者。在 OpenTracing 中,Trace 是具有 Span(跨度) 的有向无环图。一个 Span 代表应用程序中完成某些工作的逻辑表示,每个 Span 都具有以下属性:操作名称开始时间结束时间为了弄清楚,Trace 和 Span 是什么,OpenTracing 又是什么,请在 Nuget 中引入OpenTracing
。编写 Hello 类如下:启动程序,并开始追踪:在以上过程中,我们使用了 OpenTracing API,下面是关于代码中一些元素的说明:ITracer 是一个链路追踪实例,BuildSpan() 可以创建其中一个 Span;每个 ISpan 都有一个操作名称,例如say-hello
;使用Start()
开始一个 Span;使用Finish()
结束一个 Span;跟踪程序会自动记录时间戳;当然,我们运行上面的程序时,是没有出现别的信息以及 UI 界面,这是因为GlobalTracer.Instance
会返回一个无操作的 tracer。当我们定义一个 Tracer 时,可以观察到链路追踪的过程。在 Nuget 中,引入Jaeger
。在 Program 中,添加一个静态函数,这个函数返回了一个自定义的 Tracer:修改 Main 函数内容如下:完整代码:https://gist.github.com/whuanle/b57fe79c9996988db0a9b812f403f00e但是,日志直接输出 string 是很不友好的,这时,我们需要结构化日志。当然,ISpan 提供了结构化日志的方法,我们可以编写一个方法,用于格式化日志。在 Hello 类中添加以下代码:另外,我们还可以封装一个输出字符串信息的函数:将 SayHello 方法改成:改以上代码的原因是,不要在一个方法中糅合太多代码,可以尝试将一些代码复用,封装一个统一的代码。但是,原本我们只需要调用 SayHello 一个方法,这里一个方法会继续调用另外两个方法。原本是一个 Span,最后变成三个 Span。注:0000000000000000
表示一个 Span 已经结束。优点:从代码上看,SayHello -> FormaString ,SayHello -> PrintHello,我们可以清晰知道调用链路;缺点:从输出来看,Span reported 不同,我们无法中输出中判断三个函数的因果关系;我们不可能时时刻刻都盯着代码来看,运维人员和实施人员也不可能拿着代码去对比以及查找代码逻辑。ITracer 负责创建链路追踪,因此 ITracer 也提供了组合多个 Span 因果关系的 API。使用方法如下:我们创建了一个 rootSpan ,接着创建一个延续 rootSpan 的sapn
,rootSpan -> span
。输出顺序为执行完毕的顺序,say-hello 是最后才执行完成的。从什么代码中,大家发现,代码比较麻烦,因为:要将 Span 对象作为第一个参数传递给每个函数;每个函数中加上冗长的try-finally{}
确保能够完成 Span为此, OpenTracing API 提供了一种更好的方法,我们可以避免将 Span 作为参数传递给代码,可以统一自行调用 _tracer 即可。修改FormatString
和PrintHello
代码如下:修改 SayHello 代码如下:通过上面的代码,我们实现去掉了那些烦人的代码。StartActive()
代替Start()
,通过将其存储在线程本地存储中来使 span 处于“活动”状态;StartActive()
返回一个IScope
对象而不是一个对象ISpan
。IScope是当前活动范围的容器。我们通过访问活动跨度scope.Span
,一旦关闭了作用域,先前的作用域将成为当前作用域,从而重新激活当前线程中的先前活动范围;IScope
继承IDisposable
,它使我们可以使用using
语法;StartActive(true)
告诉Scope,免费云主机域名一旦它被处理,它就应该完成它所代表的范围;StartActive()
自动创建ChildOf
对先前活动范围的引用,因此我们不必AsChildOf()
显式使用 builder 方法;如果运行此程序,我们将看到所有三个报告的跨度都具有相同的跟踪ID。微服务将多个程序分开部署,每个程序提供不同的功能。在前面,我们已经学会了 OpenTracing 链路跟踪。接下来,我们将把代码拆分,控制台程序将不再提供 FormatString 函数的实现,我们使用 一个 Web 程序来实现 FormatString 服务。创建一个 ASP.NET Core 应用程序,在模板中选择带有视图模型控制器的模板。添加一个FormatController
控制器在 Controllers 目录中,其代码如下:Web 应用将作为微服务中的其中一个服务,而这个服务只有一个 API ,这个 API 很简单,就是提供字符串的格式化。你也可以编写其它 API 来提供服务。将 Program 的 CreateHostBuilder 改一下,我们固定这个服务的 端口。再到Startup
中删除app.UseHttpsRedirection();
。修改之前控制台程序的代码,把FormatString
方法改成:启动 Web 程序后,再启动 控制台程序。控制台程序输出:接着,我们可以将 Formating 改成:SetTag
可以设置标签,我们为本次请求到 Web 的 Span,设置一个标签,并且存储请求的 URL。通过Inject
将上下文信息注入。这些配置规范,可以到https://github.com/opentracing/specification/blob/master/semantic_conventions.md了解。在上面,我们实现了 Client 在不同进程的追踪,但是还没有实现在 Server 中跟踪,我们可以修改 Startup.cs 中的代码,将以下代码替换进去:这样不同的进程各种都可以实现追踪。OpenTracing 是开放式分布式追踪规范,OpenTracing API 是一致,可表达,与供应商无关的API,用于分布式跟踪和上下文传播。Jaeger 是 Uber 开源的分布式跟踪系统。OpenTracing 的客户端库以及规范,可以到 Github 中查看:https://github.com/opentracing/详细的介绍可以自行查阅资料。这里我们需要部署一个 Jaeger 实例,以供微服务以及事务跟踪学习需要。使用 Docker 部署很简单,只需要执行下面一条命令即可:访问 16686 端口,即可看到 UI 界面。Jaeger 的端口作用如下:接下来我们将学习如何通过代码,将数据上传到 Jaeger 中。要注意,数据上传到 Jaeger ,上传的是 Span,是不会上传日志内容的。继续使用上面的控制台程序,Nuget 中添加Jaeger.Senders.Grpc
包。我们可以通过 UDP (6831端口)和 gRPC(14250) 端口将数据上传到 Jaeger 中,这里我们使用 gRPC。修改控制台程序的InitTracer
方法,其代码如下:分别启动 Web 和 控制台程序,然后打开 Jaeger 界面,在 ”Service“ 中选择hello-world
,然后点击底下的Find Traces
。通过 Jaeger ,我们可以分析链路中函数的执行速度以及服务器性能情况。感谢你能够认真阅读完这篇文章,希望小编分享的“ASP.NetCore中日志与分布式链路追踪的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持百云主机,关注百云主机行业资讯频道,更多相关知识等着你来学习!
本篇内容主要讲解“JDBC连接Mysql的方式有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JDBC连接Mysql的方式有哪些”吧!mysql数据库:jdbc:mysql://localhost:3306/t…
免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。