欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Rust 語言的全鏈路追蹤庫 tracing使用方法

 更新時(shí)間:2022年12月28日 16:03:30   作者:達(dá)坦科技DatenLord  
這篇文章主要介紹了Rust 語言的全鏈路追蹤庫 tracing,接下來就以 tracing 為例,介紹一下trace 的核心概念以及使用方法,需要的朋友可以參考下

在一個(gè)應(yīng)用程序或庫的開發(fā)過程中,除了其本身的邏輯以外,開發(fā)人員還需要做很多額外的工作,以保證編寫的代碼可以正確的運(yùn)行,或者在出錯(cuò)時(shí)可以快速定位到錯(cuò)誤的位置以及原因,這就需要引入一些額外的工具,trace 就是其中特別好用的一種,下文我將會(huì)簡(jiǎn)單介紹 trace,并以 Rust 為例,演示 trace 在 Rust 中的使用方法。

可觀測(cè)性

Logs、Metrics 和 Traces 并稱為可觀測(cè)性三大支柱,通過分析它們輸出的數(shù)據(jù),開發(fā)人員能夠更好的觀測(cè)到系統(tǒng)的運(yùn)行狀況,更快的定位問題,從而提高系統(tǒng)的可靠性。

日志(Logs)

日志作為最常用的可觀測(cè)性數(shù)據(jù)源之一,相信多數(shù)開發(fā)者都比較熟悉。其本質(zhì)上就是一種帶有時(shí)間戳的離散事件記錄,通常用于記錄系統(tǒng)的運(yùn)行狀態(tài),日志的使用十分簡(jiǎn)單,只需要在代碼中需要報(bào)告信息的點(diǎn)添加一行代碼,就可以將這些信息輸出到控制臺(tái)或文件中,但是日志也有很大的缺點(diǎn),它的輸出是離散的,這意味著在記錄的時(shí)候,無法將日志信息相互關(guān)聯(lián),也無法知道日志信息的上下文,尤其是在多線程的環(huán)境下,最終輸出的信息比較混亂,不便于檢索和分析。

指標(biāo)(Metrics)

指標(biāo)是一種定量衡量,例如平均值、比率和百分比等。其值始終為數(shù)字而非文本,可以通過數(shù)學(xué)方法統(tǒng)計(jì)和分析,其主要用于描述系統(tǒng)運(yùn)行狀態(tài)的數(shù)據(jù),比如 CPU 的使用率、內(nèi)存的使用率、磁盤的使用率等,這些數(shù)據(jù)可以用來監(jiān)控系統(tǒng)的運(yùn)行狀態(tài),也可以用來預(yù)警。

追蹤(Traces)

追蹤是一種用于記錄系統(tǒng)中一次請(qǐng)求的完整生命周期的數(shù)據(jù),它可以記錄下一個(gè)請(qǐng)求從開始到結(jié)束的所有信息,包括請(qǐng)求的發(fā)起者、接收者、請(qǐng)求的路徑、請(qǐng)求的狀態(tài)、請(qǐng)求的耗時(shí)、請(qǐng)求的錯(cuò)誤信息等,這些信息可以用來分析系統(tǒng)的性能瓶頸,也可以用來分析系統(tǒng)的錯(cuò)誤。追蹤本質(zhì)上也是一種日志,他與日志的數(shù)據(jù)結(jié)構(gòu)十分相似,但是它能夠提供比日志更豐富的信息。特別是在分布式系統(tǒng)中,追蹤能夠跨越多個(gè)服務(wù),匯總出一次請(qǐng)求的完整信息,讓開發(fā)人員能夠更方便的找到系統(tǒng)中的問題。

Rust 中的 Trace

Rust 社區(qū)中比較有名的 trace 實(shí)現(xiàn)有三個(gè):

  • tracing 由 tokio 團(tuán)隊(duì)維護(hù),目前使用最廣泛,生態(tài)也比較完善
  • rustracing 使用人數(shù)相對(duì)較少
  • minitrace tikv 團(tuán)隊(duì)打造,性能最好

接下來就以 tracing 為例,介紹一下trace 的核心概念以及使用方法

Span

Span 可以說是 trace 中最關(guān)鍵的概念之一,它表示的是一個(gè)過程,也就是一段時(shí)間內(nèi)發(fā)生的所有事件的集合,其數(shù)據(jù)結(jié)構(gòu)中包含著 Span 的開始時(shí)間和結(jié)束時(shí)間,在分析數(shù)據(jù)是可以借助工具直觀的看到某次請(qǐng)求或操作的耗時(shí)情況。在同一個(gè) trace 流程中的所有 Span 都共享這相同的 Trace Id ,每個(gè) Span 也有著自己的 Span Id,并且 Span 還支持嵌套,嵌套的 Span 中也會(huì)保存著相應(yīng)的父子關(guān)系,最終可以靠這些信息,將請(qǐng)求的完整生命周期串聯(lián)起來,并且不會(huì)與相同時(shí)間段內(nèi)的其他請(qǐng)求產(chǎn)生干擾。

use tracing::{span, Level};
 
fn main() {
    let span = span!(Level::INFO, "span");
    let _enter = span.enter();
    // enter 后進(jìn)入該 span 的上下文
    // 可以記錄信息到 span 中
} // 離開作用域后,_enter 被 drop,對(duì)應(yīng)的 span 在此結(jié)束

以上代碼是創(chuàng)建并使用一個(gè) Span 最簡(jiǎn)單的方式,除此以外還有幾種不同的方式

#[instrument] // tracing 會(huì)為當(dāng)前函數(shù)自動(dòng)創(chuàng)建 span ,該 span 名與函數(shù)相同,并且整個(gè)函數(shù)都在該 span 的上下文內(nèi)
fn do_something() {
    // some event
    let span = span!(Level::INFO, "external function");
    span.in_scope(|| some_external_function()); //對(duì)于無法添加 #[instrument] 的外部函數(shù),也可以使用 in_scope 方法讓其在 span 的上下文中執(zhí)行
}
 
#[instrument] // 此方法同樣對(duì)異步函數(shù)適用
async fn do_something_async() {
    let future = async {
        // some async code
    };
    let span = span!(Level::INFO, "future");
    future.instrument(span).await; // 也可以在 future .await 之前將 span 附加給 future
}
 
// async 代碼中要避免以下情況
async fn some_async_code() {
    let span = span!(Level::INFO, "span");
    let _enter = span.enter();
    // 此處進(jìn)入 span 的上下文,直到 _enter 被 drop 后才會(huì)結(jié)束
    async_fn().await; // .await 時(shí),task 可能會(huì)讓出當(dāng)前線程的執(zhí)行權(quán),而此時(shí) _enter 還沒有 drop,因此可能會(huì)錯(cuò)誤的記錄到其他 task 的 enent.
}

Event

Event 與日志類似,表示的是某一個(gè)時(shí)間點(diǎn)發(fā)生的事件,但與日志不同的是,Event 可以將信息記錄到 Span 的上下文中,這樣在分析數(shù)據(jù)時(shí),可以直接查看 Span 中發(fā)生的所有事件。

use tracing::{event, info, span, Level};
 
fn main() {
    event!(Level::INFO, "event"); // 在 span 的上下文之外記錄一個(gè) Leval 為 INFO 的 event
 
    let span = span!(Level::INFO, "span");
    let _enter = span.enter();
 
    event!(Level::INFO, "event"); // 在 span 的上下文內(nèi)記錄 event
 
    info!("something with info level"); // 也可以使用和 log 相同的形式記錄 event
}

Collector

以上的示例不會(huì)有任何可見的輸出,因?yàn)槲覀冞€沒有配置 Collector,tracing 中所有的 Span 和 Event 都是通過 Collector 來收集的,Collector 會(huì)將 Span 和 Event 以一定的格式輸出到指定的地方,比如 stdout、stderr、文件、網(wǎng)絡(luò)等。tracing-subscriber 的 fmt 模塊提供了一個(gè) Collector ,可以方便的輸出事件信息。

use tracing::info;
use tracing_subscriber;
 
fn main() {
    // 初始化全局 Collector
    tracing_subscriber::fmt::init();
 
    info!("Hello, world!");
}

運(yùn)行上面這段代碼,可以在終端中看到一條 INFO 級(jí)別的事件,如果需要將 Trace 信息發(fā)送到其他地方,就要用到其他的 Collector 實(shí)現(xiàn),比如 tracing-appender 這個(gè) crate,可以將 Trace 信息輸出到文件中。

在 Rust 中使用

tracing 的完整示例

use std::{thread::sleep, time::Duration};
 
use tracing::{debug, info, info_span, instrument};
 
#[instrument]
fn expensive_work(secs: u64) {
    debug!("doing expensive work");
    sleep(Duration::from_secs(secs));
    debug!("done with expensive work");
}
 
fn main() {
    tracing_subscriber::fmt()
        // enable everything
        .with_max_level(tracing::Level::TRACE)
        // sets this to be the default, global collector for this application.
        .init();
    let span = info_span!("root");
    let _enter = span.enter();
 
    info!("some info in the root span");
 
    expensive_work(1);
}

運(yùn)行以上代碼將會(huì)的到以下輸出

2022-12-01T02:50:59.425475Z  INFO root: tracing_example: some info in the root span
2022-12-01T02:50:59.425518Z DEBUG root:expensive_work{secs=1}: tracing_example: doing expensive work
2022-12-01T02:51:00.425722Z DEBUG root:expensive_work{secs=1}: tracing_example: done with expensive work

每個(gè)事件都已相同的格式輸出,此輸出模式下,與 log 的輸出十分相似,

但 tracing 輸出的內(nèi)容多出了 Span 相關(guān)的信息。由 instrument 生成的 Span 還自動(dòng)添加了函數(shù)的參數(shù)信息。下面介紹的 OpenTelemetry 和 Jaeger,還可以讓我們更加直觀的查看 Span 之間的時(shí)間關(guān)系。

Trace 的標(biāo)準(zhǔn)化

想要讓 Trace 跨越多個(gè)服務(wù),集成到多種不同的語言,那就必須要規(guī)定大家相互調(diào)用的規(guī)范,要遵守一套相同的協(xié)議,才能讓 Trace 的數(shù)據(jù)在不同的系統(tǒng)中都能夠正常傳遞,Trace 早期誕生了兩種規(guī)范,分別是 OpenTracing 和 OpenCensus,后來為了規(guī)范的統(tǒng)一,OpenTracing 和 OpenCensus 合并成了 OpenTelemetry,現(xiàn)在已經(jīng)成為了 Trace 的事實(shí)標(biāo)準(zhǔn)。OpenTelemetry 提供了不同語言的 SDK,可以方便的集成到不同的系統(tǒng)中,對(duì)于 Rust ,它提供了一系列相關(guān)的 crate 用于集成。tracing 也提供了 tracing-OpenTelemetry 用來將其收集到的信息發(fā)送到兼容 OpenTelemetry 的分布式追蹤系統(tǒng)中。

Trace 數(shù)據(jù)的可視化分析

Jaeger 是受到 Dapper 和 OpenZipkin 啟發(fā)的開源分布式跟蹤系統(tǒng),由 Uber 開發(fā),現(xiàn)已捐贈(zèng)給 CNCF。Jaeger 通過收集 Trace 數(shù)據(jù),將其可視化展示,方便開發(fā)者分析系統(tǒng)的問題。下圖為 Jaeger 部署的示例。

要將 Trace 數(shù)據(jù)發(fā)送給 Jaeger,需要在我們的應(yīng)用中添加 jaeger-client 。OpenTelemetry 提供的 crate 中,就包括了響應(yīng)的 jaeger-clinet 實(shí)現(xiàn): opentelemetry-jaeger。它會(huì)將 Span 信息以 UDP 包的形式發(fā)送到 jaeger-agent,jaeger-agent 將一段時(shí)間內(nèi)的數(shù)據(jù)打包分批發(fā)送到 jaeger-collector,再由 jaeger-collector 把數(shù)據(jù)存入數(shù)據(jù)庫內(nèi),我們?cè)?jaeger 的 UI 中就可以查詢到這些數(shù)據(jù)。

OpenTelemetry 的倉庫中也提供了以上流程的示例,我們可以直接運(yùn)行這個(gè)示例,然后在 jaeger 的前端我們就可以得到下圖的內(nèi)容:

有了這些數(shù)據(jù),開發(fā)人員就能夠快速定位到請(qǐng)求的主要耗時(shí)部分,也能夠通過其中包含的事件獲取到請(qǐng)求內(nèi)的消息記錄。

總結(jié)

對(duì)于大多數(shù)同步程序,用 Log 就能夠滿足需求,并且使用起來也足夠簡(jiǎn)單,但是一旦涉及到異步程序或其他的一些復(fù)雜情況,Log 就會(huì)變得不那么好用了,一段時(shí)間內(nèi)的 Log 信息可能來自于多個(gè)不同的處理流程,難以快速方便的獲取我們需要的信息,而 Trace 則能夠很好的解決這個(gè)問題。

到此這篇關(guān)于Rust 語言的全鏈路追蹤庫 tracing的文章就介紹到這了,更多相關(guān)Rust 全鏈路追蹤庫 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • rust中間件actix_web在項(xiàng)目中的使用實(shí)戰(zhàn)

    rust中間件actix_web在項(xiàng)目中的使用實(shí)戰(zhàn)

    這篇文章主要介紹了rust中間件在項(xiàng)目中的使用實(shí)戰(zhàn),包括自定義中間件,日志中間件,Default?headers,用戶會(huì)話,錯(cuò)誤處理的用法實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • 詳解Rust調(diào)用tree-sitter支持自定義語言解析

    詳解Rust調(diào)用tree-sitter支持自定義語言解析

    使用Rust語言結(jié)合tree-sitter庫解析自定義語言需要定義語法、生成C解析器,并在Rust項(xiàng)目中集成,具體步驟包括創(chuàng)建grammar.js定義語法,使用tree-sitter-cli工具生成C解析器,以及在Rust項(xiàng)目中編寫代碼調(diào)用解析器,這一過程涉及到對(duì)tree-sitter的深入理解和Rust語言的應(yīng)用技巧
    2024-09-09
  • Rust數(shù)據(jù)類型之結(jié)構(gòu)體Struct的使用

    Rust數(shù)據(jù)類型之結(jié)構(gòu)體Struct的使用

    結(jié)構(gòu)體是Rust中非常強(qiáng)大和靈活的數(shù)據(jù)結(jié)構(gòu),可以用于組織和操作各種類型的數(shù)據(jù),本文就來介紹一下Rust數(shù)據(jù)類型之結(jié)構(gòu)體Struct的使用,感興趣的可以了解一下
    2023-12-12
  • Rust語言之trait中的個(gè)方法可以重寫嗎

    Rust語言之trait中的個(gè)方法可以重寫嗎

    在Rust中,trait定義了一組方法,這些方法可以被一個(gè)或多個(gè)類型實(shí)現(xiàn),當(dāng)你為某個(gè)類型實(shí)現(xiàn)一個(gè)trait時(shí),你可以為該trait中的每個(gè)方法提供自己的具體實(shí)現(xiàn),本文將給大家介紹一下trait中的個(gè)方法是否可以重寫,需要的朋友可以參考下
    2023-10-10
  • rust聲明式宏的實(shí)現(xiàn)

    rust聲明式宏的實(shí)現(xiàn)

    聲明式宏使得你能夠?qū)懗鲱愃?match?表達(dá)式的東西,來操作你所提供的?Rust代碼,它使用你提供的代碼來生成用于替換宏調(diào)用的代碼,感興趣的可以了解一下
    2023-12-12
  • 詳解Rust中的所有權(quán)機(jī)制

    詳解Rust中的所有權(quán)機(jī)制

    Rust?語言提供了跟其他系統(tǒng)編程語言相同的方式來控制你使用的內(nèi)存,但擁有數(shù)據(jù)所有者在離開作用域后自動(dòng)清除其數(shù)據(jù)的功能意味著你無須額外編寫和調(diào)試相關(guān)的控制代碼,這篇文章主要介紹了Rust中的所有權(quán)機(jī)制,需要的朋友可以參考下
    2022-10-10
  • Rust語言之Copy和Clone詳解

    Rust語言之Copy和Clone詳解

    在 Rust 中,Copy 和 Clone trait 用于控制類型的復(fù)制行為。它們?cè)试S你定義如何復(fù)制類型的值,以及在什么情況下可以復(fù)制。本文將詳細(xì)介紹這兩個(gè) trait 的作用和用法,并通過代碼示例來展示它們的使用,需要的朋友可以參考下
    2023-05-05
  • Rust中vector的詳細(xì)用法

    Rust中vector的詳細(xì)用法

    Rust和C++同樣也有vector概念,本文主要介紹了Rust中vector的詳細(xì)用法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-03-03
  • RUST異步流處理方法詳細(xì)講解

    RUST異步流處理方法詳細(xì)講解

    這篇文章主要介紹了RUST異步流處理方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-12-12
  • 一文掌握Rust編程中的生命周期

    一文掌握Rust編程中的生命周期

    在Rust語言中, 每一個(gè)引用都有其生命周期, 通俗講就是每個(gè)引用在程序執(zhí)行的過程中都有其自身的作用域, 一旦離開其作用域, 其生命周期也宣告結(jié)束, 值不再有效,這篇文章主要介紹了Rust編程中的生命周期,需要的朋友可以參考下
    2023-11-11

最新評(píng)論