Production debugging without proper observability is like searching for a needle in a haystack — blindfolded, with mittens on. You know something broke, but you’re left guessing whether it was a slow database query, a cascading timeout, or a misconfigured load balancer. OpenTelemetry has become the de facto standard for fixing this problem, and 2026 has brought three major leaps forward that change how teams instrument their systems.
Let’s walk through what’s new, what’s stable, and how to actually wire it all together with real code.
The Fourth Signal: Continuous Profiling Goes Alpha
For years, OpenTelemetry focused on three signals: traces, metrics, and logs. In March 2026, Profiles officially entered public Alpha, adding continuous production profiling as a first-class signal. This isn’t just another data type — it’s the missing link between “this endpoint is slow” and “this specific function is burning CPU on these exact lines.”
The profiling signal is powered by an eBPF-based agent originally donated by Elastic, now integrated directly into the OTel Collector as a receiver. What makes this significant:
- No application changes required. The eBPF profiler attaches to the kernel and profiles all running processes — Go, Java, Python, Node.js, Ruby, .NET, and even Erlang/Elixir — without any code instrumentation.
- Cross-signal correlation. Profile samples can carry
trace_idandspan_idattributes, so you can jump from a slow trace directly to the CPU flame graph for that exact request. - Efficient wire format. The new OTLP Profiles format uses deduplicated stack traces and shared dictionary tables, achieving roughly 40% smaller wire size compared to raw pprof data.
The format round-trips cleanly with pprof, so existing tooling isn’t abandoned. And because it runs as an OTel Collector receiver, you can pipe profiles through the same processing pipeline as your traces and metrics — adding Kubernetes metadata via the k8sattributes processor, filtering with OTTL rules, and exporting to any OTLP-compatible backend.
Declarative Configuration Hits 1.0
If you’ve ever wrestled with OpenTelemetry’s environment-variable-heavy configuration, you’ll appreciate this one. Declarative configuration reached stable 1.0 in March 2026, giving teams a consistent YAML-based config model that works the same way across languages.
Instead of juggling OTEL_TRACES_EXPORTER=otlp, OTEL_EXPORTER_OTLP_ENDPOINT=http://..., and a dozen other env vars, you write a single config file:
# otel-config.yaml
file_format: "1.0"
resource:
attributes:
service.name: "order-service"
service.version: "2.4.1"
tracer_provider:
processors:
- batch:
schedule_delay: 5000
exporters:
- otlp:
endpoint: "http://collector:4317"
meter_provider:
readers:
- periodic:
interval: 10000
exporter:
otlp:
endpoint: "http://collector:4317"
Point to it with OTEL_CONFIG_FILE=./otel-config.yaml and the SDK handles the rest. Implementations are available in Go, Java, JavaScript, PHP, and C++, with .NET and Python in active development. The spec compliance matrix tracks each language’s progress.
This is a big deal for polyglot organizations. Instead of maintaining language-specific configuration docs, teams can share a single YAML template that behaves identically whether the service is written in Go or Java.
Observability for GenAI Workloads
The newest frontier is GenAI semantic conventions, which standardize how LLM interactions are traced. This is critical because an AI agent’s “45-second response” is really a chain of model calls, tool invocations, and retry loops — and without structured telemetry, you’re blind to where time is actually spent.
The conventions define span attributes like gen_ai.request.model, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, and gen_ai.response.finish_reasons. Optional content capture (off by default for privacy) records full prompts, completions, and tool call arguments. VS Code Copilot, OpenAI Codex, and Claude Code already emit this telemetry natively.
Here’s what instrumenting a GenAI call looks like in Python:
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
# Setup
provider = TracerProvider()
provider.add_span_processor(
BatchSpanProcessor(OTLPSpanExporter(endpoint="http://collector:4317"))
)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer("my-agent")
# Trace an LLM call
with tracer.start_as_current_span("gen_ai.chat") as span:
span.set_attribute("gen_ai.request.model", "gpt-4o")
span.set_attribute("gen_ai.system", "openai")
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Summarize this article"}],
)
span.set_attribute("gen_ai.usage.input_tokens", response.usage.prompt_tokens)
span.set_attribute("gen_ai.usage.output_tokens", response.usage.completion_tokens)
span.set_attribute("gen_ai.response.finish_reasons", response.choices[0].finish_reason)
Every LLM call now shows up in your trace backend with model name, token counts, and latency — making it trivial to spot expensive prompts, identify retry storms, and track cost per request.
Wiring It All Together: A Practical Collector Setup
The real power comes from unifying all four signals through a single OTel Collector pipeline. Here’s a production-ready Collector config that receives traces, metrics, logs, and profiles, enriches them with Kubernetes metadata, and exports everything via OTLP:
# collector-config.yaml
receivers:
otlp:
protocols:
grpc:
endpoint: "0.0.0.0:4317"
http:
endpoint: "0.0.0.0:4318"
# eBPF profiling receiver (Alpha - v0.148.0+)
ebpf/profiles:
collection_interval: "10s"
processors:
batch:
send_batch_size: 1024
timeout: "5s"
k8sattributes:
auth_type: "serviceAccount"
passthrough: false
extract:
metadata:
- k8s.namespace.name
- k8s.deployment.name
- k8s.pod.name
exporters:
otlp:
endpoint: "https://your-backend:4317"
tls:
insecure: false
service:
pipelines:
traces:
receivers: [otlp]
processors: [k8sattributes, batch]
exporters: [otlp]
metrics:
receivers: [otlp]
processors: [k8sattributes, batch]
exporters: [otlp]
logs:
receivers: [otlp]
processors: [k8sattributes, batch]
exporters: [otlp]
profiles:
receivers: [ebpf/profiles]
processors: [k8sattributes, batch]
exporters: [otlp]
Deploy this as a sidecar or a dedicated Collector deployment in your cluster, point all your services at it, and you get unified observability across every signal — with K8s metadata attached to every data point.
What to Watch Next
Three things worth tracking as OpenTelemetry continues to evolve:
- Profiles moving toward Beta. The Alpha is functional but explicitly not recommended for critical production workloads yet. Multiple vendors are building backend support — expect Beta by late 2026.
- Dynamic configuration. The declarative config spec stabilized the file-based model, but runtime reconfiguration (changing sampling rates without restarts) is still an open OTEP. This is the next major UX improvement.
- CI/CD observability. OpenTelemetry is expanding into pipeline observability — tracing build steps, test runs, and deployment rollouts. Early work is underway to define semantic conventions for CI/CD systems.
The message is clear: OpenTelemetry is no longer just about traces. With profiles entering Alpha, declarative config hitting 1.0, and GenAI conventions standardizing LLM observability, the project is building toward a single, unified observability stack that covers every layer of modern infrastructure — from kernel-level CPU profiling to AI agent conversations. If your team hasn’t started adopting OTel yet, there’s never been a better time. The official documentation and GitHub organization are the best places to start.