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.zipInstalls 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.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
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.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| maple-rust-style (this skill) | 0 | 4mo | Review | Advanced |
| mcp | 0 | 9mo | Review | Advanced |
| rust-async-patterns | 11 | 4mo | Review | Intermediate |
| debug-lldb | 1 | 9mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
mcp
Piebald-AI
Guide for working with Splitrail's MCP server. Use when adding tools, resources, or modifying the MCP interface.
rust-async-patterns
wshobson
Master Rust async programming with Tokio, async traits, error handling, and concurrent patterns. Use when building async Rust applications, implementing concurrent systems, or debugging async code.
debug-lldb
regenrek
Capture and analyze thread backtraces with LLDB/GDB to debug hangs, deadlocks, UI freezes, IPC stalls, or high-CPU loops across any language or project. Use when an app becomes unresponsive, switching contexts stalls, or you need thread stacks to locate lock inversion or blocking calls.
rust-pro
vudovn
Master Rust 1.75+ with modern async patterns, advanced type system features, and production-ready systems programming. Expert in the latest Rust ecosystem including Tokio, axum, and cutting-edge crates. Use PROACTIVELY for Rust development, performance optimization, or systems programming.
run-rust-benchmarks
RediSearch
Run Rust benchmarks and compare performance with the C implementation
analyze-ci-speed
Sovereign-Labs
Analyze compilation time and test durations from CI logs. Use when the user asks about slow builds, slow tests, or wants to optimize CI time.