How to Stop Rewriting Code for Logs and Metrics
Imagine this: you have a dozen Java microservices running in production. At some point, one of them starts to "lag." You open the logs, but there's nothing there — the standard messages aren't enough to understand which exact stage the request is getting stuck at. Familiar story? Usually at this point, the developer goes into the code, decorates methods with annotations, adds tracing dependencies, rebuilds the project, and deploys it again. And if there are hundreds of services written on different frameworks?
In the OpenTelemetry ecosystem, there's a project that solves this problem elegantly and, what's especially nice, almost lazily. This is opentelemetry-java-instrumentation. It's a special Java agent that can inject into your application "on the fly" and collect telemetry without a single line of new code.
What This Agent Is and Why You Need It
Essentially, it's a JAR file that you attach when starting the JVM. It uses dynamic bytecode injection. When your application loads classes from popular libraries (for example, Spring, Hibernate, gRPC, or Kafka), the agent carefully injects logic for creating spans and collecting metrics.
This is an ideal option for two scenarios. First, when you need to quickly add observability to a legacy project that's scary to touch. Second, when you want to standardize data collection across the entire company without making each team manually configure the SDK.
Three Cool Features That Make Life Easier
Automatic Magic Out of the Box
The agent supports a huge number of libraries. If you use a standard stack like Spring Boot with PostgreSQL and Redis, you don't need to configure anything at all. You just attach the agent, and in your monitoring system (for example, Jaeger or Zipkin) you get a call tree: from the incoming HTTP request to the database query and cache response.
Propagating Context to Logs (MDC)
One of the most useful things in everyday debugging is automatic Trace ID insertion into logs. The agent can find your loggers (Logback, Log4j2) on its own and add the current trace's identifier to MDC. Now, when you see an error in the logs, you can just copy the ID and find the entire path of that request across all services. No more guessing which user triggered that NullPointerException.
Flexible Configuration Without Rebuilding
All parameters — where to send data, how often to sample it, which attributes to add to spans — are passed through environment variables or Java system properties. This means the same binary of your application can send data to the console in dev and to a heavy OpenTelemetry Collector cluster in production.
How to Get This Running
The setup process is surprisingly simple. First, download the latest opentelemetry-javaagent.jar from the releases page. Then add one flag to your application's launch command:
java -javaagent:path/to/opentelemetry-javaagent.jar \
-Dotel.resource.attributes=service.name=my-cool-service \
-jar myapp.jar
By default, the agent expects a collector accepting data via the OTLP protocol to be running somewhere at localhost:4318. If you want to use something else, for example Zipkin, you change it with one flag: -Dotel.traces.exporter=zipkin.
Under the Hood and Extensibility
Interestingly, the project doesn't limit you to just "automation." If the built-in capabilities aren't enough, you can use the extensions mechanism. You can write your own JAR file that will add custom instrumentation rules or company-specific attributes.
For those who don't trust agent magic at all, the project ships the same instrumentation libraries separately. You can add them as regular dependencies and configure them manually, but then you'll have to accept the need to modify code.
Is It Worth Using
I often encounter the opinion that Java agents are a "black box" that can slow down an application. There's some truth to this: the agent does spend resources on bytecode transformation at startup and adds a small overhead when executing requests. However, in 95% of cases, this overhead is negligible compared to the benefit you get when hunting bugs in a distributed system.
Who will it suit especially well:
- Teams transitioning to microservices and choking without tracing.
- Support that needs "yesterday" to understand why the old monolith is slow.
- Architects implementing a unified monitoring standard.
If you haven't tried OpenTelemetry in your Java projects yet, this agent is the fastest and least painful way to get started. Just try running it locally and see how much interesting stuff you learn about your code's behavior under load.
Related projects