Prerequisites
- Java 8 or higher
- An instance of SigNoz (either Cloud or Self-Hosted)
Choosing a Log Collection Method
There are two primary ways to send logs from your Java application to SigNoz:
Application-level Collection (OTLP):
Your application sends logs directly to SigNoz using the OpenTelemetry Java Agent.
Recommended for: Most users. It provides automatic trace-log correlation, rich metadata, and requires no changing of infrastructure.Infrastructure-level Collection (Stdout/Stderr):
Your application writes logs to the console, and an agent running on the node/cluster collects them.
Recommended for: Kubernetes environments, legacy applications you can't reconfigure, or when you want strictly separated logging concerns.
This guide focuses on Application-level Collection (OTLP).
Send logs to SigNoz
The OpenTelemetry Java Agent automatically captures logs from popular logging frameworks like Log4j 2, Logback, and java.util.logging (JUL) and sends them to SigNoz.
Step 1: Download the Java Agent
Download the latest opentelemetry-javaagent.jar:
wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
Step 2: Run the application
Set the environment variables and run your application:
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.signoz.cloud:443"
export OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<your-ingestion-key>"
export OTEL_SERVICE_NAME="java-app"
java -javaagent:./opentelemetry-javaagent.jar -jar your-app.jar
Verify these values:
<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your ingestion key.
If using a local OTel Collector (e.g., self-hosted), use:
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317"
export OTEL_SERVICE_NAME="java-app"
java -javaagent:./opentelemetry-javaagent.jar -jar your-app.jar
Add these environment variables to your deployment manifest:
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: 'https://ingest.<region>.signoz.cloud:443'
- name: OTEL_EXPORTER_OTLP_HEADERS
value: 'signoz-ingestion-key=<your-ingestion-key>'
- name: OTEL_SERVICE_NAME
value: 'java-app'
- name: JAVA_TOOL_OPTIONS
value: '-javaagent:/path/to/opentelemetry-javaagent.jar'
Verify these values:
<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your ingestion key.
Note: You need to ensure the opentelemetry-javaagent.jar is available in the container or added via an init container / volume.
Avoiding Duplicate Logs
If using the k8s-infra chart (which auto-collects container logs), disable log collection for this application to prevent duplicates.
Create a Dockerfile:
FROM eclipse-temurin:17-jre
WORKDIR /app
# Download the OpenTelemetry Java Agent
ADD https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar /app/opentelemetry-javaagent.jar
# Copy your application JAR
COPY target/your-app.jar /app/app.jar
# Set environment variables
ENV OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.signoz.cloud:443"
ENV OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<your-ingestion-key>"
ENV OTEL_SERVICE_NAME="java-app"
# Configure the agent
ENV JAVA_TOOL_OPTIONS="-javaagent:/app/opentelemetry-javaagent.jar"
CMD ["java", "-jar", "/app/app.jar"]
Build and run:
docker build -t java-app .
docker run -p 8080:8080 java-app
Replace the placeholders:
<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your ingestion key.
Avoiding Duplicate Logs
If you have a log driver or a collector picking up Docker container logs (stdout), you might see duplicate logs in SigNoz. To avoid this, either disable container log collection for this service or use only one method.
Set environment variables in PowerShell:
$env:OTEL_EXPORTER_OTLP_ENDPOINT = "https://ingest.<region>.signoz.cloud:443"
$env:OTEL_EXPORTER_OTLP_HEADERS = "signoz-ingestion-key=<your-ingestion-key>"
$env:OTEL_SERVICE_NAME = "java-app"
java -javaagent:./opentelemetry-javaagent.jar -jar your-app.jar
Verify these values:
<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your ingestion key.
Log Correlation
The OpenTelemetry Java Agent automatically injects trace_id and span_id into your logs when a tracing context is active, allowing you to correlate logs with traces in SigNoz.
By default, the Java Agent collects traces, metrics, and logs. To collect only logs, disable traces and metrics:
export OTEL_TRACES_EXPORTER="none"
export OTEL_METRICS_EXPORTER="none"
Step 1: Add dependencies
Add the following OpenTelemetry dependencies to your project.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom</artifactId>
<version>1.57.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-instrumentation-bom-alpha</artifactId>
<version>2.23.0-alpha</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- OpenTelemetry SDK -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
</dependency>
<!-- OpenTelemetry Autoconfigure -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId>
<version>1.57.0</version>
</dependency>
<!-- OpenTelemetry Exporter -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
<!-- Semantic Conventions -->
<dependency>
<groupId>io.opentelemetry.semconv</groupId>
<artifactId>opentelemetry-semconv</artifactId>
</dependency>
<!-- Logback Appender -->
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-logback-appender-1.0</artifactId>
</dependency>
</dependencies>
dependencies {
implementation platform('io.opentelemetry:opentelemetry-bom:1.57.0')
implementation platform('io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:2.23.0-alpha')
// OpenTelemetry SDK
implementation 'io.opentelemetry:opentelemetry-sdk'
// OpenTelemetry Autoconfigure
implementation 'io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:1.57.0'
// OpenTelemetry Exporter
implementation 'io.opentelemetry:opentelemetry-exporter-otlp'
// Semantic Conventions
implementation 'io.opentelemetry.semconv:opentelemetry-semconv'
// Logback Appender
implementation 'io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0'
}
Step 2: Set environment variables
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.signoz.cloud:443"
export OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<your-ingestion-key>"
export OTEL_SERVICE_NAME="java-manual-app"
Verify these values:
<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your ingestion key.
Add these environment variables to your deployment manifest:
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: 'https://ingest.<region>.signoz.cloud:443'
- name: OTEL_EXPORTER_OTLP_HEADERS
value: 'signoz-ingestion-key=<your-ingestion-key>'
- name: OTEL_SERVICE_NAME
value: 'java-manual-app'
Verify these values:
<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your ingestion key.
Avoiding Duplicate Logs
If using the k8s-infra chart (which auto-collects container logs), disable log collection for this application to prevent duplicates.
Create a Dockerfile in your project root:
FROM eclipse-temurin:17-jre
WORKDIR /app
# Copy your application JAR
COPY target/your-app.jar /app/app.jar
# Set OpenTelemetry environment variables
ENV OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.signoz.cloud:443"
ENV OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<your-ingestion-key>"
ENV OTEL_SERVICE_NAME="java-manual-app"
CMD ["java", "-jar", "/app/app.jar"]
Build and run the container:
docker build -t java-manual-app .
docker run java-manual-app
Verify these values:
<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your ingestion key.
Avoiding Duplicate Logs
If you have a log driver or a collector picking up Docker container logs (stdout), you might see duplicate logs in SigNoz. To avoid this, either disable container log collection for this service or use only one method.
Set environment variables in PowerShell:
$env:OTEL_EXPORTER_OTLP_ENDPOINT = "https://ingest.<region>.signoz.cloud:443"
$env:OTEL_EXPORTER_OTLP_HEADERS = "signoz-ingestion-key=<your-ingestion-key>"
$env:OTEL_SERVICE_NAME = "java-manual-app"
Verify these values:
<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your ingestion key.
Step 3: Initialize OpenTelemetry SDK
Create a file named src/main/java/com/example/OpenTelemetryConfig.java to initialize the OpenTelemetry SDK. You must initialize both the LoggerProvider (for logs) and the TracerProvider (for correlation).
package com.example;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
public class OpenTelemetryConfig {
public static OpenTelemetry init() {
AutoConfiguredOpenTelemetrySdk autoConfiguredSdk = AutoConfiguredOpenTelemetrySdk.initialize();
return autoConfiguredSdk.getOpenTelemetrySdk();
}
}
Step 4: Configure Logback
Create a file named src/main/resources/logback.xml and add the OpenTelemetryAppender to bridge logs to the OpenTelemetry SDK.
<configuration>
<appender name="OTEL" class="io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender">
<captureExperimentalAttributes>true</captureExperimentalAttributes>
<captureKeyValuePairAttributes>true</captureKeyValuePairAttributes>
</appender>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="OTEL" />
<appender-ref ref="CONSOLE" />
</root>
</configuration>
Step 5: Instrument usage with Log Correlation
Initialize the SDK at the start of your application. When you create spans and make them current, the OpenTelemetry appender will automatically add the trace_id and span_id to your logs.
Create or update your main application file src/main/java/com/example/Application.java.
package com.example;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
// Initialize OpenTelemetry
OpenTelemetryConfig.init();
// Install the Logback appender using GlobalOpenTelemetry
OpenTelemetryAppender.install(GlobalOpenTelemetry.get());
logger.info("Application started (no active span)");
// Create span for correlation
Tracer tracer = GlobalOpenTelemetry.getTracer("my-app");
Span span = tracer.spanBuilder("my-span").startSpan();
try (Scope scope = span.makeCurrent()) {
logger.info("Processing data within a span...");
doWork();
} finally {
span.end();
}
logger.info("Application finished");
}
private static void doWork() {
logger.warn("Simulated work log - also correlated!");
}
}
Step 6: Build and Run
Build your project and run the application.
mvn clean package
java -jar target/your-app-1.0-SNAPSHOT.jar
./gradlew build
java -jar build/libs/your-app-1.0-SNAPSHOT.jar
Validate Logs
Captured logs can be viewed in the Logs Explorer section.


Setup OpenTelemetry Collector (Optional)
What is the OpenTelemetry Collector?
Think of the OTel Collector as a middleman between your app and SigNoz. Instead of your application sending data directly to SigNoz, it sends everything to the Collector first, which then forwards it along.
Why use it?
- Cleaning up data — Filter out noisy traces you don't care about, or remove sensitive info before it leaves your servers.
- Keeping your app lightweight — Let the Collector handle batching, retries, and compression instead of your application code.
- Adding context automatically — The Collector can tag your data with useful info like which Kubernetes pod or cloud region it came from.
- Future flexibility — Want to send data to multiple backends later? The Collector makes that easy without changing your app.
See Switch from direct export to Collector for step-by-step instructions to convert your setup.
For more details, see Why use the OpenTelemetry Collector? and the Collector configuration guide.
Advanced Configuration
The OpenTelemetry Java agent provides several configuration options to control log collection and internal agent logging. These can be set as environment variables or system properties.
Log Exporter
Controls where the application logs are exported. By default, it is set to otlp.
OTEL_LOGS_EXPORTER=otlp: Exports logs via OTLP (default).OTEL_LOGS_EXPORTER=console: Prints logs to the standard output.OTEL_LOGS_EXPORTER=none: Disables log export entirely.
OTLP Exporter Configurations
When using the otlp log exporter, you can further fine-tune how logs are exported via the OTLP protocol.
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT: The specific endpoint to send logs to (e.g.,https://ingest.<region>.signoz.cloud:443). OverridesOTEL_EXPORTER_OTLP_ENDPOINT.OTEL_EXPORTER_OTLP_LOGS_PROTOCOL: The transport protocol. Options includegrpc(default),http/protobuf, andhttp/json.OTEL_EXPORTER_OTLP_LOGS_TIMEOUT: The maximum time (in milliseconds) the exporter will wait for a batch to be exported before timing out. Default is10000(10 seconds).OTEL_EXPORTER_OTLP_LOGS_HEADERS: Key-value pairs separated by commas to pass as request headers (e.g.,signoz-ingestion-key=<your-ingestion-key>). OverridesOTEL_EXPORTER_OTLP_HEADERS.
Batch Log Processor Configurations
Logs are processed in batches before being exported to reduce network overhead. You can control this behavior using the Batch LogRecord Processor configurations:
OTEL_BLRP_SCHEDULE_DELAY: The interval (in milliseconds) between two consecutive exports. Default is5000(5 seconds).OTEL_BLRP_MAX_QUEUE_SIZE: The maximum number of logs that are kept in the queue. Default is2048.OTEL_BLRP_MAX_EXPORT_BATCH_SIZE: The maximum number of logs to export in a single batch. Must be less than or equal to the maximum queue size. Default is512.OTEL_BLRP_EXPORT_TIMEOUT: The maximum time (in milliseconds) allowed to export a batch of logs. Default is30000(30 seconds).
Agent Internal Logging
You can control the internal logging behavior of the Java agent itself using the OTEL_JAVAAGENT_LOGGING environment variable (or otel.javaagent.logging system property):
OTEL_JAVAAGENT_LOGGING=simple: PrintsINFOlevel and above logs to standard error (default).OTEL_JAVAAGENT_LOGGING=none: Mutes all internal agent logging.OTEL_JAVAAGENT_LOGGING=application: Redirects agent logs to the instrumented application's SLF4J logger, allowing you to manage agent logs using your application's logging configuration (e.g.,logback.xml).
Framework Appender Toggles
The Java agent automatically enables instrumentation for popular logging frameworks by default. You can explicitly disable or enable them if needed:
OTEL_INSTRUMENTATION_LOGBACK_APPENDER_ENABLED=false: Disables the Logback appender instrumentation.OTEL_INSTRUMENTATION_LOG4J_APPENDER_ENABLED=false: Disables the Log4j 2 appender instrumentation.OTEL_INSTRUMENTATION_JUL_ENABLED=false: Disablesjava.util.logging(JUL) instrumentation.OTEL_INSTRUMENTATION_JBOSS_LOGMANAGER_APPENDER_ENABLED=false: Disables the JBoss Log Manager appender.
Logback & Log4j Experimental Features
If you are using Logback or Log4j, OpenTelemetry supports capturing various contextual attributes by enabling experimental features via environment variables.
In the configurations below, <FRAMEWORK> can be replaced with either LOGBACK or LOG4J, depending on your logging framework.
OTEL_INSTRUMENTATION_<FRAMEWORK>_APPENDER_EXPERIMENTAL_LOG_ATTRIBUTES=true: Captures standard attributes likethread.nameandthread.id.- Example for Logback:
OTEL_INSTRUMENTATION_LOGBACK_APPENDER_EXPERIMENTAL_LOG_ATTRIBUTES=true - Example for Log4j:
OTEL_INSTRUMENTATION_LOG4J_APPENDER_EXPERIMENTAL_LOG_ATTRIBUTES=true
- Example for Logback:
OTEL_INSTRUMENTATION_<FRAMEWORK>_APPENDER_EXPERIMENTAL_CAPTURE_CODE_ATTRIBUTES=true: Captures source code attributes (e.g., class name, method name, line number). Note that this may add performance overhead.OTEL_INSTRUMENTATION_<FRAMEWORK>_APPENDER_EXPERIMENTAL_CAPTURE_MARKER_ATTRIBUTE=true: Captures markers.OTEL_INSTRUMENTATION_<FRAMEWORK>_APPENDER_EXPERIMENTAL_CAPTURE_MDC_ATTRIBUTES: Controls which MDC attributes to capture. Use*to capture all MDC attributes or provide a comma-separated list of specific keys (e.g.tenant_id,tenant_user).OTEL_INSTRUMENTATION_LOGBACK_APPENDER_EXPERIMENTAL_CAPTURE_KEY_VALUE_PAIR_ATTRIBUTES=true: Captures Logback key-value pairs as log attributes.OTEL_INSTRUMENTATION_LOG4J_APPENDER_EXPERIMENTAL_CAPTURE_MAP_MESSAGE_ATTRIBUTES=true: Enables the capture of attributes from Log4j MapMessage instances.OTEL_INSTRUMENTATION_LOG4J_APPENDER_EXPERIMENTAL_CAPTURE_EVENT_NAME=true: Enables the capture of the event name from the MDC attribute "event.name" and sets it as the log record's event name.
Pass configurations using JAVA_TOOL_OPTIONS
You can pass these system properties seamlessly by adding them to the JAVA_TOOL_OPTIONS environment variable before starting your application.
export JAVA_TOOL_OPTIONS="-javaagent:/path/to/opentelemetry-javaagent.jar \
-Dotel.instrumentation.logback-appender.experimental.capture-mdc-attributes=tenant_id,tenant_user,tenant_user_id,tenantshortname \
-Dotel.instrumentation.logback-appender.experimental-log-attributes=true"
Troubleshooting
Logs are not appearing in SigNoz
If you don't see your application logs correctly in SigNoz, check the following common pitfalls:
- Enable Agent Debug Logging: Run your application with
-Dotel.javaagent.debug=trueor setOTEL_JAVAAGENT_DEBUG=true. This will print verbose internal agent logs to the console and indicate if there are connection issues with the endpoint. - Verify Exporters Setup: Ensure
OTEL_LOGS_EXPORTERis set tootlp(it is by default in Auto-Instrumentation, but double-check if explicitly set). - Check Your Endpoints: Validate that
OTEL_EXPORTER_OTLP_ENDPOINT(orOTEL_EXPORTER_OTLP_LOGS_ENDPOINT) contains an accessible, valid URL without trailing slashes. Make sure your ingestion key is correctly passed inOTEL_EXPORTER_OTLP_HEADERS. - Verify Custom Log Configurations: If you are using a custom
logback.xmlorlog4j2.xml, make sure the OpenTelemetry appender (OTEL) is bound to the root logger level you expect (e.g.<root level="INFO"> <appender-ref ref="OTEL" /> </root>).
MDC or ThreadContext attributes are missing
Logback refers to contextual logging data as MDC (Mapped Diagnostic Context), whereas Log4j2 commonly refers to it as Thread Context. By default, the OpenTelemetry Java agent doesn't capture these custom attributes.
To make them visible in SigNoz, you need to configure the OpenTelemetry agent to capture them. You can do this by passing the appropriate system property via the JAVA_TOOL_OPTIONS environment variable.
For Logback (Capture all MDC attributes):
export JAVA_TOOL_OPTIONS="-javaagent:/path/to/opentelemetry-javaagent.jar \ -Dotel.instrumentation.logback-appender.experimental.capture-mdc-attributes=*"For Log4j (Capture all ThreadContext/MDC attributes):
export JAVA_TOOL_OPTIONS="-javaagent:/path/to/opentelemetry-javaagent.jar \ -Dotel.instrumentation.log4j-appender.experimental.capture-mdc-attributes=*"
Note: Instead of *, you can also provide a comma-separated list of specific keys (e.g. tenant_id,session_id) to only capture certain attributes.
Next Steps
Get Help
If you need help with the steps in this topic, please reach out to us on SigNoz Community Slack.
If you are a SigNoz Cloud user, please use in product chat support located at the bottom right corner of your SigNoz instance or contact us at cloud-support@signoz.io.