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 via tracing-opentelemetry so existing info! / error! calls flow through OTLP.
Cargo.toml
[dependencies]
opentelemetry = "0.27"
opentelemetry_sdk = { version = "0.27", features = ["rt-tokio"] }
opentelemetry-otlp = { version = "0.27", features = ["http-proto", "reqwest-client", "logs", "metrics"] }
opentelemetry-semantic-conventions = "0.27"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tracing-opentelemetry = "0.28"
Bootstrap
Inline the endpoint and ingest key — they're a project-scoped, write-only token (Sentry-DSN-shaped).
use opentelemetry::{global, KeyValue};
use opentelemetry_otlp::{LogExporter, MetricExporter, Protocol, SpanExporter, WithExportConfig};
use opentelemetry_sdk::{
logs::LoggerProvider, metrics::SdkMeterProvider, trace::TracerProvider, Resource,
};
use opentelemetry_semantic_conventions::resource::{
DEPLOYMENT_ENVIRONMENT_NAME, SERVICE_NAME,
};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
const MAPLE_ENDPOINT: &str = "https://ingest.maple.dev";
const MAPLE_KEY: &str = "MAPLE_TEST"; // set by maple-onboard skill on pairing
pub fn init() -> Result<(TracerProvider, LoggerProvider, SdkMeterProvider), opentelemetry_otlp::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_attributes([
KeyValue::new(SERVICE_NAME, "orders-api"),
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::HttpJson)
.build()?;
let tracer_provider = TracerProvider::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::HttpJson)
.build()?;
let logger_provider = LoggerProvider::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::HttpJson)
.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(global::tracer("orders.api"));
let otel_log_layer = opentelemetry_appender_tracing::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() {
let (tracer_provider, logger_provider, meter_provider) =
telemetry::init().expect("telemetry init");
// app run …
let _ = tracer_provider.shutdown();
let _ = logger_provider.shutdown();
let _ = meter_provider.shutdown();
}
Bounded business spans via tracing
The point of bridging tracing is so existing instrumentation works unchanged. Use #[tracing::instrument] on bounded async operations:
#[tracing::instrument(name = "order.submit", skip_all, fields(order.id = %order_id))]
async fn submit_order(order_id: &str) -> Result<(), Error> {
charge_order(order_id).await?;
Ok(())
}
tracing::error! and ?err field interpolation will record the exception and set the span status to ERROR via the bridge.
Coexistence
If the project already uses tracing with a Honeycomb / Datadog / Jaeger layer, leave it in place — add Maple's tracing-opentelemetry layer alongside. Don't 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 | 3mo | Review | Advanced |
| mcp | 0 | 7mo | Review | Advanced |
| rust-async-patterns | 11 | 2mo | Review | Intermediate |
| debug-lldb | 1 | 7mo | 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.