OpenTelemetry Java Instrumentation: The Agent That Removes Manual Tracing
OpenTelemetry auto-instrumentation and instrumentation libraries for Java.
At a glance
- What is it?
- The opentelemetry-java-instrumentation project ships a Java agent that attaches to any Java 8+ app and injects bytecode to capture traces and metrics from hundreds of libraries. It is the fastest path to OpenTelemetry data, but its default OTLP endpoint and configuration churn require attention.
- Who is it for?
- Adopt the OpenTelemetry Java agent if you run a Java 8+ application and want traces and metrics from common libraries without code changes. Skip it if you need fine-grained control over spans, if you must avoid bytecode manipulation, or if your stack uses libraries not in the supported list.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What the Agent Solves and Who It Serves
The OpenTelemetry Java Instrumentation project solves a specific pain: getting telemetry out of a Java application without editing its code. Most Java services are built on frameworks like Spring, JDBC drivers, HTTP clients, and messaging libraries. Adding tracing to each of those by hand is repetitive and error-prone. The agent JAR attaches to any Java 8+ application at startup and dynamically injects bytecode to capture telemetry from a large number of popular libraries and frameworks. The intended user is a team that wants OpenTelemetry data quickly, with minimal effort, and is willing to accept that the instrumentation is generic rather than tailored to their domain. It is also useful for legacy applications where you cannot easily change the source code. The README makes this explicit: the net result is the ability to gather telemetry data from a Java application without code changes. That is the core promise, and it is a strong one for teams that need visibility fast.
How the Bytecode Injection Works
The mechanism is a Java agent that uses the JVM's instrumentation API to modify class bytecode as classes load. The agent is not a library you import; it is a JAR you pass to the JVM with the -javaagent flag. When the JVM starts, the agent's premain method runs, registers a ClassFileTransformer, and then every class that loads is examined. If the class matches a known instrumentation pattern, such as a JDBC driver or an HTTP servlet, the agent injects bytecode that creates spans, adds attributes, and propagates context. This happens transparently to the application code. The agent also includes the OpenTelemetry SDK and all supported exporters, so it can send data directly to a collector or console. The data flow is simple: the injected code creates telemetry, the SDK processes it, and the configured exporter sends it out. Because the instrumentation is injected at class load time, it works with frameworks that use reflection or dynamic proxies, though the README does not detail those edge cases. The documentation does not specify which bytecode library is used, but the effect is that you get spans without writing a single line of tracing code.
Getting Started: One JAR and Two Flags
The quick start is refreshingly short. You download the latest opentelemetry-javaagent.jar from the releases page, then launch your application with the -javaagent flag. The README gives this exact command: java -javaagent:path/to/opentelemetry-javaagent.jar -jar myapp.jar. By default, the agent uses the OTLP exporter and sends data to an OpenTelemetry collector at http://localhost:4318. That means you need a collector running on localhost, or you change the exporter. For testing, you can switch to console output with -Dotel.traces.exporter=console. You can also set the service name with -Dotel.resource.attributes=service.name=your-service-name. Configuration is done through Java system properties (-D flags) or environment variables. The README warns that configuration parameter names are very likely to change over time, so you should check the configuration docs when upgrading. This is a real operational concern: a config key that works in v2.30.0 might not work in v2.31.0, and you will need to track those changes.
Configuration Depth and Its Risks
The agent is highly configurable, according to the README. You can choose the exporter, set where data is sent, control trace context propagation headers, and more. The full list lives in the agent configuration docs and the SDK configuration docs. This flexibility is a double-edged sword. On one hand, you can tailor the agent to your infrastructure without writing code. On the other, the README explicitly says that config parameter names are very likely to change over time. That is an unusual admission for a mature project, and it means your startup scripts and environment variables are part of your maintenance burden. The debug flag, -Dotel.javaagent.debug=true, turns on internal logging, but the README warns that these logs are extremely verbose and negatively impact performance. So you should enable it only when troubleshooting, not in production. The configuration surface is broad, but the documentation points to external docs rather than listing everything in the README, which is appropriate for a project this large.
When the Agent Is the Wrong Tool
The agent is not a universal solution. First, it only instruments libraries and frameworks that are on the supported list. If your application uses a niche library or a custom protocol, you will get no telemetry from it. The README mentions a full list of supported libraries and application servers, but it does not enumerate them in the README itself. You must check that list before committing. Second, the agent injects bytecode, which can interfere with applications that do their own class loading tricks or that run in environments with strict security policies. The README does not discuss these failure modes, but they are inherent to bytecode manipulation. Third, the default OTLP endpoint assumes a collector on localhost:4318. If you do not run one, you get no data. That is a simple setup detail, but easy to miss. Finally, the agent is designed for automatic, generic instrumentation. If you need to add domain-specific attributes to spans or create custom spans for business logic, you must use manual instrumentation. The README says that for most users, the out-of-the-box instrumentation is sufficient, but it also points to manual instrumentation docs for those who need more. That is a clear boundary.
Alternatives: Standalone Instrumentation and Manual API
The same repository publishes standalone instrumentation for several libraries, which you can use if you prefer not to use the Java agent. The key difference is that standalone instrumentation is a library you add to your application's classpath, and it instruments only the specific library it targets. You get more control over what is instrumented and when, but you must add dependencies and possibly configure each one. This is a trade-off: the agent gives you everything at once with zero code, while standalone libraries give you a smaller footprint and more explicit control. Another alternative is manual instrumentation, where you use the OpenTelemetry API directly in your code to create spans and add attributes. That is the opposite of the agent: full control, but you write and maintain the instrumentation code. The README positions manual instrumentation as something you do when the automatic spans are not enough. So the choice is between zero-effort generic telemetry, targeted library instrumentation, and hand-written spans. Each fits a different need.
Extensions, Distributions, and Maintenance Cost
If the agent does not do exactly what you want, you can extend it without forking the repository. Agent extensions let you add custom samplers or span exporters, set new defaults, and embed everything into a single jar. The README recommends extensions over creating your own distribution, because distributions require rebuilding with each OpenTelemetry Java agent release. That is a concrete maintenance cost: if you build a custom distribution, you take on the burden of tracking upstream releases and rebuilding. Extensions are simpler because they do not require that. The project also provides an example of creating a distribution, but the README explicitly says extensions are recommended for most users. This guidance is practical and saves you from a common trap. The project is maintained by a team from Splunk, Microsoft, Grafana Labs, Elastic, and others, with a clear governance structure. The license is Apache-2.0, which means you can use it in commercial products without paying a fee, but you should understand the license terms yourself. The release cadence is active, with three versions in the last two months, so you can expect regular updates and potential behavior changes.
Editorial conclusion
Adopt the OpenTelemetry Java agent if you run a Java 8+ application and want traces and metrics from common libraries without code changes. Skip it if you need fine-grained control over spans, if you must avoid bytecode manipulation, or if your stack uses libraries not in the supported list. Before production, verify that your application server and libraries are in the supported list, confirm that the default OTLP endpoint http://localhost:4318 matches your collector, and test with -Dotel.javaagent.debug=true to see what instrumentation actually activates. The agent is the easiest path to OpenTelemetry, but it is not a substitute for understanding your own application's telemetry needs.
Community notes