MA

maple-rust-style

Provides boilerplate and configuration for integrating OpenTelemetry into Rust-based services.

Install

mkdir -p .claude/skills/maple-rust-style && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/11447" && unzip -o skill.zip -d .claude/skills/maple-rust-style && rm skill.zip

Installs to .claude/skills/maple-rust-style

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Rust OpenTelemetry style for Maple: opentelemetry + opentelemetry_sdk + opentelemetry-otlp HTTP exporter, tracing-opentelemetry bridge for the tracing crate, inline endpoint + ingest key, semconv resource attributes.
216 charsno explicit “when” trigger
Advanced

Key capabilities

  • →Configure OpenTelemetry for Rust applications
  • →Export traces, logs, and metrics via OTLP HTTP
  • →Bridge `tracing` crate calls to OpenTelemetry
  • →Set resource attributes using semantic conventions
  • →Handle endpoint and ingest key for Maple

How it works

The skill bootstraps OpenTelemetry SDK components for traces, logs, and metrics, configuring them to export via OTLP HTTP to a specified Maple endpoint using an ingest key, and integrates with the `tracing` crate.

Inputs & outputs

You give it
Rust application code, Maple endpoint, Maple ingest key, DEPLOYMENT_ENV, GITHUB_SHA
You get back
Initialized OpenTelemetry tracer, logger, and meter providers, configured tracing subscriber

When to use maple-rust-style

  • →Setup observability
  • →Configure trace exporters
  • →Instrument rust code

About this skill

Maple Rust style

Use the official opentelemetry + opentelemetry_sdk crates with opentelemetry-otlp (HTTP exporter, not gRPC). Bridge the tracing crate: tracing-opentelemetry turns tracing spans into OTel spans, and opentelemetry-appender-tracing turns info! / error! events into OTLP log records.

Cargo.toml

[dependencies]
opentelemetry = "0.32"
opentelemetry_sdk = { version = "0.32", features = ["trace", "logs", "metrics"] }
opentelemetry-otlp = { version = "0.32", features = ["http-proto", "reqwest-blocking-client", "reqwest-rustls", "trace", "logs", "metrics"] }
opentelemetry-appender-tracing = "0.32"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tracing-opentelemetry = "0.33"

Keep the opentelemetry* crates on one minor version, and pair tracing-opentelemetry with the release built for it (0.33 for 0.32). The builder-default batch processors export from their own thread, so use the blocking reqwest client. The async reqwest-client panics there with "there is no reactor running". reqwest-rustls is required for HTTPS: opentelemetry-otlp builds reqwest without default TLS.

Bootstrap

Inline the endpoint and ingest key. The key is a project-scoped, write-only token (shaped like a Sentry DSN).

use opentelemetry::{global, trace::TracerProvider as _, KeyValue};
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
use opentelemetry_otlp::{
    ExporterBuildError, LogExporter, MetricExporter, Protocol, SpanExporter, WithExportConfig,
    WithHttpConfig,
};
use opentelemetry_sdk::{
    logs::SdkLoggerProvider, metrics::SdkMeterProvider, trace::SdkTracerProvider, Resource,
};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

const MAPLE_ENDPOINT: &str = "https://ingest.maple.dev"; // EU: https://ingest.eu.maple.dev
const MAPLE_KEY: &str = "MAPLE_TEST"; // public ingest key (maple_pk_…), or MAPLE_TEST until the user has one

pub fn init() -> Result<(SdkTracerProvider, SdkLoggerProvider, SdkMeterProvider), ExporterBuildError> {
    let auth = format!("Bearer {MAPLE_KEY}");
    let mut headers = std::collections::HashMap::new();
    headers.insert("authorization".to_string(), auth);

    let resource = Resource::builder()
        .with_service_name("orders-api")
        .with_attributes([
            KeyValue::new("deployment.environment.name", std::env::var("DEPLOYMENT_ENV").unwrap_or_else(|_| "development".into())),
            KeyValue::new("vcs.repository.url.full", "https://github.com/acme/orders-api"),
            KeyValue::new("vcs.ref.head.revision", std::env::var("GITHUB_SHA").unwrap_or_default()),
        ])
        .build();

    let trace_exporter = SpanExporter::builder()
        .with_http()
        .with_endpoint(format!("{MAPLE_ENDPOINT}/v1/traces"))
        .with_headers(headers.clone())
        .with_protocol(Protocol::HttpBinary)
        .build()?;
    let tracer_provider = SdkTracerProvider::builder()
        .with_batch_exporter(trace_exporter)
        .with_resource(resource.clone())
        .build();
    global::set_tracer_provider(tracer_provider.clone());

    let log_exporter = LogExporter::builder()
        .with_http()
        .with_endpoint(format!("{MAPLE_ENDPOINT}/v1/logs"))
        .with_headers(headers.clone())
        .with_protocol(Protocol::HttpBinary)
        .build()?;
    let logger_provider = SdkLoggerProvider::builder()
        .with_batch_exporter(log_exporter)
        .with_resource(resource.clone())
        .build();

    let metric_exporter = MetricExporter::builder()
        .with_http()
        .with_endpoint(format!("{MAPLE_ENDPOINT}/v1/metrics"))
        .with_headers(headers)
        .with_protocol(Protocol::HttpBinary)
        .build()?;
    let meter_provider = SdkMeterProvider::builder()
        .with_periodic_exporter(metric_exporter)
        .with_resource(resource)
        .build();
    global::set_meter_provider(meter_provider.clone());

    let otel_layer = tracing_opentelemetry::layer().with_tracer(tracer_provider.tracer("orders.api"));
    let otel_log_layer = OpenTelemetryTracingBridge::new(&logger_provider);

    tracing_subscriber::registry()
        .with(tracing_subscriber::EnvFilter::from_default_env())
        .with(tracing_subscriber::fmt::layer())
        .with(otel_layer)
        .with(otel_log_layer)
        .init();

    Ok((tracer_provider, logger_provider, meter_provider))
}

Call from main and shut down on exit:

#[tokio::main]
async fn main() {
    // A telemetry setup error is logged, never fatal: the app runs without export.
    let providers = telemetry::init()
        .inspect_err(|err| eprintln!("telemetry disabled: {err}"))
        .ok();

    // app run …

    if let Some((tracer_provider, logger_provider, meter_provider)) = providers {
        let _ = tracer_provider.shutdown();
        let _ = logger_provider.shutdown();
        let _ = meter_provider.shutdown();
    }
}

Bounded business spans via tracing

Bridging tracing keeps existing instrumentation unchanged. Use #[tracing::instrument] on bounded async operations:

#[tracing::instrument(name = "order.submit", skip_all, err, fields(order.id = %order_id))]
async fn submit_order(order_id: &str) -> Result<(), Error> {
    charge_order(order_id).await?;
    Ok(())
}

Add err to #[instrument]. An Err return then emits an event with an error field, which tracing-opentelemetry records as an exception event and span status Error (both on by default).

Coexistence

If the project already uses tracing with a Honeycomb, Datadog, or Jaeger layer, leave it in place and add Maple's layers alongside. Do not strip the existing exporter unless the user asks.

When not to use it

  • →When using gRPC exporter for OpenTelemetry
  • →When the user does not want to use `tracing` crate
  • →When the user does not want to use Maple's observability platform

Limitations

  • →Uses HTTP exporter, not gRPC
  • →Assumes Maple endpoint and ingest key
  • →Requires `tracing` crate for existing instrumentation

How it compares

This skill provides a standardized, opinionated configuration for OpenTelemetry in Rust applications for Maple, automating the setup of exporters, resource attributes, and `tracing` integration, which would otherwise require manual configur

Compared to similar skills

maple-rust-style side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
maple-rust-style (this skill)04moReviewAdvanced
mcp09moReviewAdvanced
rust-async-patterns114moReviewIntermediate
debug-lldb19moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

Search skills

Search the agent skills registry