CtrlK
BlogDocsLog inGet started
Tessl Logo

maple-telemetry-conventions

Maple's OpenTelemetry conventions — custom span attribute keys (`maple.*` vendor namespace, `query.context`, `db.query.*`, `result.*`, `cache.*`, `tenant.*`), Title Case status codes (`Ok`/`Error`/`Unset`), resource attribute dual-emit (`deployment.environment` + `deployment.environment.name`), span kinds, Tinybird MV pre-extracted columns, loop-prevention filters, and sampling. Use whenever writing or reviewing instrumentation code in any language (TypeScript, Rust, Python) in this repo — adding `setAttribute`/`setAttributes`/`record`/`#[instrument(fields(...))]` calls, setting span status, configuring an OTLP exporter, defining a new resource attribute, or wiring a new query through `WarehouseQueryService.sqlQuery()`.

65

Quality

78%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Fix and improve this skill with Tessl

tessl review fix ./.agents/skills/maple-telemetry-conventions/SKILL.md
SKILL.md
Quality
Evals
Security

Maple Telemetry Conventions

Reference for the language-agnostic OpenTelemetry conventions Maple uses across TypeScript (apps/api, Cloudflare workers in lib/effect-sdk/), Rust (apps/ingest), and future Python services. These conventions are load-bearing — Tinybird materialized views pre-extract certain attribute keys into columns, dashboards filter on Title Case status strings, and sampling-aware throughput math relies on the SampleRate column. Use the exact attribute spellings here in every language.

When to apply

  • Adding setAttribute / Effect.annotateCurrentSpan / Span::current().record(...) / #[instrument(fields(...))] to any code path
  • Setting span status (Ok / Error / Unset)
  • Wiring a new query through WarehouseQueryService.sqlQuery() (the context and profile options become span attributes)
  • Configuring an OTLP exporter, tracer provider, or resource builder
  • Introducing a new pre-extracted MV column or a new vendor attribute under maple.*
  • Reviewing a PR that touches apps/api/src/services/WarehouseQueryService.ts, apps/ingest/src/main.rs, apps/api/src/app.ts, lib/effect-sdk/src/cloudflare/, or packages/domain/src/tinybird/materializations.ts

Index

  • rules/span-attributes.md — Master reference of every custom attribute key Maple emits, grouped by namespace, with file:line citations.
  • rules/status-and-kind.md — Title Case status code rule (Ok/Error/Unset) and span kind conventions (Server / Client / Internal).
  • rules/resource-attributes.mdservice.* identity, deployment.environment.name resolution order, the legacy deployment.environment dual-emit, and maple_org_id.
  • rules/language-bindings.md — Parallel TypeScript / Rust / Python snippets that emit the same attribute keys.
  • rules/mv-first-class-columns.md — Which span and resource attributes Tinybird MVs pre-extract into columns (and the rule for adding new ones).
  • rules/service-map-attribution.md — Required span and resource attributes for the service map to render edges, runtime icons, and platform badges. Includes the canonical peer.service registry.
  • rules/loop-prevention.md — The three guards that prevent Maple's self-traffic from creating a feedback loop: API TracerDisabledWhen, ingest loopback guard, sampling.

Quick reference

TopicRule
Status codesAlways Title Case: "Ok", "Error", "Unset". Never OK, ERROR, SUCCESS, FAILED.
Vendor namespaceCustom attributes go under maple.*. Sub-namespaces: maple.ingest.*, maple.cloudflare.*.
Standard semconvUse OTel semconv keys verbatim: service.name, http.request.method, db.system.name, error.type.
Org identityorgId (camelCase) in TypeScript spans, maple.org_id (dotted) in Rust spans. Don't unify until MVs migrate.
Deployment envDual-emit deployment.environment + deployment.environment.name. Keep both until MV coalesce() migration lands.
Warehouse SQL spansEvery span from WarehouseQueryService.executeSql carries db.system.name, peer.service, db.query.text, db.query.fingerprint, db.duration_ms, result.rowCount, orgId, query.context, query.profile. Legacy spans (pre 2026-06) use db.statement*/db.system; warehouse readers coalesce both.
Service mapOutbound spans need peer.service (HTTP/RPC) or db.system.name (DB) on a Client/Producer span. Resource attrs need process.runtime.name, cloud.platform, maple.sdk.type for runtime icon + platform badge. See rules/service-map-attribution.md.
Loop preventionNever remove HttpMiddleware.TracerDisabledWhen (apps/api/src/app.ts:169-175) or the ingest loopback guard (apps/ingest/src/main.rs:499-514).

Canonical references (do not modify from this skill)

  • apps/api/src/services/WarehouseQueryService.ts:441-510executeSql span emission (the canonical example for TS).
  • apps/ingest/src/otel.rs — Resource builder + platform detection + forward-span helper for Rust. The canonical example for Rust resource and outbound-span attribution.
  • apps/ingest/src/main.rshandle_signal and handle_cloudflare_logpush (search for tracing::info_span! with otel.kind = "server") — Server-kind span macros for OTLP inbound.
  • apps/api/src/app.ts:169-175TracerDisabledWhen filter.
  • lib/effect-sdk/src/cloudflare/index.tsMapleCloudflareSDK tracer setup.
  • packages/domain/src/tinybird/materializations.ts — MV SELECT lists that pre-extract attribute keys into columns.
Repository
MapleTechLabs/maple
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.