#insight #applications #axum #tracing #appinsights

axum-insights

通过跟踪实现 Azure 应用程序洞察的 axum 导出器

9 个版本

0.4.0 2024年8月9日
0.3.2 2023年10月25日
0.2.3 2023年9月1日
0.1.0 2023年8月30日

#681 in 网页编程

Download history 1/week @ 2024-04-29 1/week @ 2024-05-27 1/week @ 2024-06-03 8/week @ 2024-06-10 105/week @ 2024-08-05 32/week @ 2024-08-12

137 每月下载量
rtz 中使用

MIT 许可证

62KB
770

Build and Test codecov Version Crates.io Documentation Rust License:MIT

axum-insights

通过 axumtracing 实现的 Azure 应用程序洞察 导出器。

用法

此库旨在作为 axum 的层使用。它将自动对您的 axum 应用程序进行仪器化,并将遥测数据发送到 Azure 应用程序洞察。随着生态系统的成熟,将添加更多功能。

示例

以下示例是一个 "完整" 示例,这意味着它包括此库的所有可选功能。

use serde::{Serialize, Deserialize};
use axum::Router;
use axum_insights::AppInsights;
use axum_insights::AppInsightsError;
use tracing_subscriber::filter::LevelFilter;
use std::collections::HashMap;
use tracing::Instrument;

// Define some helper types for the example.

#[derive(Default, Serialize, Deserialize, Clone)]
struct WebError {
    message: String,
}

impl AppInsightsError for WebError {
    fn message(&self) -> Option<String> {
        Some(self.message.clone())
    }

    fn backtrace(&self) -> Option<String> {
        None
    }
}

// Set up the exporter, and get the `tower::Service` layer.

let telemetry_layer = AppInsights::default()
    // Accepts an optional connection string.  If None, then no telemetry is sent.
    .with_connection_string(None)
    // Sets the service namespace and name.  Default is empty.
    .with_service_config("namespace", "name")
    // Sets the HTTP client to use for sending telemetry.  Default is reqwest async client.
    .with_client(reqwest::Client::new())
    // Sets whether or not live metrics are collected.  Default is false.
    .with_live_metrics(true)
    // Sets the sample rate for telemetry.  Default is 1.0.
    .with_sample_rate(1.0)
    // Sets the minimum level for telemetry.  Default is INFO.
    .with_minimum_level(LevelFilter::INFO)
    // Sets the subscriber to use for telemetry.  Default is a new subscriber.
    .with_subscriber(tracing_subscriber::registry())
    // Sets the runtime to use for telemetry.  Default is Tokio.
    .with_runtime(opentelemetry_sdk::runtime::Tokio)
    // Sets whether or not to catch panics, and emit a trace for them.  Default is false.
    .with_catch_panic(true)
    // Sets whether or not to make this telemetry layer a noop.  Default is false.
    .with_noop(true)
    // Sets a function to extract extra fields from the request.  Default is no extra fields.
    .with_field_mapper(|parts| {
        let mut map = HashMap::new();
        map.insert("extra_field".to_owned(), "extra_value".to_owned());
        map
    })
    // Sets a function to extract extra fields from a panic.  Default is a default error.
    .with_panic_mapper(|panic| {
        (500, WebError { message: panic })
    })
    // Sets a function to determine the success-iness of a status.  Default is (100 - 399 => true).
    .with_success_filter(|status| {
        status.is_success() || status.is_redirection() || status.is_informational() || status == http::StatusCode::NOT_FOUND
    })
    // Sets the common error type for the application, and will automatically extract information from handlers that return that error.
    .with_error_type::<WebError>()
    .build_and_set_global_default()
    .unwrap()
    .layer();

// Add the layer to your app.

// You likely will not need to specify `Router<()>` in your implementation.  This is just for the example.
let app: Router<()> = Router::new()
    // ...
    .layer(telemetry_layer);

// Then, in a handler, you would use the `tracing` macros to emit telemetry.

use axum::response::IntoResponse;
use axum::Json;
use tracing::{Level, instrument, debug, error, info, warn, event};

// Instrument async handlers to get method-specific tracing.
#[instrument]
async fn handler(Json(body): Json<String>) -> Result<impl IntoResponse, WebError> {
    // Emit events using the `tracing` macros.
    debug!("Debug message");
    info!("Info message");
    warn!("Warn message");
    error!("Error message");
    event!(name: "exception", Level::ERROR, exception.message = "error message");

    // Create new spans using the `tracing` macros.
    let span = tracing::info_span!("DB Query");
    
    db_query().instrument(span).await;
    
    if body == "error" {
        return Err(WebError { message: "Error".to_owned() });
    }

    Ok(())
}

async fn db_query() {
    // ...
}

致谢

此库依赖于其他维护者的个人努力,例如

测试

cargo test --features web

依赖项

~14–45MB
~719K SLoC