CtrlK
BlogDocsLog inGet started
Tessl Logo

kopai/otel-instrumentation

Instrument applications with the OpenTelemetry SDK and prove the telemetry is good by validating it against a local Kopai backend. Use when setting up observability, adding tracing/logging/metrics, deciding what to instrument or which attributes to add, retrofitting OTel into an existing codebase, threading context through call chains, configuring sampling, or when traces/logs/metrics aren't appearing after setup. Also use when users say things like "my traces aren't showing up", "I don't see any data", or "how do I add observability to my app". Do NOT use to investigate existing telemetry for a root cause (use root-cause-analysis), to build dashboards (use create-dashboard), or to instrument LLM and agent calls (use otel-genai-instrumentation).

Quality

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Low

Low-risk findings worth noting

Overview
Quality
Evals
Security
Files

lang-java.mdreferences/

titleimpacttags
Java InstrumentationHIGHlang, java, jvm, traces, logs, metrics

Java Instrumentation

Set up OpenTelemetry for Java applications using the Java agent for automatic instrumentation.

Install

# Download the latest OpenTelemetry Java agent
curl -L -O https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar

Configuration

export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf   # required — the agent defaults to gRPC
export OTEL_SERVICE_NAME="my-java-service"
export OTEL_LOGS_EXPORTER="otlp"
export OTEL_RESOURCE_ATTRIBUTES="validation.run_id=$RUN_ID"

Environment Variables:

VariableDescription
OTEL_EXPORTER_OTLP_ENDPOINTOTLP endpoint (e.g., http://localhost:4318)
OTEL_EXPORTER_OTLP_PROTOCOLhttp/protobuf — Kopai is HTTP-only; the agent defaults to gRPC on 4317
OTEL_SERVICE_NAMEService name shown in observability backend
OTEL_LOGS_EXPORTERSet to otlp to export logs via OTLP
OTEL_RESOURCE_ATTRIBUTESRun tag for the validation loop — see setup-environment.md

Forgetting the protocol is the single most common Java setup failure: the agent tries gRPC on 4317, Kopai isn't listening there, and nothing arrives with no obvious error.

Run with Agent

# Compile your application
javac MyApp.java

# Run with the agent attached
java -javaagent:opentelemetry-javaagent.jar MyApp

Or with a JAR file:

java -javaagent:opentelemetry-javaagent.jar -jar myapp.jar

What Gets Instrumented

The Java agent automatically instruments:

  • Traces: HTTP requests, database calls, messaging systems
  • Logs: Bridges java.util.logging, Log4j, SLF4J to OTLP
  • Metrics: JVM metrics, HTTP request metrics

No code changes required - the agent intercepts calls at runtime.

The agent handles flushing on JVM shutdown, so validate-shutdown.md S1 normally passes without extra work. It does not survive kill -9.

Custom spans and attributes

The agent gives you the skeleton; business context is still yours to add.

import io.opentelemetry.api.trace.Span;

Span span = Span.current();
span.setAttribute("user.id", userId);
span.setAttribute("user.type", user.getTier());
span.setAttribute("cart.total", cart.getTotal());
Tracer tracer = GlobalOpenTelemetry.getTracer("checkout-service");
Span span = tracer.spanBuilder("process-payment").startSpan();
try (Scope scope = span.makeCurrent()) {
    // ...
} catch (Exception e) {
    span.setAttribute("exception.slug", "err-stripe-charge-failed");
    span.setAttribute("error", true);
    span.recordException(e);
    span.setStatus(StatusCode.ERROR, e.getMessage());
    throw e;
} finally {
    span.end();
}

Context across thread pools

Thread-local context does not follow work submitted to an executor — spans created in the worker become orphans. Wrap the executor:

import io.opentelemetry.context.Context;

ExecutorService traced = Context.taskWrapping(executor);
traced.submit(() -> processItem(item));   // context follows

The same applies to CompletableFuture chains and reactive streams. See context-propagation.md.

Example

See the complete working example: kopai-integration-examples/java

Reference

OpenTelemetry Java

Next

SDK setup is step 3 of six. It gets bytes flowing; it does not make the telemetry good.

  1. Decide what earns a span — instrument-spans.md
  2. Add the context that makes spans answerable — instrument-attributes.md
  3. Instrument the error paths — instrument-errors.md
  4. Drive traffic yourself — drive-traffic.md
  5. Assert on what arrived — validate-traces.md

Confirm before moving on: the SDK starts before any application code that could create a span, and shutdown flushes on SIGTERM (validate-shutdown.md). Both fail silently.

references

_sections.md

architectural-patterns.md

attributes.md

cli-reference.md

context-propagation.md

custom-instrumentation.md

drive-traffic.md

instrument-attributes.md

instrument-errors.md

instrument-spans.md

lang-cpp.md

lang-dotnet.md

lang-erlang.md

lang-fastify.md

lang-go.md

lang-java.md

lang-nextjs.md

lang-nodejs.md

lang-php.md

lang-python.md

lang-ruby.md

lang-rust.md

layered-telemetry.md

nextjs-examples.md

otel-docs.md

sampling.md

setup-backend.md

setup-environment.md

troubleshoot-missing-attrs.md

troubleshoot-missing-spans.md

troubleshoot-no-data.md

troubleshoot-wrong-port.md

validate-logs.md

validate-metrics.md

validate-shutdown.md

validate-traces.md

CHANGELOG.md

SKILL.md

tile.json