Subchapter 93.6
references/java.mdMarkdown6 KBView on GitHub
AI agents: this is one page from PostHog’s docs. Full index of Markdown docs for LLMs: https://posthog.com/llms.txt (opens in a new tab)
Cloud region: This page uses US Cloud hosts. For an EU Cloud project, use
https://eu.i.posthog.cominstead ofhttps://us.i.posthog.com(ingestion host), and usehttps://eu.posthog.cominstead ofhttps://app.posthog.com(app host for links).
1
Required
For the complete SDK reference, see the OpenTelemetry Java docs (opens in a new tab).
The zero-code Java agent is the recommended way to instrument a Java app. Download the latest agent jar:
curl -L -O https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jarThe agent instruments your application at runtime, so you don’t need to add any dependencies to get started. If you’d rather instrument manually, see the SDK alternative in the configuration step.
2
Required
You’ll need your PostHog project token to authenticate trace requests. This is the same token you use for capturing events with the PostHog SDK.
Important: Use your project token which starts with
phc_. Do not use a personal API key (which starts withphx_).
You can find your project token in Project settings (opens in a new tab).
3
Required
Set the OpenTelemetry environment variables to export spans to PostHog over OTLP HTTP, then start your app with the agent attached.
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://us.i.posthog.com/i/v1/traces
OTEL_EXPORTER_OTLP_TRACES_HEADERS=Authorization=Bearer <ph_project_token>
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/protobuf
OTEL_SERVICE_NAME=my-servicejava -javaagent:opentelemetry-javaagent.jar4
Required
Wrap the operations you want to measure in spans, and attach attributes for context.
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Scope;
Tracer tracer = GlobalOpenTelemetry.getTracer("my-service"
5
Recommended
Once everything is configured, confirm spans are reaching PostHog:
Checkpoint
What you can do with your traces
| Action | Description |
|---|---|
| Why you need distributed tracing (opens in a new tab) | What a trace shows you that nothing else does |
| Explore traces | Read a trace as a waterfall to see where time goes |
| Filter spans | Narrow down by service, status, duration, and attributes |
| Propagate context | Pass trace context across services so spans join the same trace |
To instrument manually instead, add the SDK dependencies (opentelemetry-api, opentelemetry-sdk, and opentelemetry-exporter-otlp via the opentelemetry-bom) and build the exporter in code:
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
OtlpHttpSpanExporter spanExporter = OtlpHttpSpanExporter.builder()
.setEndpoint("https://us.i.posthog.com/i/v1/traces")
.addHeader("Authorization", "Bearer <ph_project_token>")
.build();
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(BatchSpanProcessor.builder(spanExporter).build())
.build();
OpenTelemetrySdk openTelemetry = OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.buildAndRegisterGlobal();The buildAndRegisterGlobal() call registers the SDK as the global instance, so GlobalOpenTelemetry.getTracer(...) in the next step works. (The Java agent does this for you, which is why the zero-code path needs no registration.)
Note: Pass the full
/i/v1/tracespath to the traces endpoint.OtlpHttpSpanExporteralready sends OTLP over HTTP/protobuf, so no protocol setting is needed in code. If you configure via the environment variables above instead, setOTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/protobuf– the SDK’s autoconfigure path defaults to gRPC.