Zero-code instrumentation is a way to collect telemetry from an application without changing its source code. An agent, runtime hook or eBPF program attaches to the process and instruments common libraries such as HTTP servers, database clients and messaging frameworks automatically. OpenTelemetry uses this term for what was previously called automatic instrumentation.
What is zero-code instrumentation?
Zero-code instrumentation gives you traces, metrics and often logs from an application without editing its code. Instead of calling the OpenTelemetry API inside your handlers, you attach an agent or enable a runtime hook at startup, and it instruments the libraries the application already uses. OpenTelemetry documentation adopted the term to replace "automatic instrumentation", because it describes more precisely what the user does: nothing in the code.
It complements, rather than replaces, code-based instrumentation. Zero-code gives broad coverage of frameworks and protocols on day one; manual spans and attributes add the business context only your code knows.
How it works
The mechanism depends on the runtime:
- Bytecode manipulation (Java): a Java agent rewrites classes of supported libraries as they load and inserts span creation and context propagation.
- Monkey patching (Python, Node.js, Ruby): library functions are wrapped at import time.
- Profiler APIs (.NET): the CLR profiling interface lets an external component inject instrumentation.
- eBPF (compiled languages such as Go, or any process): kernel programs observe function calls or network traffic from outside the process. OpenTelemetry has eBPF-based projects for this, such as OpenTelemetry Go automatic instrumentation and OpenTelemetry eBPF Instrumentation (OBI).
All approaches emit data following semantic conventions, so a Java service and a Python service report HTTP spans with the same attributes.
Examples per language
Java
export OTEL_SERVICE_NAME=checkout
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
java -javaagent:./opentelemetry-javaagent.jar -jar checkout.jar
Python
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
opentelemetry-instrument --service_name checkout python app.py
Node.js
npm install @opentelemetry/api @opentelemetry/auto-instrumentations-node
node --require @opentelemetry/auto-instrumentations-node/register app.js
.NET, PHP and other runtimes
For .NET, the OpenTelemetry .NET automatic instrumentation project ships install scripts and uses the CLR profiler interface, so ASP.NET Core, HttpClient and common database clients are traced without code changes. PHP uses a compiled extension together with instrumentation packages installed through Composer. Ruby offers an all-in-one instrumentation gem that only needs a few lines of configuration. Coverage differs between languages, so check the list of supported libraries for your stack before you rely on it in production.
Configuration happens through standard environment variables such as OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_RESOURCE_ATTRIBUTES and OTEL_TRACES_SAMPLER, which work the same across languages.
Zero-code on Kubernetes with the Operator
The OpenTelemetry Operator makes zero-code instrumentation a platform feature. You define an Instrumentation resource with exporter endpoint, propagators and sampler once, then opt workloads in with an annotation on the pod template:
metadata:
annotations:
instrumentation.opentelemetry.io/inject-java: "true"
The Operator injects the agent via an init container and sets the environment variables. Annotations exist for Java, Node.js, Python, .NET and Go, among others. Application teams get tracing without touching their images, and the platform team controls versions centrally.
Benefits and limits
| Benefits | Limits |
|---|---|
| Fast time to value, no code changes or redeploys of new code | Only instruments supported libraries and frameworks |
| Consistent coverage across many services and teams | No business context, such as order value or tenant, without manual attributes |
| Works for third-party and legacy applications | Startup time and memory overhead, depending on runtime and agent |
| Upgrades managed centrally | Can produce noisy spans, for example for health checks, that need filtering |
Zero-code, eBPF or manual: how to choose
The three approaches answer different needs. Language agents give the richest detail for supported frameworks, including database statements and messaging metadata, and they propagate trace context inside the process. eBPF-based instrumentation needs no runtime support at all and covers services you cannot restart with an agent, but it sees less application context and depends on kernel features. Manual instrumentation offers full control and business attributes, at the cost of developer time. In practice, most teams combine them: agents for the languages they run widely, eBPF for gaps such as compiled or third-party binaries, and manual spans for the few code paths where business context really matters.
Best practices
- Start with zero-code, then add manual spans where business logic matters. Agents usually expose the OpenTelemetry API, so manual spans join the same trace.
- Set
service.nameand environment explicitly; defaults such asunknown_servicemake data hard to find. - Disable instrumentations you do not need to cut overhead and noise; most agents support per-library switches.
- Pin agent versions and test upgrades in staging, because instrumentation changes can alter span names and attributes.
- Measure overhead under realistic load before rolling out widely.
- Filter noise in the Collector, for example health-check and readiness probe spans.
How Obseria helps
Obseria works with the standard OpenTelemetry zero-code agents and the Operator; point OTEL_EXPORTER_OTLP_ENDPOINT at Obseria and teams with existing OpenTelemetry setups typically see a first trace within 15 minutes. Alternatively, the Obseria Agent is installed once per host and collects metrics, logs, traces and profiles without per-service code changes. Language guides: Java, Python and Node.js.