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

axum-insights

An Azure Application Insights exporter for axum via tracing.

Usage

This library is meant to be used as a layer for axum. It will automatically instrument your axum application, and send telemetry to Azure Application Insights. As the ecosystem matures, more features will be added.

Example

The following example is a "complete" example, which means that it includes all of the optional features of this library.

```rust use serde::{Serialize, Deserialize}; use axum::Router; use axuminsights::AppInsights; use axuminsights::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 { Some(self.message.clone()) }

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

}

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

let telemetrylayer = AppInsights::default() // Accepts an optional connection string. If None, then no telemetry is sent. .withconnectionstring(None) // Sets the service namespace and name. Default is empty. .withserviceconfig("namespace", "name") // Sets the HTTP client to use for sending telemetry. Default is reqwest async client. .withclient(reqwest::Client::new()) // Sets the sample rate for telemetry. Default is 1.0. .withsamplerate(1.0) // Sets the minimum level for telemetry. Default is INFO. .withminimumlevel(LevelFilter::INFO) // Sets the subscriber to use for telemetry. Default is a new subscriber. .withsubscriber(tracingsubscriber::registry()) // Sets the runtime to use for telemetry. Default is Tokio. .withruntime(opentelemetry::runtime::Tokio) // Sets whether or not to catch panics, and emit a trace for them. Default is false. .withcatchpanic(true) // Sets whether or not to make this telemetry layer a noop. Default is false. .withnoop(true) // Sets a function to extract extra fields from the request. Default is no extra fields. .withfieldmapper(|parts| { let mut map = HashMap::new(); map.insert("extrafield".toowned(), "extravalue".toowned()); map }) // Sets a function to extract extra fields from a panic. Default is a default error. .withpanicmapper(|panic| { (500, WebError { message: panic }) }) // Sets a function to determine the success-iness of a status. Default is (100 - 399 => true). .withsuccessfilter(|status| { status.issuccess() || status.isredirection() || status.isinformational() || status == http::StatusCode::NOTFOUND }) // Sets the common error type for the application, and will automatically extract information from handlers that return that error. .witherrortype::() .buildandsetglobaldefault() .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::{instrument, debug, error, info, warn};

// Instrument async handlers to get method-specific tracing.

[instrument]

async fn handler(Json(body): Json) -> Result { // Emit events using the tracing macros. debug!("Debug message"); info!("Info message"); warn!("Warn message"); error!("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() { // ... } ```

Acknowledgements

This library depends on individual efforts of other maintainers such as: * opentelemetry-application-insights by @frigus02. * appinsights-rs by @dmolokanov.

Test

bash cargo test --features web