Rust中Tracing 应用指南
欢迎来到这篇全面的Rust跟踪入门指南。Rust 的tracing
是一个用于应用程序级别的诊断和调试的库。它提供了一种结构化的、异步感知的方式来记录日志和跟踪事件。与传统的日志记录相比,tracing
能够更好地处理复杂的异步系统和分布式系统中的事件跟踪,帮助开发者理解程序的执行流程和状态变化。
在本文中,我们将探讨跟踪的概念,它在Rust生态系统中的重要性,以及如何利用它来改进Rust应用程序。无论你是一个经验丰富的Rust爱好者,希望深入研究性能优化,还是一个对学习更多调试工具感兴趣的语言新手,本指南都旨在为你提供在Rust中有效使用跟踪所需的知识。
理解基本概念
在我们深入研究Rust中的跟踪细节之前,了解跟踪是什么以及为什么它是开发人员的关键工具是很重要的。
在软件开发的上下文中,跟踪是一种用于监视程序执行的方法。它包括记录有关程序执行的信息,例如函数调用、变量值,甚至整个调用堆栈。这些信息通常被称为“跟踪数据”,然后可以对其进行分析,以深入了解程序的行为。
跟踪在调试和性能优化中起着关键作用。通过提供程序执行的详细视图,跟踪允许开发人员识别瓶颈,发现低效率,并了解bug的根本原因。这使得它成为提高代码性能和可靠性的宝贵工具。下面是tracing 的几个关键概念:
- Span(跨度):Span 代表程序执行中的一个时间段,可以嵌套。例如,函数的执行时间范围可以是一个 Span,在这个函数内部调用的其他函数的执行范围可以是嵌套在该 Span 中的子 Span。它可以用于记录函数调用的开始和结束时间、相关的变量值等信息。
- Event(事件):事件是在程序执行过程中发生的离散的、值得记录的点。比如,某个重要的条件被满足、一个错误被抛出或者一个网络请求被发送等情况都可以记录为一个事件。
在下一节中,我们将探讨如何在Rust应用程序中利用跟踪功能。
tracing包简介
在Rust中,跟踪是由名为tracing 包的强大库提供的。这个包提供了实现框架,用于检测Rust程序,以收集结构化的、基于事件的诊断信息。与传统的日志记录不同,tracing旨在了解系统中一个事件或一系列事件的上下文,使其成为诊断复杂系统的强大工具。
要开始在Rust中进行跟踪,首先需要将tracing 包添加到项目中。这可以通过在Cargo中添加以下行来完成Cargo.toml文件:
[dependencies]
tracing = "0.1.37"
tracing - subscriber = "0.3.17"
一旦tracing 包被添加到你的项目中,你就可以通过在你的主Rust文件中添加以下一行来开始使用它:
use tracing::{info, trace, warn, error};
tracing包为不同级别的诊断信息提供了几个宏,包括 debug!
,info!
, warn!
和 error!
这些宏对应于不同级别的事件,可用于在适当级别记录信息。
在下一节中,我们将深入研究如何在Rust项目中实现跟踪,并提供代码示例和解释。
简单日志记录
我们已经在项目中设置了tracing包,让我们深入了解如何在Rust项目中实现跟踪。
use tracing::{info, trace, warn, error};
use tracing_subscriber::FmtSubscriber;fn main() {tracing::subscriber::set_global_default(tracing_subscriber::FmtSubscriber::new()).expect("setting default subscriber failed");let number = 5;info!("The number is {}", number);let result = compute(number);info!("The result is {}", result);
}fn compute(n: i32) -> i32 {trace!("Computing the value...");if n > 10 {warn!("The number is greater than 10");} else if n < 1 {error!("The number is less than 1");}n * 2
}
在上面的代码中,我们首先为跟踪事件设置默认订阅者。然后,我们使用这些info!
在信息级别记录事件的宏。在compute函数中,我们使用trace!warn!,还有error!基于n的值在不同级别记录事件的宏。
这是简单的示例,但它说明了tracing包的基本用法。你可以根据需要向代码中添加更复杂的跟踪逻辑。
使用span示例
下面示例使用span跟踪函数执行:
use tracing::{info, Level, span, Instrument};
use tracing_subscriber::FmtSubscriber;fn main() {let subscriber = FmtSubscriber::builder().with_max_level(Level::INFO).finish();tracing::subscriber::set_global_default(subscriber).expect("设置全局订阅者失败");let result = add_numbers(3, 5).instrument(span!(Level::INFO, "add_numbers_span"));info!("计算结果为: {}", result);
}fn add_numbers(a: i32, b: i32) -> i32 {let sum = a + b;sum
}
使用span!(Level::INFO, "add_numbers_span")
创建了一个INFO
级别的 Span,名称为add_numbers_span
。
然后通过instrument
方法将add_numbers
函数的执行与这个 Span 关联起来。当函数执行时,tracing
会记录这个 Span 的开始和结束时间等信息,帮助开发者更好地了解函数执行的上下文。运行这个程序会输出包含 Span 相关信息的日志,如 Span 的进入和退出记录。
在下一节中,我们将讨论如何分析程序生成的跟踪数据。
分析跟踪数据
一旦在Rust应用程序中实现了跟踪并生成了跟踪数据,下一步就是分析这些数据,以深入了解应用程序的行为。分析跟踪数据包括检查记录的事件,并使用它们来理解程序的执行流。这有帮于识别模式、发现异常,并了解应用程序的性能特征。Rust中有几个工具可用于分析跟踪数据。其中最流行的是 tracing-subscriber
,它提供了实现和配置订阅者的实用程序。
下面是如何使用跟踪订阅者来分析跟踪数据的一个基本示例:
use tracing_subscriber::FmtSubscriber;fn main() {let subscriber = FmtSubscriber::builder().with_max_level(tracing::Level::TRACE).finish();tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");// Your application code goes here...
}
在本例中,我们创建了FmtSubscriber,并将其设置为全局默认值。with_max_level函数用于设置订阅者将记录的事件的最大级别。在本例中,设置了最大日志级别为TRACE
。这意味着只有TRACE
级别及以上的日志消息才会被打印。一旦收集了跟踪数据,就可以使用各种工具对其进行可视化和解释。这可以帮助你了解应用程序的性能特征、识别瓶颈并发现潜在问题。
在下一节中,我们将探索Rust中的一些高级跟踪技术。
高级跟踪技术
随着您对Rust中的基本跟踪越来越熟悉,您可能会发现自己需要更高级的技术来诊断复杂问题或优化性能。Rust生态系统为高级跟踪提供了几个强大的工具和库。
其中一个这样的工具是tracking-futures,它是跟踪tracing包的扩展,提供了支持用诊断信息检测的Future。这在异步Rust程序中特别有用,在异步Rust程序中,理解future的行为对于调试和性能优化至关重要。
另一个有用的工具是trace-serde,它提供了一个序列化器实现,用于将tracing
的Id、Metadata、Event、Record和Span类型作为Serde Serializable类型。当你需要序列化跟踪数据以进行分析或传输时,这非常有用。
以下是一个更复杂一些的Rust tracing
示例,展示了在异步环境下如何使用tracing
以及如何对不同的模块或组件进行更细致的跟踪:
首先,在Cargo.toml
中添加必要的依赖:
[dependencies]
tracing = "0.1.37"
tracing-subscriber = "0.3.17"
tokio = { version = "1.34.0", features = ["full"] }
异步跟踪示例代码:
use tracing::{debug, error, info, instrument, span, Level};
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
use tokio::task;// 模拟一个异步操作,这里只是简单地休眠一段时间
async fn async_operation(name: &str) -> i32 {let sleep_duration = tokio::time::Duration::from_secs(2);tokio::time::sleep(sleep_duration).await;debug!("{} 异步操作完成", name);42
}// 一个函数,内部调用了异步操作,并进行跟踪
#[instrument(skip(inner_operation_name))]
async fn perform_operation(inner_operation_name: &str) -> i32 {let outer_span = span!(Level::INFO, "perform_operation_span");let _outer_guard = outer_span.enter();info!("开始执行 perform_operation");// 调用异步操作,并使用instrument进行跟踪let result = async_operation(inner_operation_name).instrument(span!(Level::DEBUG, "async_operation_span")).await;info!("perform_operation 执行结束");result
}#[tokio::main]
async fn main() {// 设置日志输出格式和过滤条件let subscriber = fmt::Subscriber::builder().with_env_filter(EnvFilter::from_default_env()).with_max_level(Level::DEBUG).finish();tracing::subscriber::set_global_default(subscriber).expect("设置全局订阅者失败");let operation_name = "重要操作";let result = perform_operation(operation_name).await;info!("最终结果: {}", result);// 模拟一个错误情况let error_span = span!(Level::ERROR, "error_span");let _error_guard = error_span.enter();error!("发生了一个错误");
}
-
异步操作的跟踪:
async_operation
函数模拟简单的异步操作,这里只是休眠一段时间然后返回固定值。在函数内部使用debug!
宏记录了异步操作完成的信息。当在
perform_operation
函数中调用async_operation
时,通过instrument
方法将其与一个名为async_operation_span
的DEBUG
级别的 Span 相关联。这样在执行异步操作时,tracing
会记录关于这个 Span 的相关信息,比如它的开始和结束时间等,有助于在异步环境下准确了解这个操作的执行情况。 -
函数执行的跟踪:
perform_operation
函数本身也被instrument
标记,创建了名为perform_operation_span
的INFO
级别的 Span。在函数内部,先记录了开始执行的信息,然后调用异步操作并等待其结果,最后记录了执行结束的信息。通过这种方式,可以清晰地看到整个函数从开始到结束的执行流程以及其中包含的异步操作的情况。在
Rust
中,instrument
宏主要用于为异步操作添加跟踪功能。它不会改变被包装函数(在这里是async_operation
)的返回值类型和实际返回的值。当async_operation
函数执行完成后,它原本返回的i32
类型的值(在这个例子中是42
)会被正常返回,然后赋值给result
变量。instrument
只是在异步操作执行的过程中,围绕这个操作创建一个Span
,用于记录诸如操作开始、结束等相关的跟踪信息。例如,在async_operation
函数内部返回42
这个值,通过instrument
包装后,这个42
依然会被正确地传递给result
变量,就好像instrument
不存在一样,从返回值的角度看,它是透明的。 -
主函数中的设置和操作:
在
main
函数中,首先设置了日志订阅者的格式和过滤条件。这里使用EnvFilter
根据环境变量来确定要过滤的日志级别,并且设置了最大日志级别为DEBUG
,这样可以看到更多详细的信息。然后调用perform_operation
函数并等待其结果,记录最终结果的信息。最后,为了演示错误情况的记录,创建了
ERROR
级别的error_span
,并在其中使用error!
宏记录了发生错误的信息。
运行这个程序,你会看到类似如下的输出(具体输出可能因环境和执行情况略有不同):
INFO [perform_operation_span] 开始执行 perform_operation
DEBUG [async_operation_span] 重要操作 异步操作完成
INFO [perform_operation_span] perform_operation 执行结束
INFO 最终结果: 42
ERROR [error_span] 发生了一个错误
通过这些输出,可以清晰地跟踪程序各个部分的执行情况,包括函数的调用、异步操作的执行以及错误的发生等,这对于调试和理解复杂的异步程序非常有帮助。
这些只是Rust中可用的高级跟踪技术的几个例子。随着你继续探索Rust生态系统,你将发现更多旨在帮助您充分利用跟踪的工具和库。编码快乐!🦀
相关文章:
Rust中Tracing 应用指南
欢迎来到这篇全面的Rust跟踪入门指南。Rust 的tracing是一个用于应用程序级别的诊断和调试的库。它提供了一种结构化的、异步感知的方式来记录日志和跟踪事件。与传统的日志记录相比,tracing能够更好地处理复杂的异步系统和分布式系统中的事件跟踪,帮助开…...
海外媒体发稿:根据您的要求编写二十个文案标题方法-华媒舍
本文旨在科普解读并描述标题中所包含的二十个爆款文案,为读者提供更深入的了解和知识。通过对每个标题进行拆解描述,我们将深入探讨各个文案标题的背后含义和吸引人之处。 1、"10个你不可忽视的秘密技巧,提升你的生活品质!&q…...
gitlab:使用脚本批量下载项目,实现全项目检索
目的 当需要知道gitlab中所有项目是否存在某段代码时,gitlab免费版只提供了当个项目内的检索,当项目过多时一个个查太过繁琐。下面通过 GitLab API 将指定 Group 下的所有项目克隆到本地。此脚本会自动获取项目列表并逐一克隆它们,再在本地进…...
macos 使用 nvm 管理 node 并自定义安装目录
系统环境:MacOS Version 参考文章: Github 地址:https://github.com/nvm-sh/nvm 安装的方式是很简单的,直接执行下面的命令即可: curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bas…...
网络编程第一课
0voice第一课 https://github.com/0voice 今日学习:网络通信IO 网络通信的核心是通过系统提供的socket套接字实现的。socket和c语言中文件操作的本质类似,在c语言中,通过fopen、fclose、fread、fwrite实现了对文件的操作,socket…...
玩转 Burp Suite (1)
内容预览 ≧∀≦ゞ 玩转 Burp Suite (1)声明Burp Suite 简介Dashboard(仪表盘)1. 默认任务管理2. 暂停任务3. 新建扫描任务4. 使用总结 Target(目标)1. SIte Map (站点地图)2. Scope(范围&#…...
【linux】(16)date命令
基本用法 date [OPTION]... [FORMAT]显示当前日期和时间 默认情况下,date 命令显示当前的日期和时间: date输出示例: Sun Jun 2 10:29:08 UTC 2024自定义日期和时间格式 可以使用 FORMAT 选项自定义输出格式。常用的格式选项包括&#…...
算法笔记:并查集
一、什么是并查集 并查集的逻辑结构是一个包含N个元素的集合,如图: 我们将各个元素划分为若干个互不相交的子集,如图: 二、并查集的基本操作 (一)初始化 初始化可以先将每个子集指向自己 //初始化int []…...
密码系统设计实验3-2
文章目录 《密码系统设计》实验实验项目实验三 密码模块实现4-6 学时实践要求(30 分) 《密码系统设计》实验 实验项目 实验序号实验名称实验学时数实验目的实验内容实验类型学生学习预期成果实验三密码模块实现6基于商用密码标准的密码模块的实现实现简…...
Spring Boot 与 Spring Cloud Alibaba 版本兼容对照
版本选择要点 Spring Boot 3.x 与 Spring Cloud Alibaba 2022.0.x Spring Boot 3.x 基于 Jakarta EE,javax.* 更换为 jakarta.*。 需要使用 Spring Cloud 2022.0.x 和 Spring Cloud Alibaba 2022.0.x。 Alibaba 2022.0.x 对 Spring Boot 3.x 的支持在其发行说明中…...
SVD 奇异值分解
SVD 是一种矩阵分解和降维的算法,通过分解矩阵找到奇异值,奇异值越大代表特征越重要。公式如下 A U Σ V T A U \Sigma V^T AUΣVT U : 左矩阵 ( m \times m ) Σ \Sigma Σ: 对角奇异值矩阵V:右矩阵( n \times n ) Sklearn 实现 S…...
C++设计模式-享元模式
动机(Motivation) 在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行时代价——主要指内存需求方面的代价。如何在避免大量细粒度对象问题的同时,让外部客户程序仍然能够透明地使用面向对象的方式来进行操作…...
AI加持,华为全屋智能品牌升级为“鸿蒙智家”
1.传统智能家居的困境:从便利到繁琐 近年来,智能家居因其便捷性和科技感受到消费者的青睐。然而,随着用户需求的多样化,传统智能家居的弊端逐渐显现: 设备连接复杂,品牌间兼容性不足,用户不得不…...
洛谷刷题之p1631
序列合并 题目入口 题目描述 有两个长度为 N N N 的单调不降序列 A , B A,B A,B,在 A , B A,B A,B 中各取一个数相加可以得到 N 2 N^2 N2 个和,求这 N 2 N^2 N2 个和中最小的 N N N 个。 输入格式 第一行一个正整数 N N N; 第二…...
uniapp前端开发,基于vue3,element plus组件库,以及axios通讯
简介 UniApp 是一个基于 Vue.js 的跨平台开发框架,旨在通过一次开发、编译后运行在多个平台上,如 iOS、Android、H5、以及小程序(微信小程序、支付宝小程序、百度小程序等)等。UniApp 为开发者提供了统一的开发体验,使…...
在Unity中实现物体动画的完整流程
在Unity中,动画是游戏开发中不可或缺的一部分。无论是2D还是3D游戏,动画都能为游戏增添生动的视觉效果。本文将详细介绍如何在Unity中为物体添加动画,包括资源的准备、播放组件的添加、动画控制器的创建以及动画片段的制作与调度。 1. 准备动…...
【云计算网络安全】解析 Amazon 安全服务:构建纵深防御设计最佳实践
文章目录 一、前言二、什么是“纵深安全防御”?三、为什么有必要采用纵深安全防御策略?四、以亚马逊云科技为案例了解纵深安全防御策略设计4.1 原始设计缺少安全策略4.2 外界围栏构建安全边界4.3 访问层安全设计4.4 实例层安全设计4.5 数据层安全设计4.6…...
【Andriod ADB基本命令总结】
笔者工作当中遇到安卓机器的数据访问和上传,特来简单总结一下常用命令。 1、ADB命令简介与安装 简介: ADB (Android Debug Bridge) 是一个强大的命令行工具,用于与 Android 设备进行交互,常用于开发、调试、测试以及设备管理等操作。它是 Android 开发工具包(SDK)的一部…...
ChatGPT如何辅助academic writing?
今天想和大家分享一篇来自《Nature》杂志的文章《Three ways ChatGPT helps me in my academic writing》,如果您的日常涉及到学术论文的写作(writing)、编辑(editing)或者审稿( peer review)&a…...
Day 27 贪心算法 part01
贪心算法其实就是没有什么规律可言,所以大家了解贪心算法 就了解它没有规律的本质就够了。 不用花心思去研究其规律, 没有思路就立刻看题解。 基本贪心的题目 有两个极端,要不就是特简单,要不就是死活想不出来。 学完贪心之后再去看动态规划,就会了解贪心和动规的区别。…...
使用Python实现目标追踪算法
引言 目标追踪是计算机视觉领域的一个重要任务,广泛应用于视频监控、自动驾驶、机器人导航、运动分析等多个领域。目标追踪的目标是在连续的视频帧中定位和跟踪感兴趣的物体。本文将详细介绍如何使用Python和OpenCV实现一个基本的目标追踪算法,并通过一…...
某科技研发公司培训开发体系设计项目成功案例纪实
某科技研发公司培训开发体系设计项目成功案例纪实 ——建立分层分类的培训体系,加强培训跟踪考核,促进培训成果实现 【客户行业】科技研发行业 【问题类型】培训开发体系 【客户背景】 某智能科技研发公司是一家专注于智能科技、计算机软件技术开发与…...
如何通过高效的缓存策略无缝加速湖仓查询
引言 本文将探讨如何利用开源项目 StarRocks 的缓存策略来加速湖仓查询,为企业提供更快速、更灵活的数据分析能力。作为 StarRocks 社区的主要贡献者和商业化公司,镜舟科技深度参与 StarRocks 项目开发,也为企业着手构建湖仓架构提供更多参考…...
Linux V4L2框架介绍
linux V4L2框架介绍 V4L2框架介绍 V4L2,全称Video for Linux 2,是Linux操作系统下用于视频数据采集设备的驱动框。它提供了一种标准化的方式使用户空间程序能够与视频设备进行通信和交互。通过V4L2接口,用户可以方便地实现视频图像数据的采…...
【前端】JavaScript 中 arguments、类数组与数组的深入解析
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 💯前言💯什么是 arguments 对象2.1 arguments 的定义2.2 arguments 的特性2.3 使用场景 💯深入了解 arguments 的结构3.1 arguments 的内部结构arguments 的关键属性…...
Android 布局菜单或按钮图标或Menu/Item设置可见和不可见
设置可见和不可见 即 设置 显示和隐藏;是双向设置;什么情况显示,什么情况隐藏分判断的条件 它不同于删除和屏蔽,删除和屏蔽,覆盖是单向的,不可逆转的。它间接等于单向的隐藏!!&…...
|| 与 ??的区别
?? : 空值合并运算符, 用于在左侧操作数为 null 或 undefined 时返回右侧操作数 let name null // null 或者 undefinedlet defaultName defaultNamelet displayName name ?? defaultNameconsole.log(displayName) // defaultName || : 逻辑或,…...
wordpress获取文章总数、分类总数、tag总数等
在制作wordpress模板的时候会要调用网站的文章总数分类总数tag总数等这个数值,如果直接用count查询数据库那就太过分了。好在wordpress内置了一些标签可以直接获取到这些数值,本文整理了一些常用的wordpress网站总数标签。 文章总数 <?php $count_…...
pytest 通过实例讲清单元测试、集成测试、测试覆盖率
1. 单元测试 概念 定义: 单元测试是对代码中最小功能单元的测试,通常是函数或类的方法。目标: 验证单个功能是否按照预期工作,而不依赖其他模块或外部资源。特点: 快速、独立,通常是开发者最先编写的测试。 示例:pytest 实现单…...
C#里怎么样自己实现10进制转换为二进制?
C#里怎么样自己实现10进制转换为二进制? 很多情况下,我们都是采用C#里类库来格式化输出二进制数。 如果有人要你自己手写一个10进制数转换为二进制数,并格式化输出, 就可以采用本文里的方法。 这里采用求模和除法来实现的。 下…...
哪做网站/百度推广登录平台官网
程序分目录管理 szz_aip:工程目录bin:可执行文件 start.pyconfig:配置文件 setting.pylib:工具类、初始化服务类、接口类 interface.py 接口 tools.py 工具logs:日志readme.txt:说明 setting.p…...
山西建筑网站设计设计/济南百度推广代理商
主要讲解了 MOS管子 运放 三极管的知识。...
巫山网站设计/内存优化大师
每日任务内容: 本次会议为第四次Scrum Meeting会议~由于本次会议女生今日因身体不适未参与会议,故在宿舍楼开会,大家集会15分钟。队员 昨日完成任务 明日要完成任务 刘乾 #130 学习python的单元测试,并撰写一个demo或者blog&…...
泉州模板建站平台/优化网站建设
标签(空格分隔): 三省吾身 原文地址:你应当怎样学习C(以及编程) 本人反思自己这些年在学校学得稀里糊涂半灌水。看到这篇文章,感觉收获不少。仿佛有指明自己道路的感觉,当然真正困难的还是坚持学习…...
怎样把自己做的网页放在网站里/如何让网站被百度收录
文章目录一、内存的基础知识1.1 什么是内存1.2 进程的运行原理1.2.1 指令1.2.2 逻辑地址和物理地址1.2.3 从写程序到程序运行1.2.4 装入模块装入内存1.3 三种装入方式1.3.1 绝对装入1.3.2 静态重定位1.3.3 动态重定位1.4 链接的三种方式1.5 总结二、内存管理的概念2.1 内存空间…...
自己做的个人网站无法备案/如何做好平台推广
1234567891011121314151617181920212223# K近邻,适用于小型数据集,是很好的基准模型,容易解释from sklearn.neighbors import KNeighborsClassifier# 线性模型,非常可靠的首选算法,适用于很大的数据集,也适…...