A zero-code path to sending traces, metrics, and logs to JJHub OBSERVE via the OpenTelemetry Java agent, with env-var config, data verification steps, and fixes for common 401 and protocol mismatches.
The lowest-friction way to get a Java service into an observability platform is the OpenTelemetry Java agent — attach a JAR and you get traces, metrics, and logs with zero code changes. This guide walks through the whole path end to end, and clears up the two sticking points that trip up nearly everyone: 401 auth failures and exporter protocol mismatches.
Before you start, it helps to know what you're sending. OpenTelemetry models three signal types — traces (the path a request takes through your services), metrics (numeric measurements like request rate and latency), and logs. The Java agent can emit all three, and the setup below turns them all on at once, so you don't have to revisit this later.
Download opentelemetry-javaagent.jar into your deploy directory and add these JVM flags:
java -javaagent:opentelemetry-javaagent.jar -Dotel.exporter.otlp.endpoint=https://ob.jjhub.cn/otlp -Dotel.resource.attributes=service.name=order-service -Dotel.traces.exporter=otlp -Dotel.metrics.exporter=otlp -Dotel.logs.exporter=otlp -jar order-service.jar
Name your service as app-env, e.g. order-service-prod, so you can filter by environment in the service list. The agent auto-instruments HTTP, databases, and message queues, so no business code changes are needed.
One thing to know up front: the agent instruments everything it recognizes by default. If the span volume gets noisy, disable libraries you don't actually use with flags like -Dotel.instrumentation.spring-webmvc.enabled=false, rather than hand-rolling spans later. It's cheaper to trim the agent than to build your own instrumentation.
As the flag list grows, it gets hard to maintain — especially in Kubernetes. Move everything to environment variables:
export OTEL_EXPORTER_OTLP_ENDPOINT=https://ob.jjhub.cn/otlp
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer <your-token>"
export OTEL_SERVICE_NAME=order-service
export OTEL_METRICS_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp
Two things to watch. The auth header must be Authorization=Bearer <token> — a missing token means a 401 and zero data lands, which is the single most common reason "nothing shows up." And if your OTLP endpoint speaks HTTP rather than gRPC, the protocol must match your agent's exporter: older agents default to gRPC, newer ones to HTTP/Protobuf. When you see connection-refused or timeout errors, confirm that pairing before touching anything else.
Traces alone won't correlate if logs stay in local files. Use the Logback OpenTelemetry appender to push logs over OTLP — trace_id and span_id are attached automatically, so clicking a span in the trace view shows the exact log lines it produced. Add the opentelemetry-logback-appender dependency, then wire it into logback.xml alongside your existing console appender:
<appender name="otel" class="io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender"/>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="otel"/>
</root>
Keep the console appender as a fallback: if the collector is down, you still have local logs to fall back on, and a collector outage never costs you your application logs. One caveat — the appender sends logs asynchronously in batches, so at very high log volume you may want to raise the batch size and queue limit rather than defaulting to a blocking sync write.
Wait about 30 seconds after startup. order-service should appear in the service list, with traces and metrics behind it. Fire one real request, then look it up by trace_id to confirm logs and traces line up end to end. If they don't, check in order: is the token right, is the endpoint right, and does the exporter protocol match? Resolve those three and the data will flow — in our experience, those three account for almost every onboarding problem.
Once one service is in, repeat the same steps for the rest. The first service takes the longest because it's where you establish the convention for service naming and token handling; every service after that is a copy-paste job.
Most failures announce themselves clearly if you know where to look. A 401 Unauthorized in the agent's debug log means the token is missing or wrong — check OTEL_EXPORTER_OTLP_HEADERS. A Connection refused or timeout means the endpoint or protocol is off — verify the URL and whether the receiver expects gRPC or HTTP/Protobuf. Silence with no errors at all usually means the exporter is disabled or pointing at a queue that isn't flushing; flip on -Dotel.javaagent.debug=true to see exactly what the agent is doing with each span. Armed with those three signals, most onboarding stalls resolve in a few minutes without a support ticket.