Instrumentação Java com Elven Observability
Sumário
- Visão geral
- Pré-requisitos
- Caminho recomendado
- Quick Start — Docker + ENV (zero-code recomendado)
- Pacotes disponíveis
- Quick Start — Java Agent embedded sem Docker
- Quick Start — Java Agent oficial com extensão Elven
- Quick Start — Spring Boot Starter
- Quick Start — Inicialização manual
- Configuração por variáveis de ambiente
- Deploy com Docker — variações
- Logs e correlação com Loki
- Traces manuais, erros e atributos semânticos
- Métricas manuais
- Instrumentações automáticas
- Configuração por arquivo
- Privacidade e dados sensíveis
- Boas práticas para SaaS multi-tenant
- Validação ponta a ponta
- Troubleshooting
- FAQ
Visão geral
A instrumentação Java da Elven é uma distribuição OpenTelemetry para aplicações Java 11+. Ela usa o Java Agent oficial do OpenTelemetry para auto-instrumentação e aplica os padrões da Elven para o stack LGTM.
O Collector OTLP fica sempre no ambiente do cliente. A aplicação envia traces e métricas para esse Collector local/do cliente, e o Collector encaminha os dados para Tempo e Mimir conforme a arquitetura contratada.
- Grafana Tempo para traces
- Grafana Mimir para métricas
- Grafana Loki para logs, via
logs-interceptor-java - Grafana para consulta, correlação, painéis e alertas
┌──────────────────────────────────────────────────────────────┐
│ elven-opentelemetry-instrumentation-java │
│ │
│ ┌───────────────────────┐ ┌─────────────────────────────┐ │
│ │ Java Agent │ │ API manual │ │
│ │ │ │ │ │
│ │ - HTTP server/client │ │ - Observability.init() │ │
│ │ - JDBC / pools │ │ - TracerFacade │ │
│ │ - Messaging │ │ - MetricFacade │ │
│ │ - Frameworks │ │ - LogCorrelation / MDC │ │
│ └───────────┬───────────┘ └──────────────┬──────────────┘ │
│ │ │ │
│ └──────────────┬──────────────┘ │
│ ▼ │
│ OTLP HTTP/protobuf ou gRPC │
└─────────────────────────────┬────────────────────────────────┘
│
▼
Collector OTLP no ambiente do cliente
│
┌─────────┴─────────┐
▼ ▼
Tempo Mimir
Logs da aplicação ── logs-interceptor-java ──► Loki
| Componente | O que faz |
|---|---|
elven-opentelemetry-instrumentation-javaagent |
Java agent embedded: agent oficial + extensão Elven no mesmo JAR. É o modo zero-code mais simples. |
elven-opentelemetry-instrumentation-javaagent-extension |
Extensão Elven para usar junto com o Java agent oficial via OTEL_JAVAAGENT_EXTENSIONS. |
elven-opentelemetry-instrumentation-core |
API manual: Observability, GlobalObservability, TracerFacade, MetricFacade e LogCorrelation. |
elven-opentelemetry-instrumentation-spring-boot-starter |
Auto-configuração para Spring Boot quando a aplicação precisa inicializar a SDK no próprio processo. |
elven-opentelemetry-instrumentation-autoconfigure |
Defaults Elven via SPI do OpenTelemetry SDK. Usado pelo agent e por cenários avançados. |
elven-opentelemetry-instrumentation-bom |
Alinhamento de versões Maven. |
logs-interceptor-java |
Biblioteca separada para envio de logs ao Loki. Esta doc mostra como correlacionar logs com traces. |
Recomendação: para aplicações web, APIs, workers com HTTP/JDBC/messaging e serviços já existentes, use o Java Agent embedded. Ele entrega auto-instrumentação sem alterar o código da aplicação.
Pré-requisitos
- Java 11+
- Maven ou Gradle para aplicações que usam dependências da API manual
- Endpoint do Collector OTLP implantado no ambiente do cliente
- Credenciais da Elven Observability:
- Tenant ID
- API Token
- Endpoint do Collector OTLP do cliente para traces e métricas
- Endpoint Loki para logs, quando usar
logs-interceptor-java
Baseline técnico
| Item | Versão |
|---|---|
| Java mínimo | Java 11 |
| OpenTelemetry SDK BOM | 1.61.0 |
| OpenTelemetry Java Agent | 2.27.0 |
| OpenTelemetry Instrumentation BOM | 2.27.0 |
| Semantic Conventions | 1.41.0 |
| Versão atual da lib Elven | 0.1.1 |
Protocolos suportados
| Protocolo | Valor | Uso recomendado |
|---|---|---|
| OTLP HTTP/protobuf | http/protobuf |
Padrão recomendado para ambientes HTTP, proxies e gateways. |
| OTLP gRPC | grpc |
Útil quando o Collector do cliente aceita gRPC. |
Para métricas, envie OTLP para o Collector do cliente. O Collector faz a tradução para Mimir/Prometheus remote write quando necessário.
Caminho recomendado
A ordem recomendada de adoção é sempre começar pelo caminho de menor atrito:
| Prioridade | Caminho | Quando usar |
|---|---|---|
| 1 | Docker + ENV + Java Agent embedded | Caminho padrão para clientes. Zero-code, previsível e fácil de aplicar em serviços existentes. |
| 2 | JAVA_TOOL_OPTIONS em VM/ECS/serviço já empacotado |
Quando a aplicação não é rebuildada em Docker, mas permite variáveis de ambiente no runtime. |
| 3 | Java Agent oficial + extensão Elven | Quando a empresa já padronizou o opentelemetry-javaagent.jar oficial e quer só acoplar os defaults Elven. |
| 4 | Spring Boot Starter / API manual | Quando a aplicação precisa criar spans/métricas de negócio, controlar lifecycle ou inicializar a SDK por código. |
| 5 | Configuração por arquivo | Quando o ambiente exige arquivo versionado ou montado por secret/config. |
Para a maioria dos clientes, o fluxo é:
1. Adicionar o agent no Dockerfile
2. Configurar OTEL_* e LOGS_* no runtime
3. Subir a imagem
4. Validar traces no Tempo, métricas no Mimir e logs correlacionados no Loki
Quick Start — Docker + ENV (zero-code recomendado)
Este é o caminho padrão para aplicações Java em container. Não exige alteração no código da aplicação.
1. Adicione o Java Agent no Dockerfile
FROM eclipse-temurin:21-jre
WORKDIR /app
RUN mkdir -p /opt/elven <br>
&& curl -fsSL <br>
-o /opt/elven/elven-opentelemetry-instrumentation-javaagent.jar <br>
https://repo1.maven.org/maven2/io/github/elven-observability/elven-opentelemetry-instrumentation-javaagent/0.1.1/elven-opentelemetry-instrumentation-javaagent-0.1.1.jar
COPY target/app.jar /app/app.jar
ENV JAVA_TOOL_OPTIONS="-javaagent:/opt/elven/elven-opentelemetry-instrumentation-javaagent.jar"
ENV OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
ENV OTEL_TRACES_EXPORTER="otlp"
ENV OTEL_METRICS_EXPORTER="otlp"
ENV OTEL_LOGS_EXPORTER="none"
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
2. Configure as variáveis no runtime
docker run --rm -p 8080:8080 <br>
-e OTEL_SERVICE_NAME=checkout-api <br>
-e OTEL_SERVICE_VERSION=1.0.0 <br>
-e OTEL_SERVICE_NAMESPACE=payments <br>
-e OTEL_DEPLOYMENT_ENVIRONMENT=production <br>
-e OTEL_RESOURCE_ATTRIBUTES=team=payments,region=sa-east-1 <br>
-e OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector.sua-infra.com:4318 <br>
-e OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf <br>
-e OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer seu-api-token,X-Scope-OrgID=seu-tenant-id" <br>
-e OTEL_EXPORTER_OTLP_COMPRESSION=gzip <br>
-e OTEL_TRACES_EXPORTER=otlp <br>
-e OTEL_METRICS_EXPORTER=otlp <br>
-e OTEL_LOGS_EXPORTER=none <br>
-e OTEL_TRACES_SAMPLER=parentbased_traceidratio <br>
-e OTEL_TRACES_SAMPLER_ARG=1 <br>
-e OTEL_ELVEN_PRIVACY_REDACT_DB_STATEMENT=true <br>
-e OTEL_ELVEN_PRIVACY_HASH_USER_ID=true <br>
-e OTEL_ELVEN_PRIVACY_REDACT_URL_CREDENTIALS=true <br>
-e OTEL_ELVEN_PRIVACY_REDACT_HEADERS=true <br>
-e OTEL_ELVEN_PRIVACY_REDACT_PAYLOADS=true <br>
minha-api:latest
3. Configure logs quando precisar enviar para Loki
LOGS_URL=https://loki.elvenobservability.com/loki/api/v1/push
LOGS_TENANT=seu-tenant-id
LOGS_TOKEN=seu-api-token
LOGS_APP_NAME=checkout-api
LOGS_APP_VERSION=1.0.0
LOGS_ENVIRONMENT=production
LOGS_COMPRESSION=gzip
A instrumentação Java envia traces e métricas. Logs continuam com o
logs-interceptor-java, mantendo correlação portrace_idespan_id.
4. Valide o startup
No log da aplicação, confirme que o agent iniciou:
opentelemetry-javaagent - version: 2.27.0
Depois gere uma request e valide service.name no Tempo.
Pacotes disponíveis
Maven com BOM
Use o BOM para travar as versões de todos os artefatos Elven:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.elven-observability</groupId>
<artifactId>elven-opentelemetry-instrumentation-bom</artifactId>
<version>0.1.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
API manual
<dependency>
<groupId>io.github.elven-observability</groupId>
<artifactId>elven-opentelemetry-instrumentation-core</artifactId>
</dependency>
Spring Boot Starter
<dependency>
<groupId>io.github.elven-observability</groupId>
<artifactId>elven-opentelemetry-instrumentation-spring-boot-starter</artifactId>
</dependency>
SDK autoconfigure
Use em cenários avançados nos quais a aplicação já usa AutoConfiguredOpenTelemetrySdk:
<dependency>
<groupId>io.github.elven-observability</groupId>
<artifactId>elven-opentelemetry-instrumentation-autoconfigure</artifactId>
</dependency>
Gradle
dependencyManagement {
imports {
mavenBom("io.github.elven-observability:elven-opentelemetry-instrumentation-bom:0.1.1")
}
}
dependencies {
implementation("io.github.elven-observability:elven-opentelemetry-instrumentation-core")
}
Ou sem plugin de dependency management:
dependencies {
implementation(platform("io.github.elven-observability:elven-opentelemetry-instrumentation-bom:0.1.1"))
implementation("io.github.elven-observability:elven-opentelemetry-instrumentation-core")
}
Quick Start — Java Agent embedded sem Docker
Use este modo quando a aplicação roda em VM, ECS task customizada, systemd, serviço gerenciado ou qualquer runtime em que você consegue adicionar arquivos e variáveis de ambiente, mas não quer alterar o Dockerfile.
1. Baixe o agent embedded
mkdir -p /opt/elven
curl -fsSL <br>
-o /opt/elven/elven-opentelemetry-instrumentation-javaagent.jar <br>
https://repo1.maven.org/maven2/io/github/elven-observability/elven-opentelemetry-instrumentation-javaagent/0.1.1/elven-opentelemetry-instrumentation-javaagent-0.1.1.jar
2. Configure as variáveis de ambiente
# === Identidade do serviço ===
export OTEL_SERVICE_NAME="checkout-api"
export OTEL_SERVICE_VERSION="1.0.0"
export OTEL_SERVICE_NAMESPACE="payments"
export OTEL_DEPLOYMENT_ENVIRONMENT="production"
export OTEL_RESOURCE_ATTRIBUTES="team=payments,region=sa-east-1"
# === Export OTLP ===
export OTEL_EXPORTER_OTLP_ENDPOINT="https://otel-collector.sua-infra.com:4318"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer seu-api-token,X-Scope-OrgID=seu-tenant-id"
export OTEL_EXPORTER_OTLP_COMPRESSION="gzip"
# === Sinais ===
export OTEL_TRACES_EXPORTER="otlp"
export OTEL_METRICS_EXPORTER="otlp"
export OTEL_LOGS_EXPORTER="none"
export OTEL_PROPAGATORS="tracecontext,baggage"
# === Sampling ===
export OTEL_TRACES_SAMPLER="parentbased_traceidratio"
export OTEL_TRACES_SAMPLER_ARG="1"
# === Privacy Elven ===
export OTEL_ELVEN_PRIVACY_REDACT_DB_STATEMENT="true"
export OTEL_ELVEN_PRIVACY_HASH_USER_ID="true"
export OTEL_ELVEN_PRIVACY_REDACT_URL_CREDENTIALS="true"
export OTEL_ELVEN_PRIVACY_REDACT_HEADERS="true"
export OTEL_ELVEN_PRIVACY_REDACT_PAYLOADS="true"
3. Inicie a aplicação com JAVA_TOOL_OPTIONS
export JAVA_TOOL_OPTIONS="-javaagent:/opt/elven/elven-opentelemetry-instrumentation-javaagent.jar"
java -jar app.jar
Pronto. A aplicação passa a gerar spans automaticamente para frameworks, HTTP, banco, mensageria e bibliotecas suportadas pelo Java Agent oficial.
Quick Start — Java Agent oficial com extensão Elven
Use este modo quando o ambiente já padroniza o JAR oficial opentelemetry-javaagent.jar e você quer carregar apenas a extensão Elven.
1. Baixe o Java Agent oficial
mkdir -p /opt/otel /opt/elven
curl -fsSL <br>
-o /opt/otel/opentelemetry-javaagent.jar <br>
https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v2.27.0/opentelemetry-javaagent.jar
2. Baixe a extensão Elven
curl -fsSL <br>
-o /opt/elven/elven-opentelemetry-instrumentation-javaagent-extension.jar <br>
https://repo1.maven.org/maven2/io/github/elven-observability/elven-opentelemetry-instrumentation-javaagent-extension/0.1.1/elven-opentelemetry-instrumentation-javaagent-extension-0.1.1-all.jar
3. Configure agent + extensão
export JAVA_TOOL_OPTIONS="-javaagent:/opt/otel/opentelemetry-javaagent.jar"
export OTEL_JAVAAGENT_EXTENSIONS="/opt/elven/elven-opentelemetry-instrumentation-javaagent-extension.jar"
export OTEL_SERVICE_NAME="checkout-api"
export OTEL_EXPORTER_OTLP_ENDPOINT="https://otel-collector.sua-infra.com:4318"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer seu-api-token,X-Scope-OrgID=seu-tenant-id"
export OTEL_TRACES_EXPORTER="otlp"
export OTEL_METRICS_EXPORTER="otlp"
export OTEL_LOGS_EXPORTER="none"
java -jar app.jar
Use um formato de agent por processo: embedded ou oficial + extensão. Não combine os dois no mesmo
JAVA_TOOL_OPTIONS.
Quick Start — Spring Boot Starter
Use o starter quando você quer inicializar a SDK no processo da aplicação via Spring Boot.
Para auto-instrumentação profunda de HTTP/JDBC/frameworks, o Java Agent continua sendo o modo recomendado. O starter é útil para aplicações que preferem bootstrap explícito, custom spans, custom metrics e lifecycle integrado ao contexto Spring.
1. Adicione o BOM e o starter
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.elven-observability</groupId>
<artifactId>elven-opentelemetry-instrumentation-bom</artifactId>
<version>0.1.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.elven-observability</groupId>
<artifactId>elven-opentelemetry-instrumentation-spring-boot-starter</artifactId>
</dependency>
</dependencies>
2. Configure o ambiente
export OTEL_SERVICE_NAME="billing-api"
export OTEL_SERVICE_VERSION="1.0.0"
export OTEL_DEPLOYMENT_ENVIRONMENT="production"
export OTEL_EXPORTER_OTLP_ENDPOINT="https://otel-collector.sua-infra.com:4318"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer seu-api-token,X-Scope-OrgID=seu-tenant-id"
export OTEL_TRACES_EXPORTER="otlp"
export OTEL_METRICS_EXPORTER="otlp"
export OTEL_LOGS_EXPORTER="none"
3. Injete ObservabilityHandle quando precisar de spans ou métricas manuais
package com.acme.billing;
import io.github.elvenobservability.opentelemetry.instrumentation.api.ObservabilityHandle;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributeKey;
import org.springframework.stereotype.Service;
@Service
public class BillingService {
private final ObservabilityHandle observability;
public BillingService(ObservabilityHandle observability) {
this.observability = observability;
}
public void closeInvoice(String invoiceId) {
observability.tracer().withSpan("invoice.close", span -> {
span.setAttribute("invoice.id", invoiceId);
observability.metrics().increment(
"billing_invoice_closed_total",
1,
Attributes.of(AttributeKey.stringKey("status"), "success"));
});
}
}
4. Configuração Spring opcional
elven:
otel:
enabled: true
shutdown-on-context-close: true
Variáveis equivalentes:
ELVEN_OTEL_ENABLED=true
ELVEN_OTEL_SHUTDOWN_ON_CONTEXT_CLOSE=true
Quick Start — Inicialização manual
Use este modo para jobs, aplicações console, serviços sem Spring ou cenários em que você precisa controlar a inicialização por código.
1. Adicione a dependência
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.elven-observability</groupId>
<artifactId>elven-opentelemetry-instrumentation-bom</artifactId>
<version>0.1.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.elven-observability</groupId>
<artifactId>elven-opentelemetry-instrumentation-core</artifactId>
</dependency>
</dependencies>
2. Inicialize a partir das variáveis de ambiente
import io.github.elvenobservability.opentelemetry.instrumentation.api.Observability;
import io.github.elvenobservability.opentelemetry.instrumentation.api.ObservabilityHandle;
public final class Main {
public static void main(String[] args) {
ObservabilityHandle handle = Observability.initFromEnv();
try {
handle.tracer().withSpan("job.run", span -> {
span.setAttribute("job.name", "daily-close");
handle.metrics().increment("jobs_started_total", 1);
});
handle.forceFlush().toCompletableFuture().join();
} finally {
handle.shutdown().toCompletableFuture().join();
}
}
}
3. Ou inicialize com builder explícito
import io.github.elvenobservability.opentelemetry.instrumentation.api.Observability;
import io.github.elvenobservability.opentelemetry.instrumentation.api.ObservabilityHandle;
import io.github.elvenobservability.opentelemetry.instrumentation.config.ExporterConfig;
import io.github.elvenobservability.opentelemetry.instrumentation.config.MetricsConfig;
import io.github.elvenobservability.opentelemetry.instrumentation.config.ObservabilityConfig;
import io.github.elvenobservability.opentelemetry.instrumentation.config.PrivacyConfig;
import io.github.elvenobservability.opentelemetry.instrumentation.config.ServiceConfig;
import io.github.elvenobservability.opentelemetry.instrumentation.config.TracingConfig;
import java.time.Duration;
ObservabilityHandle handle = Observability.init(
ObservabilityConfig.builder()
.service(ServiceConfig.builder()
.serviceName("checkout-worker")
.serviceVersion("1.0.0")
.serviceNamespace("payments")
.deploymentEnvironment("production")
.attribute("team", "payments")
.attribute("region", "sa-east-1")
.build())
.exporters(ExporterConfig.builder()
.endpoint("https://otel-collector.sua-infra.com:4318")
.protocol("http/protobuf")
.header("Authorization", "Bearer seu-api-token")
.header("X-Scope-OrgID", "seu-tenant-id")
.compression("gzip")
.timeout(Duration.ofSeconds(30))
.build())
.tracing(TracingConfig.builder()
.enabled(true)
.ratio(1.0d)
.build())
.metrics(MetricsConfig.builder()
.enabled(true)
.exportInterval(Duration.ofSeconds(60))
.build())
.privacy(PrivacyConfig.builder()
.redactDbStatement(true)
.hashUserId(true)
.redactUrlCredentials(true)
.redactHeaders(true)
.redactPayloads(true)
.build())
.autoShutdown(true)
.build());
Precedência de configuração
A resolução segue esta ordem:
Builder explícito > Java system property > variável de ambiente > arquivo opcional > default da lib
Exemplo com system properties:
java <br>
-Dotel.service.name=checkout-api <br>
-Dotel.exporter.otlp.endpoint=https://otel-collector.sua-infra.com:4318 <br>
-jar app.jar
Configuração por variáveis de ambiente
Identidade do serviço
| Variável | Descrição | Default |
|---|---|---|
OTEL_SERVICE_NAME |
Nome do serviço. Deve ser estável e único por aplicação. | unknown-service |
OTEL_SERVICE_VERSION |
Versão da aplicação. | 0.0.0 |
OTEL_SERVICE_NAMESPACE |
Domínio, produto ou agrupador lógico. | — |
OTEL_DEPLOYMENT_ENVIRONMENT |
Ambiente: production, staging, development. |
— |
OTEL_RESOURCE_ATTRIBUTES |
Atributos extras no formato key=value,key2=value2. |
— |
Exemplo:
OTEL_SERVICE_NAME=checkout-api
OTEL_SERVICE_VERSION=1.8.3
OTEL_SERVICE_NAMESPACE=payments
OTEL_DEPLOYMENT_ENVIRONMENT=production
OTEL_RESOURCE_ATTRIBUTES=team=payments,region=sa-east-1,product=checkout
Export OTLP
| Variável | Descrição | Default |
|---|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT |
Endpoint base OTLP. Em HTTP/protobuf, a lib deriva /v1/traces e /v1/metrics. |
http://localhost:4318 |
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT |
Endpoint específico de traces. | Derivado do endpoint base |
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT |
Endpoint específico de métricas. | Derivado do endpoint base |
OTEL_EXPORTER_OTLP_PROTOCOL |
http/protobuf ou grpc. |
http/protobuf |
OTEL_EXPORTER_OTLP_HEADERS |
Headers em key=value,key2=value2. |
— |
OTEL_EXPORTER_OTLP_COMPRESSION |
gzip ou none. |
none na API manual; gzip pode ser definido no ambiente |
OTEL_EXPORTER_OTLP_TIMEOUT |
Timeout em milissegundos. | 30000 |
OTEL_EXPORTER_OTLP_INSECURE |
Permitir transporte inseguro em gRPC quando aplicável. | false |
Sinais
| Variável | Descrição | Default |
|---|---|---|
OTEL_TRACES_EXPORTER |
Exporter de traces: otlp, console ou none. |
otlp |
OTEL_METRICS_EXPORTER |
Exporter de métricas: otlp, console ou none. |
otlp |
OTEL_LOGS_EXPORTER |
Exporter de logs OpenTelemetry. | none |
OTEL_TRACING_ENABLED |
Liga/desliga tracing na API manual. | Conforme exporter |
OTEL_METRICS_ENABLED |
Liga/desliga métricas na API manual. | Conforme exporter |
A lib Java da Elven não exporta logs via OpenTelemetry. Logs devem ser enviados pelo
logs-interceptor-javaou pela pipeline de logs da aplicação.
Sampling e propagação
| Variável | Descrição | Default |
|---|---|---|
OTEL_PROPAGATORS |
Propagadores de contexto. | tracecontext,baggage |
OTEL_TRACES_SAMPLER |
Sampler de traces. | parentbased_traceidratio |
OTEL_TRACES_SAMPLER_ARG |
Taxa de sampling entre 0.0 e 1.0. |
1 |
OTEL_METRIC_EXPORT_INTERVAL |
Intervalo de export de métricas em ms. | 60000 |
OTEL_METRIC_EXPORT_TIMEOUT |
Timeout de export de métricas em ms. | 30000 |
Exemplos:
# 100% dos traces
OTEL_TRACES_SAMPLER=parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG=1
# 10% dos traces
OTEL_TRACES_SAMPLER=parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG=0.1
Privacy Elven
| Variável | Descrição | Default |
|---|---|---|
OTEL_ELVEN_PRIVACY_REDACT_DB_STATEMENT |
Redactar db.statement e texto de queries por padrão. |
true |
OTEL_ELVEN_PRIVACY_HASH_USER_ID |
Converter identidade de usuário para hash/pseudônimo. | true |
OTEL_ELVEN_PRIVACY_REDACT_URL_CREDENTIALS |
Remover credenciais e segredos de URLs. | true |
OTEL_ELVEN_PRIVACY_REDACT_HEADERS |
Redactar headers sensíveis. | true |
OTEL_ELVEN_PRIVACY_REDACT_PAYLOADS |
Redactar atributos com payloads/mensagens sensíveis. | true |
OTEL_ELVEN_PRIVACY_ALLOW_RAW_ATTRIBUTES |
Lista de atributos que podem sair sem redaction. | — |
OTEL_ELVEN_AUTO_SHUTDOWN |
Registrar shutdown hook automático. | true |
OTEL_ELVEN_CONFIG_FILE |
Caminho de arquivo .properties, .yaml ou .yml. |
— |
Exemplo para uma investigação temporária de SQL:
OTEL_ELVEN_PRIVACY_REDACT_DB_STATEMENT=false
OTEL_ELVEN_PRIVACY_ALLOW_RAW_ATTRIBUTES=db.statement,db.query.text
Use allowlist de atributos crus apenas por tempo limitado e com aprovação do time responsável por segurança/dados.
Java Agent
| Variável | Descrição |
|---|---|
JAVA_TOOL_OPTIONS |
Injeta -javaagent:/path/agent.jar sem alterar o comando original da aplicação. |
OTEL_JAVAAGENT_EXTENSIONS |
Caminho do JAR de extensão quando usar o agent oficial. |
OTEL_JAVAAGENT_DEBUG |
Habilita debug do Java Agent. Use apenas em troubleshooting. |
OTEL_JAVAAGENT_LOGGING |
Estratégia de logs internos do agent. Padrão Elven: simple. |
OTEL_INSTRUMENTATION_COMMON_DEFAULT_ENABLED |
Liga/desliga instrumentações por padrão. |
OTEL_INSTRUMENTATION_<NOME>_ENABLED |
Liga/desliga uma instrumentação específica do agent. |
Exemplos:
OTEL_INSTRUMENTATION_JDBC_ENABLED=true
OTEL_INSTRUMENTATION_KAFKA_ENABLED=true
OTEL_INSTRUMENTATION_REDIS_ENABLED=true
OTEL_INSTRUMENTATION_COMMON_DEFAULT_ENABLED=true
Deploy com Docker — variações
Dockerfile — app com JAR pronto
FROM eclipse-temurin:21-jre
WORKDIR /app
RUN mkdir -p /opt/elven <br>
&& curl -fsSL <br>
-o /opt/elven/elven-opentelemetry-instrumentation-javaagent.jar <br>
https://repo1.maven.org/maven2/io/github/elven-observability/elven-opentelemetry-instrumentation-javaagent/0.1.1/elven-opentelemetry-instrumentation-javaagent-0.1.1.jar
COPY target/app.jar /app/app.jar
ENV JAVA_TOOL_OPTIONS="-javaagent:/opt/elven/elven-opentelemetry-instrumentation-javaagent.jar"
ENV OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
ENV OTEL_TRACES_EXPORTER="otlp"
ENV OTEL_METRICS_EXPORTER="otlp"
ENV OTEL_LOGS_EXPORTER="none"
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
Credenciais e endpoints devem entrar no runtime, nunca hardcoded no Dockerfile:
docker run --rm -p 8080:8080 <br>
-e OTEL_SERVICE_NAME=checkout-api <br>
-e OTEL_SERVICE_VERSION=1.0.0 <br>
-e OTEL_DEPLOYMENT_ENVIRONMENT=production <br>
-e OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector.sua-infra.com:4318 <br>
-e OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer seu-api-token,X-Scope-OrgID=seu-tenant-id" <br>
minha-api:latest
Dockerfile multi-stage com Maven
FROM maven:3.9.12-eclipse-temurin-21 AS build
WORKDIR /build
COPY pom.xml .
COPY src ./src
RUN mvn -B -ntp package -DskipTests
FROM eclipse-temurin:21-jre
WORKDIR /app
RUN mkdir -p /opt/elven <br>
&& curl -fsSL <br>
-o /opt/elven/elven-opentelemetry-instrumentation-javaagent.jar <br>
https://repo1.maven.org/maven2/io/github/elven-observability/elven-opentelemetry-instrumentation-javaagent/0.1.1/elven-opentelemetry-instrumentation-javaagent-0.1.1.jar
COPY --from=build /build/target/*.jar /app/app.jar
ENV JAVA_TOOL_OPTIONS="-javaagent:/opt/elven/elven-opentelemetry-instrumentation-javaagent.jar"
ENV OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
ENV OTEL_TRACES_EXPORTER="otlp"
ENV OTEL_METRICS_EXPORTER="otlp"
ENV OTEL_LOGS_EXPORTER="none"
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
Dockerfile usando Maven para copiar o agent
Útil quando o build já usa Maven e você quer evitar URLs no Dockerfile:
FROM maven:3.9.12-eclipse-temurin-21 AS agent
RUN mkdir -p /opt/elven <br>
&& mvn -B -ntp dependency:copy <br>
-Dartifact=io.github.elven-observability:elven-opentelemetry-instrumentation-javaagent:0.1.1:jar <br>
-DoutputDirectory=/opt/elven <br>
-Dmdep.stripVersion=true
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY --from=agent /opt/elven/elven-opentelemetry-instrumentation-javaagent.jar /opt/elven/elven-opentelemetry-instrumentation-javaagent.jar
COPY target/app.jar /app/app.jar
ENV JAVA_TOOL_OPTIONS="-javaagent:/opt/elven/elven-opentelemetry-instrumentation-javaagent.jar"
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
docker-compose.yml
services:
checkout-api:
image: minha-api:latest
ports:
- "8080:8080"
environment:
# Identidade
OTEL_SERVICE_NAME: checkout-api
OTEL_SERVICE_VERSION: "1.0.0"
OTEL_SERVICE_NAMESPACE: payments
OTEL_DEPLOYMENT_ENVIRONMENT: production
OTEL_RESOURCE_ATTRIBUTES: team=payments,region=sa-east-1,product=checkout
# OTLP
OTEL_EXPORTER_OTLP_ENDPOINT: https://otel-collector.sua-infra.com:4318
OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf
OTEL_EXPORTER_OTLP_HEADERS: Authorization=Bearer seu-api-token,X-Scope-OrgID=seu-tenant-id
OTEL_EXPORTER_OTLP_COMPRESSION: gzip
# Sinais
OTEL_TRACES_EXPORTER: otlp
OTEL_METRICS_EXPORTER: otlp
OTEL_LOGS_EXPORTER: none
OTEL_TRACES_SAMPLER: parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG: "1"
# Privacy
OTEL_ELVEN_PRIVACY_REDACT_DB_STATEMENT: "true"
OTEL_ELVEN_PRIVACY_HASH_USER_ID: "true"
OTEL_ELVEN_PRIVACY_REDACT_URL_CREDENTIALS: "true"
OTEL_ELVEN_PRIVACY_REDACT_HEADERS: "true"
OTEL_ELVEN_PRIVACY_REDACT_PAYLOADS: "true"
# Logs via logs-interceptor-java
LOGS_URL: https://loki.elvenobservability.com/loki/api/v1/push
LOGS_TENANT: seu-tenant-id
LOGS_TOKEN: seu-api-token
LOGS_APP_NAME: checkout-api
LOGS_APP_VERSION: "1.0.0"
LOGS_ENVIRONMENT: production
Logs e correlação com Loki
Esta lib não cria pipeline de exportação de logs OpenTelemetry. Ela fornece correlação com trace_id, span_id e trace_flags, para que os logs enviados ao Loki possam ser relacionados com traces no Tempo.
Use logs-interceptor-java para envio ao Loki.
Dependências de logs
Exemplo com Logback:
<properties>
<logs-interceptor-java.version>VERSAO_PUBLICADA_DA_LIB_DE_LOGS</logs-interceptor-java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.elvenobservability</groupId>
<artifactId>logs-interceptor-bom</artifactId>
<version>${logs-interceptor-java.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.elvenobservability</groupId>
<artifactId>logs-interceptor-core</artifactId>
</dependency>
<dependency>
<groupId>io.github.elvenobservability</groupId>
<artifactId>logs-interceptor-transport-loki</artifactId>
</dependency>
<dependency>
<groupId>io.github.elvenobservability</groupId>
<artifactId>logs-interceptor-adapter-logback</artifactId>
</dependency>
</dependencies>
Substitua VERSAO_PUBLICADA_DA_LIB_DE_LOGS pela versão vigente do logs-interceptor-java disponibilizada pela Elven no gerenciador de pacotes usado pelo cliente.
Variáveis de logs
LOGS_URL=https://loki.elvenobservability.com/loki/api/v1/push
LOGS_TENANT=seu-tenant-id
LOGS_TOKEN=seu-api-token
LOGS_APP_NAME=checkout-api
LOGS_APP_VERSION=1.0.0
LOGS_ENVIRONMENT=production
LOGS_COMPRESSION=gzip
LOGS_LABEL_TEAM=payments
LOGS_LABEL_REGION=sa-east-1
Correlação manual com MDC
import io.github.elvenobservability.opentelemetry.instrumentation.context.LogCorrelation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(CheckoutService.class);
handle.tracer().withSpan("checkout.process", span -> {
try (AutoCloseable ignored = LogCorrelation.putMdc()) {
span.setAttribute("checkout.id", "chk_123");
logger.info("checkout processado");
} catch (Exception ex) {
handle.tracer().recordException(span, ex);
throw new RuntimeException(ex);
}
});
Pattern Logback local
Mesmo quando o envio ao Loki é feito por appender dedicado, manter trace_id e span_id no console ajuda no troubleshooting:
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} %-5level [%thread] trace_id=%X{trace_id} span_id=%X{span_id} %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
Como a correlação aparece
Um log correlacionado deve carregar:
{
"message": "checkout processado",
"trace_id": "313549e4a83129bc6065bb38a24a79f0",
"span_id": "6065bb38a24a79f0",
"service_name": "checkout-api",
"environment": "production"
}
No Grafana, use trace_id para navegar de Loki para Tempo.
Traces manuais, erros e atributos semânticos
O Java Agent cria spans automaticamente para bibliotecas suportadas. Use a API manual para eventos de negócio e spans que só a aplicação conhece.
Span simples
handle.tracer().withSpan("order.approve", span -> {
span.setAttribute("order.id", "ord_123");
span.setAttribute("order.amount_cents", 15990);
span.setAttribute("payment.provider", "acquirer-a");
});
Registrar exceções
handle.tracer().withSpan("payment.capture", span -> {
try {
paymentGateway.capture();
span.setAttribute("payment.status", "captured");
} catch (RuntimeException ex) {
handle.tracer().recordException(span, ex);
throw ex;
}
});
O helper recordException() adiciona:
- evento de exception no span
- status
ERROR - atributo
error.type
Usuário final com privacidade
Prefira enduser.pseudo.id em vez de enduser.id.
handle.tracer().withSpan("user.checkout", span -> {
handle.tracer().setPseudonymousUserId(span, user.getId());
});
Isso gera um identificador pseudonimizado, adequado para correlação sem expor o ID bruto do usuário.
Quando usar atributos crus
Evite:
span.setAttribute("enduser.id", user.getId());
span.setAttribute("user.email", user.getEmail());
Use apenas quando houver política explícita e allowlist:
OTEL_ELVEN_PRIVACY_ALLOW_RAW_ATTRIBUTES=enduser.id
Métricas manuais
Use métricas manuais para indicadores de negócio, filas, batches e estados internos que não aparecem automaticamente.
Counter
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributeKey;
handle.metrics().increment(
"checkout_requests_total",
1,
Attributes.of(
AttributeKey.stringKey("status"), "success",
AttributeKey.stringKey("payment_method"), "credit_card"));
Histogram
handle.metrics().recordHistogram(
"checkout_duration_ms",
durationMillis,
Attributes.of(AttributeKey.stringKey("route"), "/checkout"));
UpDownCounter
handle.metrics().addUpDown(
"queue_inflight_jobs",
1,
Attributes.of(AttributeKey.stringKey("queue"), "payments"));
Gauge
handle.metrics().setGauge(
"worker_pool_usage_ratio",
0.82,
Attributes.of(AttributeKey.stringKey("pool"), "default"));
Cuidados de cardinalidade
Evite labels com alta cardinalidade:
// Evite em métricas:
AttributeKey.stringKey("user_id")
AttributeKey.stringKey("request_id")
AttributeKey.stringKey("order_id")
AttributeKey.stringKey("trace_id")
Prefira labels com cardinalidade controlada:
status
method
route
region
team
queue
payment_provider
Instrumentações automáticas
O Java Agent oficial instrumenta automaticamente bibliotecas e frameworks comuns. A lista exata evolui com o OpenTelemetry Java Agent, mas os grupos mais importantes são:
| Categoria | Exemplos |
|---|---|
| HTTP server | Servlet, Spring MVC, Spring WebFlux, JAX-RS, Jetty, Tomcat, Undertow, Netty |
| HTTP client | Java HttpClient, Apache HttpClient, OkHttp, Spring RestTemplate, WebClient |
| Banco de dados | JDBC, HikariCP, PostgreSQL, MySQL, MariaDB, Oracle, SQL Server |
| Messaging | Kafka, RabbitMQ, JMS, AWS SQS/SNS em bibliotecas suportadas |
| Cache/datastores | Redis, MongoDB, Cassandra, Elasticsearch em versões suportadas |
| Frameworks | Spring Boot, Micronaut, Quarkus, Dropwizard em cenários suportados |
| Logging | Correlação com frameworks suportados pelo agent e MDC quando aplicável |
| GraphQL | GraphQL Java em versões suportadas pelo agent |
Habilitar/desabilitar instrumentações
# Todas habilitadas por padrão
OTEL_INSTRUMENTATION_COMMON_DEFAULT_ENABLED=true
# Desabilitar uma instrumentação específica
OTEL_INSTRUMENTATION_KAFKA_ENABLED=false
# Habilitar explicitamente JDBC
OTEL_INSTRUMENTATION_JDBC_ENABLED=true
SQL statements
Por padrão, a Elven aplica redaction em statements SQL:
OTEL_ELVEN_PRIVACY_REDACT_DB_STATEMENT=true
Para investigar um problema específico, habilite temporariamente:
OTEL_ELVEN_PRIVACY_REDACT_DB_STATEMENT=false
OTEL_ELVEN_PRIVACY_ALLOW_RAW_ATTRIBUTES=db.statement,db.query.text
Volte para o padrão seguro ao terminar a análise.
Configuração por arquivo
Além de variáveis de ambiente e system properties, a API manual aceita arquivo .properties, .yaml ou .yml.
Usando variável
OTEL_ELVEN_CONFIG_FILE=/etc/elven/otel.yaml
Usando builder
ObservabilityHandle handle = Observability.init(
ObservabilityConfig.builder()
.configFile("/etc/elven/otel.yaml")
.build());
Exemplo .properties
otel.service.name=checkout-api
otel.service.version=1.0.0
otel.service.namespace=payments
otel.deployment.environment=production
otel.resource.attributes=team=payments,region=sa-east-1
otel.exporter.otlp.endpoint=https://otel-collector.sua-infra.com:4318
otel.exporter.otlp.protocol=http/protobuf
otel.exporter.otlp.headers=Authorization=Bearer seu-api-token,X-Scope-OrgID=seu-tenant-id
otel.exporter.otlp.compression=gzip
otel.traces.exporter=otlp
otel.metrics.exporter=otlp
otel.logs.exporter=none
otel.traces.sampler=parentbased_traceidratio
otel.traces.sampler.arg=1
otel.elven.privacy.redact.db.statement=true
otel.elven.privacy.hash.user.id=true
otel.elven.privacy.redact.url.credentials=true
otel.elven.privacy.redact.headers=true
otel.elven.privacy.redact.payloads=true
Exemplo .yaml
otel.service.name: checkout-api
otel.service.version: 1.0.0
otel.service.namespace: payments
otel.deployment.environment: production
otel.resource.attributes: team=payments,region=sa-east-1
otel.exporter.otlp.endpoint: https://otel-collector.sua-infra.com:4318
otel.exporter.otlp.protocol: http/protobuf
otel.exporter.otlp.headers: Authorization=Bearer seu-api-token,X-Scope-OrgID=seu-tenant-id
otel.exporter.otlp.compression: gzip
otel.traces.exporter: otlp
otel.traces.sampler: parentbased_traceidratio
otel.traces.sampler.arg: 1
otel.metrics.exporter: otlp
otel.logs.exporter: none
otel.elven.privacy.redact.db.statement: true
otel.elven.privacy.hash.user.id: true
otel.elven.privacy.redact.url.credentials: true
otel.elven.privacy.redact.headers: true
otel.elven.privacy.redact.payloads: true
Privacidade e dados sensíveis
Os defaults da Elven são privacy-first. A instrumentação assume que aplicações podem carregar dados pessoais, tokens, cookies, queries sensíveis e payloads de negócio.
Redactado por padrão
db.statementdb.query.text- credenciais em URL
- query params com tokens/secrets
- headers de autenticação
- cookies
- payloads e atributos com aparência de corpo de mensagem
user.ideenduser.idvindos de dependências legadas ou customizadas
Identidade de usuário
Use:
enduser.pseudo.id
Evite:
enduser.id
user.id
user.email
Permitir atributo cru
OTEL_ELVEN_PRIVACY_ALLOW_RAW_ATTRIBUTES=enduser.id,db.statement
Use somente em ambientes controlados ou janelas curtas de diagnóstico.
Headers
Nunca coloque tokens diretamente em OTEL_RESOURCE_ATTRIBUTES. Para autenticação OTLP, use:
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer seu-api-token,X-Scope-OrgID=seu-tenant-id"
E mantenha esses valores em secret manager, variável segura do runtime ou ferramenta equivalente.
Boas práticas para SaaS multi-tenant
Identidade do serviço
Use nomes estáveis:
{dominio}-{componente}
Exemplos:
auth-api
billing-worker
checkout-api
notifications-scheduler
Tenant routing
O roteamento de tenant deve ficar no header do transporte ou no Collector do cliente:
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer seu-api-token,X-Scope-OrgID=tenant-a"
Atributos de tenant
Para spans, use atributos de tenant apenas quando eles forem necessários para investigação:
span.setAttribute("tenant.id", "tenant-a");
span.setAttribute("tenant.plan", "enterprise");
Para métricas, tenha cuidado redobrado. tenant.id como label pode explodir cardinalidade em SaaS com muitos clientes.
Prefira métricas agregadas por dimensões controladas:
plan
region
service.namespace
deployment.environment
status
Logs
No Loki, labels devem ser de baixa cardinalidade:
LOGS_LABEL_TEAM=payments
LOGS_LABEL_ENVIRONMENT=production
LOGS_LABEL_REGION=sa-east-1
Evite labels como:
LOGS_LABEL_USER_ID=...
LOGS_LABEL_REQUEST_ID=...
LOGS_LABEL_TRACE_ID=...
LOGS_LABEL_ORDER_ID=...
Esses valores devem ir no corpo do log, não como label indexado.
Sampling
Para serviços críticos ou baixo volume:
OTEL_TRACES_SAMPLER_ARG=1
Para alto volume:
OTEL_TRACES_SAMPLER_ARG=0.1
Em incidentes, aumente temporariamente a taxa do serviço afetado.
Validação ponta a ponta
1. Verifique o log de startup
Com Java Agent, procure por mensagens indicando que o agent iniciou:
opentelemetry-javaagent - version: 2.27.0
Se OTEL_JAVAAGENT_DEBUG=true, o agent mostra mais detalhes das instrumentações carregadas.
2. Gere tráfego
curl -i http://localhost:8080/health
curl -i http://localhost:8080/api/checkout
3. Verifique traces
No Grafana Tempo:
- filtre por
service.name="checkout-api" - confirme spans HTTP server/client
- confirme spans JDBC ou messaging quando a aplicação usar essas bibliotecas
- abra erros e confirme exception events
4. Verifique métricas
No Grafana/Mimir:
- procure métricas runtime/processo geradas pelo agent
- procure métricas manuais criadas por
MetricFacade - valide labels de baixa cardinalidade
Exemplos de nomes manuais:
checkout_requests_total
checkout_duration_ms
queue_inflight_jobs
worker_pool_usage_ratio
5. Verifique logs correlacionados
No Loki:
{app="checkout-api"} |= "trace_id"
Depois copie o trace_id e procure o trace correspondente no Tempo.
6. Valide redaction
Confirme que dados sensíveis não aparecem crus:
- tokens em URL devem aparecer como redigidos
- headers de auth não devem aparecer em claro
db.statementdeve estar redigido quandoOTEL_ELVEN_PRIVACY_REDACT_DB_STATEMENT=true- IDs de usuário devem aparecer como
enduser.pseudo.id, nãoenduser.id
Troubleshooting
Traces não aparecem
- Confirme que o agent está carregado:
bash
echo "$JAVA_TOOL_OPTIONS"
2. Verifique se existe -javaagent:/caminho/agent.jar.
3. Confirme OTEL_SERVICE_NAME.
4. Confirme OTEL_TRACES_EXPORTER=otlp.
5. Confirme OTEL_EXPORTER_OTLP_ENDPOINT ou OTEL_EXPORTER_OTLP_TRACES_ENDPOINT.
6. Verifique headers:
bash
echo "$OTEL_EXPORTER_OTLP_HEADERS"
7. Habilite debug temporariamente:
bash
OTEL_JAVAAGENT_DEBUG=true
Métricas não aparecem
- Confirme
OTEL_METRICS_EXPORTER=otlp. - Confirme que o endpoint OTLP aceita
/v1/metrics. - Verifique
OTEL_METRIC_EXPORT_INTERVAL; o default é60000ms. - Confirme que o Collector do cliente encaminha métricas para Mimir.
- Evite testar e encerrar a aplicação antes do primeiro ciclo de export. Para jobs curtos, chame
forceFlush()antes de finalizar.
Logs não aparecem no Loki
- Confirme que
logs-interceptor-javaestá instalado/configurado. - Confirme as variáveis:
bash
LOGS_URL
LOGS_TENANT
LOGS_TOKEN
LOGS_APP_NAME
3. Confirme que a aplicação realmente emite logs.
4. Confirme que o appender/agent de logs está ativo.
5. Se traces aparecem mas logs não, o problema está na pipeline de logs, não na instrumentação OpenTelemetry.
Logs aparecem sem trace_id
- Confirme que o log foi emitido dentro de um span ativo.
- Em spans manuais, use:
java
try (AutoCloseable ignored = LogCorrelation.putMdc()) {
logger.info("mensagem correlacionada");
}
3. Confirme que o pattern/appender captura MDC.
4. Em chamadas assíncronas, confirme que o contexto OpenTelemetry está sendo propagado para a thread.
JDBC não gera spans
- Confirme que a aplicação está rodando com Java Agent.
- Confirme que a dependência JDBC está em versão suportada pelo agent.
- Confirme que a conexão passa por
java.sql/JDBC ou pool suportado. - Verifique se a instrumentação foi desabilitada:
bash
OTEL_INSTRUMENTATION_JDBC_ENABLED=false
5. Habilite debug temporariamente para ver decisões do agent.
db.statement não aparece
Por padrão, a Elven redacta SQL para evitar vazamento de dados.
Para diagnóstico temporário:
OTEL_ELVEN_PRIVACY_REDACT_DB_STATEMENT=false
OTEL_ELVEN_PRIVACY_ALLOW_RAW_ATTRIBUTES=db.statement,db.query.text
Depois volte:
OTEL_ELVEN_PRIVACY_REDACT_DB_STATEMENT=true
OTEL_ELVEN_PRIVACY_ALLOW_RAW_ATTRIBUTES=
Erro de endpoint OTLP inválido
Sintomas comuns:
[instrumentation-java] Invalid OTLP traces endpoint
[instrumentation-java] Invalid OTLP metrics endpoint
Verifique:
OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector.sua-infra.com:4318
O endpoint precisa ter scheme e host (http:// ou https://).
Erro em headers OTLP
Formato correto:
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer seu-api-token,X-Scope-OrgID=seu-tenant-id"
Formato inválido:
OTEL_EXPORTER_OTLP_HEADERS="Authorization Bearer token"
Cada item precisa estar no formato key=value.
Sampling inválido
OTEL_TRACES_SAMPLER_ARG precisa estar entre 0.0 e 1.0:
OTEL_TRACES_SAMPLER_ARG=0.25
Valores como 25, 100 ou -1 são inválidos.
Aplicação não inicia com agent
- Confirme que o JAR existe:
bash
ls -lh /opt/elven/elven-opentelemetry-instrumentation-javaagent.jar
2. Confirme permissão de leitura.
3. Confirme que a imagem usa Java 11+.
4. Confirme que há apenas um -javaagent OpenTelemetry no processo.
5. Rode localmente com debug:
bash
JAVA_TOOL_OPTIONS="-javaagent:/opt/elven/elven-opentelemetry-instrumentation-javaagent.jar" <br>
OTEL_JAVAAGENT_DEBUG=true <br>
java -jar app.jar
Duplicate SDK setup
Se a aplicação já registra GlobalOpenTelemetry, a API manual reutiliza a instância global quando possível. Evite inicializar múltiplas SDKs no mesmo processo.
Boas práticas:
- com Java Agent, não chame outro bootstrap OpenTelemetry concorrente
- com Spring Boot Starter, deixe apenas um bean
ObservabilityHandle - em testes, isole processos ou use reset apenas em contexto de teste
FAQ
Preciso alterar código para usar a lib?
Não no modo Java Agent embedded. Basta adicionar o JAR e configurar JAVA_TOOL_OPTIONS + variáveis de ambiente.
A lib envia logs para Loki?
Não diretamente. Ela configura traces, métricas e correlação de logs. Para envio de logs ao Loki, use logs-interceptor-java.
Posso usar só a API manual sem Java Agent?
Sim. Nesse modo você consegue criar spans e métricas manuais, configurar SDK e exportar OTLP. Para auto-instrumentação completa de HTTP, JDBC e frameworks, use o Java Agent.
Posso usar Java Agent e Spring Boot Starter juntos?
Pode, mas normalmente não é necessário. Em aplicações Spring Boot, prefira:
- Java Agent para auto-instrumentação zero-code
- Starter/API manual apenas quando precisar de
ObservabilityHandle, spans manuais ou métricas manuais
Evite criar duas SDKs OpenTelemetry concorrentes.
Qual endpoint devo usar?
Na maioria dos ambientes, use o endpoint do Collector OTLP implantado no cliente:
OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector.sua-infra.com:4318
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
Se usar endpoints separados:
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://otel-collector.sua-infra.com:4318/v1/traces
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://otel-collector.sua-infra.com:4318/v1/metrics
Como vejo SQL statements?
Por padrão eles são redigidos. Para diagnóstico temporário:
OTEL_ELVEN_PRIVACY_REDACT_DB_STATEMENT=false
OTEL_ELVEN_PRIVACY_ALLOW_RAW_ATTRIBUTES=db.statement,db.query.text
Use com cuidado e volte ao padrão seguro depois.
Como correlaciono Loki e Tempo?
Garanta que logs tenham trace_id e span_id.
Com spans manuais, use:
try (AutoCloseable ignored = LogCorrelation.putMdc()) {
logger.info("evento correlacionado");
}
Com logs-interceptor-java, o MDC é enviado junto no corpo do log.
Qual versão devo usar?
Use:
0.1.1
com groupId:
io.github.elven-observability
e artifact principal:
elven-opentelemetry-instrumentation-java
Checklist de deploy
- [ ] Aplicação roda em Java 11+
- [ ]
JAVA_TOOL_OPTIONSaponta para o Java Agent embedded ou para o agent oficial - [ ]
OTEL_JAVAAGENT_EXTENSIONSconfigurado quando usar agent oficial + extensão - [ ]
OTEL_SERVICE_NAMEdefinido - [ ]
OTEL_SERVICE_VERSIONdefinido - [ ]
OTEL_DEPLOYMENT_ENVIRONMENTdefinido - [ ]
OTEL_EXPORTER_OTLP_ENDPOINTou endpoints por sinal configurados - [ ]
OTEL_EXPORTER_OTLP_HEADERScontém autenticação e tenant corretos - [ ]
OTEL_TRACES_EXPORTER=otlp - [ ]
OTEL_METRICS_EXPORTER=otlp - [ ]
OTEL_LOGS_EXPORTER=none - [ ] Privacy Elven mantida ligada em produção
- [ ] Sampling adequado ao volume do serviço
- [ ]
logs-interceptor-javaconfigurado quando logs precisam ir ao Loki - [ ] Logs carregam
trace_idespan_id - [ ] Traces aparecem no Tempo com
service.namecorreto - [ ] Métricas aparecem no Mimir/Grafana
- [ ] Nenhum token, cookie, header sensível ou payload aparece cru nos spans