<< All versions

Skill v0.1.0

currentAutomated scan100/100
radra23/otel-as-code-plugin/language-maturity
──Details
PublishedSeptember 28, 2026 at 11:11 AM
Content Hashsha256:9803c28501585530...
Git SHA25ffec089b98
──Files
Files (1 file, 11.8 KB)
SKILL.md11.8 KBactive
SKILL.md · 186 lines · 11.8 KB

name: language-maturity description: Per-language OTel signal maturity matrix (Stable / Beta / Development) and feature-gating rules. Use before generating OTel SDK code to gate signals by maturity and the --experimental flag. version: 0.1.0


OTel Language Signal Maturity Matrix

Reference: opentelemetry.io/docs/languages (pinned semconv version: see SEMCONV_VERSION in the semconv-discipline skill — the single source of truth)

Maturity Levels

  • Stable — API/SDK frozen, safe for production, full semconv coverage
  • Beta — feature-complete but may have minor API changes
  • Development — experimental, incomplete, not for production

Runtime gating — what this matrix is about

Every row below describes a server-side runtime. The matrix is indexed by the service's runtime field from the context cache, NOT by language: those are different questions, and conflating them is how a Vite + React SPA (language: nodejs, runtime: browser) gets a @opentelemetry/sdk-node bootstrap that cannot run and breaks the build.

runtimeIn scope?Notes
nodeyesNode.js row below
pythonyesPython row below
jvmyesJava agent row below
dotnetyes.NET code-based SDK (all signals Stable) — see the .NET row below
browsernoOut of scope for the MVP — see "Browser / RUM" below
goyesGo row below (manual net/http SDK wiring)
rubyyesRuby row below (opentelemetry-instrumentation-all)
php rustnot yetv1 additions table at the end

Browser / RUM — out of scope, deliberately

Browser instrumentation is a different product: a different SDK (@opentelemetry/sdk-trace-web + @opentelemetry/auto-instrumentations-web), a different delivery path (bundled into the page, not preloaded with node -r), a different transport (OTLP/HTTP with CORS, never gRPC), and a different signal set (document load, resource timing, user interactions — not inbound HTTP server spans). None of the server-side generation in this plugin applies to it.

/otel-instrument must therefore refuse a service with runtime: browser and say why, rather than generating a near-miss. This is stated here as well as in the MVP docs because the only other way to discover it is to try it.

Supported Languages (Node.js, Python, Java, .NET, Go, Ruby)

Node.js

SignalStatusPackage
TracesStable@opentelemetry/sdk-trace-node
MetricsStable@opentelemetry/sdk-metrics
LogsStable@opentelemetry/sdk-logs + @opentelemetry/winston-transport
AutoStable@opentelemetry/auto-instrumentations-node

Node.js bootstrap: use @opentelemetry/sdk-node (bundles traces + metrics + logs). OTLP exporter: @opentelemetry/exporter-trace-otlp-grpc (prefer gRPC over HTTP). Semconv constants: @opentelemetry/semantic-conventions — use named exports (ATTR_SERVICE_NAME, ATTR_HTTP_REQUEST_METHOD, etc.) not raw strings.

Python

SignalStatusPackage
TracesStableopentelemetry-sdk
MetricsStableopentelemetry-sdk (MeterProvider)
LogsDevelopmentopentelemetry-sdk (opentelemetry.sdk._logs) — gated behind --experimental
AutoStableopentelemetry-instrumentation-* (per-framework)

Python bootstrap: use opentelemetry-sdk + opentelemetry-exporter-otlp-proto-grpc. Auto-instrumentation: framework-specific package (e.g. opentelemetry-instrumentation-fastapi, opentelemetry-instrumentation-django, opentelemetry-instrumentation-flask).

Logs are Development, not Beta — gated behind `--experimental`. The OTel spec marks the Logs SDK stable, but the Python implementation has not been promoted: the API lives under the underscore module opentelemetry.sdk._logs, the SDK's own signal that it may still change. So treat Python logs as Development — traces and metrics (both Stable) always generate; the logs pipeline is emitted only when --experimental is set (see the Python logs block in instrumentation-gen). Do not "promote" this to Stable from the spec status alone.

Java (OpenTelemetry Java agent)

SignalStatusMechanism
TracesStableJava agent — auto-instruments common libraries
MetricsStableJava agent — auto
LogsStableJava agent — log-appender bridge (Logback / Log4j2 / JUL → OTLP)
AutoStableopentelemetry-javaagent.jar (zero-code, JDK 8+)

Java uses the OpenTelemetry Java agent (-javaagent:opentelemetry-javaagent.jar), NOT a manual SDK bootstrap file: it auto-instruments with no code change. Configure entirely via OTEL_* env vars (OTEL_SERVICE_NAME, OTEL_RESOURCE_ATTRIBUTES, OTEL_EXPORTER_OTLP_ENDPOINT) — the generator emits an otel-java.env file plus a pinned agent download + run command (see the Java section in instrumentation-gen). The agent exports OTLP by default, so per-signal exporter env (OTEL_TRACES_EXPORTER=otlp, etc.) is redundant and omitted. "Logs = Stable" refers to the log-appender bridge (application logging frameworks → OTLP logs), not arbitrary log collection.

.NET (code-based SDK)

SignalStatusMechanism
TracesStableOpenTelemetry.Instrumentation.AspNetCore / .Http + OTLP exporter
MetricsStablesame instrumentation packages, WithMetrics
LogsStablebuilder.Logging.AddOpenTelemetry(...) (ILogger → OTLP)
DBBetaOpenTelemetry.Instrumentation.EntityFrameworkCore — see the note below
Auton/acode-based DI wiring, not a profiler (the zero-code agent is a v1 follow-up)

.NET uses a code-based SDK wired into the DI container — the generator emits a marker-stamped OpenTelemetry.cs (a public static IServiceCollection AddOtelObservability(...) extension) and prints the single Program.cs line + dotnet add package commands, rather than editing the user's files (see the .NET section in instrumentation-gen). The three core signals (traces, metrics, logs) via AspNetCore/Http are Stable, so nothing is gated behind --experimental.

EF Core DB instrumentation is Beta — the one .NET package not on the stable line. OpenTelemetry.Instrumentation.EntityFrameworkCore — the most common third package for any .NET service that touches a database — still ships as Beta (1.17.0-beta.x) while its AspNetCore/Http/core siblings are on stable 1.x, because DB semantic conventions haven't fully stabilized upstream. Like Node's incubating messaging.* (above), don't wave it through as "all Stable": if you add it, prepend the Beta comment, and note that it ships EmitOldAttributes/EmitNewAttributes toggles for the OLD→NEW DB attribute transition (db.name→db.namespace, db.statement→db.query.text, db.operation→db.operation.name) — verify the compiled defaults of the installed version rather than asserting which it emits. Traces + metrics ship in the extension; logs wire on builder.Logging (a separate line) so they are offered as a printed optional add-on rather than folded into the one-liner. Requires a hosted app (ASP.NET Core / Generic Host); a plain console app has no IServiceCollection and is refused.

Go

SignalMaturityPackage
TracesStablego.opentelemetry.io/otel/sdk + otlptracegrpc (v1.46.0)
MetricsStablego.opentelemetry.io/otel/sdk/metric + otlpmetricgrpc (v1.46.0)
LogsBetago.opentelemetry.io/otel/sdk/log + otlploggrpc (v0.22.0) — generated by default (Beta doesn't need --experimental), with a Beta comment
AutoBetago.opentelemetry.io/contrib/.../otelhttp (v0.71.0) — net/http only

Logs are Beta, not Development — generated without `--experimental`. Unlike Python's Development-level logs (gated behind --experimental), Go's Logs SDK is feature-complete enough to ship as Beta: generate the InitOtelLogsBeta function by default, with the Beta warning comment, same as Feature Gating Rule 3.

Ruby

SignalMaturityPackage
TracesStableopentelemetry-sdk + opentelemetry-exporter-otlp (1.13.0 / 0.35.1)
MetricsDevelopmentsame gems — generated only under --experimental
LogsDevelopmentsame gems — generated only under --experimental
Auton/aopentelemetry-instrumentation-all (0.96.0) — auto-detects Rails/Sinatra/Rack/DB drivers/HTTP clients, no per-framework list to maintain

Metrics and Logs are both Development — gated behind `--experimental`. Unlike Go's Beta logs (generated by default with a warning comment), Ruby's Metrics AND Logs implementations are both Development-level: BLOCK generation of both unless --experimental is set, per Feature Gating Rule 4 — the same treatment Python's Development-level logs already get.

Feature Gating Rules

When generating code for a signal:

  1. Check the maturity level from the table above.
  2. Stable → generate without warning.
  3. Beta → generate but prepend a comment: # Beta signal — API may change in future OTel releases. Adapt comment syntax to the target language (// for Node.js/Go/.NET, # for Python/Ruby).
  4. Development → BLOCK generation unless --experimental flag is set. Show:

⚠ [signal] for [language] is Development-level and not recommended for production. Re-run with --experimental to generate anyway.

Partial language support: If a language has mixed maturity (e.g. Traces=Beta, Logs=Development), generate the higher-maturity signals and block only the Development-level ones (unless --experimental). Never block an entire SDK generation request because one signal is Development-level.

v1 Language Additions (not in MVP)

LanguageTracesMetricsLogs
PHPStableBetaDevelopment
RustBetaBetaDevelopment
SwiftBetaDevelopmentDevelopment

Browser/RUM is not on this list: it is a scope decision, not a maturity one (the web SDK's traces are Stable). See "Browser / RUM" above.

--experimental Flag Behavior

When --experimental is passed:

  • Unlock Development-level signals — generate the code but prepend: # Experimental — requires --experimental flag (replaces the beta comment for Development signals).
  • Enable experimental semconv attributes (GenAI gen_ai.*, profiling process.*).
  • All generated code must include a comment: # Experimental — requires --experimental flag.
All versions