alibabacloud-rum 0.1.0

Alibaba Cloud RUM SDK for native Rust applications.
Documentation

Alibaba Cloud RUM Rust SDK

Crates.io Documentation

alibabacloud-rum is the Alibaba Cloud RUM SDK for native Rust applications. It is currently focused on Android native Rust processes and reqwest based HTTP clients.

The SDK can initialize a RUM session, emit an initial view event, instrument outbound HTTP requests, inject trace headers, collect resource timing data, and flush RUM payloads to an Alibaba Cloud RUM collector.

Crate

Add the SDK to your application:

[dependencies]
alibabacloud-rum = "0.1.0"
reqwest = { version = "0.12.28", default-features = false, features = ["rustls-tls"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

The default feature set enables reqwest instrumentation. Disable default features when you only need manual custom event/resource reporting:

[dependencies]
alibabacloud-rum = { version = "0.1.0", default-features = false }

Requirements

  • Rust 1.86 or newer.
  • An async runtime compatible with tokio.
  • A RUM collector address and app id from Alibaba Cloud RUM.
  • For Android builds, install the matching Rust target, for example aarch64-linux-android for arm64-v8a devices or emulators.

Android native Rust integrations should prefer rustls TLS, as shown in the dependency example above.

Quick Start

Initialize the SDK once and wrap your reqwest::Client:

use std::time::Duration;

use alibabacloud_rum::{RumConfig, RumEnv};

#[tokio::main]
async fn main() -> alibabacloud_rum::Result<()> {
    let config = RumConfig::builder()
        .config_address("https://your-project.cn-hangzhou.log.aliyuncs.com/rum/web/v2")
        .app_id("your-app-id")
        .app_name("my-rust-app")
        .app_version("1.0.0")
        .env(RumEnv::Prod)
        .utdid("device-id")
        .user_id("user-id")
        .exporter(|exporter| {
            exporter
                .flush_interval(Duration::from_secs(5))
                .max_batch_size(20)
        })
        .build()?;

    alibabacloud_rum::init_as_global(config).await?;

    let client = alibabacloud_rum::wrap_reqwest(reqwest::Client::new())?;
    let response = client
        .get("https://api.example.com/users/123")
        .send()
        .await?;

    println!("status: {}", response.status());
    let _body = response.bytes().await?;

    alibabacloud_rum::flush().await?;
    alibabacloud_rum::shutdown().await?;
    Ok(())
}

For non-global initialization, use Rum::init(config).await? and call rum.wrap_reqwest(reqwest::Client::new())?.

reqwest Instrumentation

With the reqwest feature enabled, the wrapper supports common request builder methods such as get, post, put, patch, delete, header, headers, query, json, form, body, timeout, basic_auth, and bearer_auth.

The wrapper records a resource event when the response body is consumed through bytes, text, json, or when the wrapped response is dropped. It also injects outbound trace headers unless tracing is disabled or the target host is excluded.

let client = alibabacloud_rum::wrap_reqwest(reqwest::Client::new())?;

let response = client
    .post("https://api.example.com/orders")
    .json(&serde_json::json!({ "sku": "123" }))
    .send()
    .await?;

let body = response.text().await?;

Custom Events

Use the global helpers or the methods on a Rum instance to report custom events, logs, exceptions, and manually measured resources.

use alibabacloud_rum::{
    CustomEvent, CustomException, CustomLog, CustomLogLevel, CustomResource,
    CustomResourceMeasuring, CustomResourceType, TraceContext, TraceProtocol,
};

alibabacloud_rum::report_custom_event(
    CustomEvent::new("biz", "checkout")?
        .group("order")
        .value(1.0)?
        .extra("sku", "123")?,
)
.await?;

alibabacloud_rum::report_custom_log(
    CustomLog::new("biz", "payment")?
        .level(CustomLogLevel::Warn)
        .content("slow payment")
        .extra("order_id", "1")?,
)
.await?;

alibabacloud_rum::report_custom_exception(
    CustomException::new("Panic", "index out of bounds")?
        .source("event")
        .file("main.rs")
        .stack("stack line 1\nstack line 2"),
)
.await?;

let trace = TraceContext::generate(TraceProtocol::TraceParent);

alibabacloud_rum::report_custom_resource(
    CustomResource::new("https://api.example.com/orders/1", "GET")?
        .resource_type(CustomResourceType::Fetch)
        .status_code(200)
        .success(true)
        .measuring(CustomResourceMeasuring {
            duration_ms: 120,
            size_bytes: 2048,
            connect_duration_ms: 10,
            ssl_duration_ms: 20,
            dns_duration_ms: 5,
            redirect_duration_ms: 0,
            first_byte_duration_ms: 45,
            download_duration_ms: 40,
        })
        .trace_context(trace),
)
.await?;

Configuration

RumConfig::builder() requires config_address and app_id. Other fields are optional:

  • Application: app_name, app_version, app_type, env.
  • Device and user: utdid, user_id, user_name, user_tags, device_name, device_model, device_brand, device_type.
  • Platform: os_type, os_version, net_device_model.
  • Extra payload properties: property(key, value).
  • Exporter: flush_interval, max_batch_size, max_queue_size, request_timeout, cache_path.
  • Network: enabled, record_enabled, tracing_enabled, trace_parent, sw8, exclude_host, should_record_request, should_trace_request.

The collector host is excluded from network tracing automatically to avoid self-reporting loops.

Trace Propagation

The default propagation mode is W3C Trace Context. It injects:

  • traceparent
  • tracestate

Switch to Alibaba Cloud/SkyWalking SW8 propagation when your backend expects sw8:

let config = RumConfig::builder()
    .config_address("https://your-project.cn-hangzhou.log.aliyuncs.com/rum/web/v2")
    .app_id("your-app-id")
    .network(|network| network.sw8())
    .build()?;

For manual resources, use TraceContext and TraceHeaderWriter to generate headers for your own business request.

Examples

Run the reqwest example against local mock services:

cargo run --example reqwest_poc --features reqwest

Run it against a real collector and a real target API:

RUM_CONFIG_ADDRESS="https://your-project.cn-hangzhou.log.aliyuncs.com/rum/web/v2" \
RUM_APP_ID="your-app-id" \
RUM_TARGET_URL="https://api.example.com/users/123" \
cargo run --example reqwest_poc --features reqwest

Run the custom event/resource example:

cargo run --example custom_poc

Use SW8 propagation in either example:

RUM_TRACE_MODE=sw8 cargo run --example reqwest_poc --features reqwest
RUM_TRACE_MODE=sw8 cargo run --example custom_poc

Android Verification

For an arm64-v8a device or emulator:

rustup target add aarch64-linux-android

export NDK="$ANDROID_HOME/ndk/26.3.11579264"
export NDK_BIN="$NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin"

CC_aarch64_linux_android="$NDK_BIN/aarch64-linux-android34-clang" \
AR_aarch64_linux_android="$NDK_BIN/llvm-ar" \
CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="$NDK_BIN/aarch64-linux-android34-clang" \
cargo build --release --examples --features reqwest --target aarch64-linux-android

Push and run an example:

adb push target/aarch64-linux-android/release/examples/reqwest_poc /data/local/tmp/reqwest_poc
adb shell chmod 755 /data/local/tmp/reqwest_poc
adb shell 'RUM_CONFIG_ADDRESS="https://your-project.cn-hangzhou.log.aliyuncs.com/rum/web/v2" RUM_APP_ID="your-app-id" RUM_TARGET_URL="https://api.example.com/users/123" /data/local/tmp/reqwest_poc'

For a standalone Android rlib consumer demo, see demos/android-rlib-consumer/README.md.

Features

Feature Default Description
reqwest Yes Enables reqwest client wrapping, trace header injection, and resource event capture.

Public API

The main exported types and functions are:

  • Rum, RumConfig, RumConfigBuilder, RumEnv
  • init_as_global, global, flush, shutdown
  • wrap_reqwest, RumReqwestClient, RumRequestBuilder, RumReqwestResponse
  • CustomEvent, CustomLog, CustomLogLevel, CustomException
  • CustomResource, CustomResourceMeasuring, CustomResourceType
  • report_custom_event, report_custom_log, report_custom_exception, report_custom_resource
  • TraceContext, TraceProtocol, TraceGenerator, TraceHeaderWriter

Development

Common checks:

cargo fmt
cargo test --no-default-features
cargo test
cargo run --example custom_poc

The previous long-form project notes and Android troubleshooting guide were moved to CONTRIBUTING.md.

Resources