SigNoz
Docs
PricingCustomers
Get Started - Free
Docs
IntroductionContributingMigrate from DatadogSigNoz API
OpenTelemetry
What is OpenTelemetryOpenTelemetry Collector GuideOpenTelemetry Demo
Community
Support
Slack
X
Launch Week
Changelog
Dashboard Templates
DevOps Wordle
Newsletter
KubeCon, Atlanta 2025
More
SigNoz vs DatadogSigNoz vs New RelicSigNoz vs GrafanaSigNoz vs Dynatrace
Careers
AboutTermsPrivacySecurity & Compliance
SigNoz - Open Source Datadog Alternative
SigNoz
All systems operational
HIPAASOC-2
  1. ...
  2. Docs
  3. Metrics
  4. Send Metrics
  5. Application Metrics
  6. Send Metrics from Java Application using OpenTelemetry

Send Metrics from Java Application using OpenTelemetry

SigNoz Cloud - This page applies to SigNoz Cloud editions.
Self-Host - This page applies to self-hosted SigNoz editions.

This guide shows you how to send custom and JVM runtime metrics from your Java application to SigNoz using the OpenTelemetry Java agent.

Most steps are identical. To adapt this guide, update the endpoint and remove the ingestion key header as shown in Cloud → Self-Hosted.

Prerequisites

  • Java 8+
  • A SigNoz Cloud account or self-hosted SigNoz instance

JFR-based (Java Flight Recorder) metrics can provide deeper runtime insights with lower overhead. JFR captures detailed GC events, memory allocation patterns, thread contention, and CPU profiling data that aren't available through standard JMX/MBeans alone.

Send metrics to SigNoz

A VM is a virtual computer that runs on physical hardware. This includes:

  • Cloud VMs: AWS EC2, Google Compute Engine, Azure VMs, DigitalOcean Droplets
  • On-premise VMs: VMware, VirtualBox, Hyper-V, KVM
  • Bare metal servers: Physical servers running Linux/Unix directly

Use this section if you're deploying your Java application directly on a server or VM without containerization.

Step 1. Download the OpenTelemetry Java agent

wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar

Step 2. Set environment variables

export OTEL_SERVICE_NAME="<service-name>"
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.signoz.cloud:443"
export OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<your-ingestion-key>"
export OTEL_METRICS_EXPORTER="otlp"
export OTEL_METRIC_EXPORT_INTERVAL="60000"
export OTEL_TRACES_EXPORTER="none"
export OTEL_LOGS_EXPORTER="none"

Replace the following:

  • <region>: Your SigNoz Cloud region. See endpoints.
  • <your-ingestion-key>: Your SigNoz ingestion key.
  • <service-name>: A descriptive name for your service (e.g., payment-service).

The Java agent auto-instruments web frameworks like Spring Boot, JAX-RS, and Servlet containers, generating traces for every HTTP request. Since traces and logs export is enabled by default, these would be sent to SigNoz even though this guide only covers metrics.

For applications handling many requests, this can generate significant data volume and costs. Setting OTEL_TRACES_EXPORTER and OTEL_LOGS_EXPORTER to none disables them while keeping metrics working. If you want traces or logs later, change them to otlp or remove these variables.

Step 3. Add OpenTelemetry API dependency

Add the OpenTelemetry API to your project. The agent provides the implementation at runtime.

pom.xml
<dependency>
  <groupId>io.opentelemetry</groupId>
  <artifactId>opentelemetry-api</artifactId>
  <version>1.57.0</version>
</dependency>
build.gradle
implementation 'io.opentelemetry:opentelemetry-api:1.57.0'

The version above is current as of this writing. Check the OpenTelemetry Java releases for the latest versions.

Step 4. Add custom metrics to your application

Use GlobalOpenTelemetry.getMeter() to create metrics. The agent configures the MeterProvider automatically.

OrderService.java
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.Meter;

public class OrderService {
    private static final Meter meter = GlobalOpenTelemetry.getMeter("order-service");
    private static final LongCounter ordersCounter = meter
            .counterBuilder("orders.processed")
            .setDescription("Total number of orders processed")
            .build();

    public void processOrder(String orderId) {
        // Your business logic here
        ordersCounter.add(1);
    }
}

This example shows a Counter, which only increases. OpenTelemetry supports other metric types like UpDownCounter, Histogram, and Observable Gauge. See Custom Metrics Examples for complete examples of each type.

Step 5. Run your application

java -javaagent:./opentelemetry-javaagent.jar -jar your-app.jar

Step 1. Add the agent to your Dockerfile

FROM eclipse-temurin:17-jre
WORKDIR /app

COPY target/<my-app>.jar app.jar

RUN wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar -O opentelemetry-javaagent.jar

ENTRYPOINT ["java", "-javaagent:/app/opentelemetry-javaagent.jar", "-jar", "app.jar"]

Step 2. Add environment variables to your deployment

env:
- name: OTEL_SERVICE_NAME
  value: '<service-name>'
- 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_METRICS_EXPORTER
  value: 'otlp'
- name: OTEL_METRIC_EXPORT_INTERVAL
  value: '60000'
- name: OTEL_TRACES_EXPORTER
  value: 'none'
- name: OTEL_LOGS_EXPORTER
  value: 'none'

Replace <region>, <your-ingestion-key>, and <service-name> with your values.

Step 3. Add OpenTelemetry API and custom metrics

Follow Step 3 and Step 4 from the VM tab to add the dependency and custom metrics code.

Step 1. Download the OpenTelemetry Java agent

Invoke-WebRequest -Uri "https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar" -OutFile "opentelemetry-javaagent.jar"

Step 2. Set environment variables

$env:OTEL_SERVICE_NAME = "<service-name>"
$env:OTEL_EXPORTER_OTLP_ENDPOINT = "https://ingest.<region>.signoz.cloud:443"
$env:OTEL_EXPORTER_OTLP_HEADERS = "signoz-ingestion-key=<your-ingestion-key>"
$env:OTEL_METRICS_EXPORTER = "otlp"
$env:OTEL_METRIC_EXPORT_INTERVAL = "60000"
$env:OTEL_TRACES_EXPORTER = "none"
$env:OTEL_LOGS_EXPORTER = "none"

Replace <region>, <your-ingestion-key>, and <service-name> with your values.

Step 3. Add OpenTelemetry API and custom metrics

Follow Step 3 and Step 4 from the VM tab to add the dependency and custom metrics code.

Step 4. Run your application

java -javaagent:.\opentelemetry-javaagent.jar -jar your-app.jar

Step 1. Add the agent to your Dockerfile

FROM eclipse-temurin:17-jre
WORKDIR /app

COPY target/<my-app>.jar app.jar

RUN wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar -O opentelemetry-javaagent.jar

ENV OTEL_SERVICE_NAME="<service-name>"
ENV OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.signoz.cloud:443"
ENV OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<your-ingestion-key>"
ENV OTEL_METRICS_EXPORTER="otlp"
ENV OTEL_METRIC_EXPORT_INTERVAL="60000"
ENV OTEL_TRACES_EXPORTER="none"
ENV OTEL_LOGS_EXPORTER="none"

ENTRYPOINT ["java", "-javaagent:/app/opentelemetry-javaagent.jar", "-jar", "app.jar"]

Replace <my-app>.jar, <region>, <your-ingestion-key>, and <service-name> with your values.

Step 2. Add OpenTelemetry API and custom metrics

Follow Step 3 and Step 4 from the VM tab to add the dependency and custom metrics code.

Step 3. Build and run

docker build -t my-java-app .
docker run -p 8080:8080 my-java-app

Or pass environment variables at runtime:

docker run -p 8080:8080 \
  -e OTEL_SERVICE_NAME="my-service" \
  -e OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.us.signoz.cloud:443" \
  -e OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<key>" \
  -e OTEL_METRICS_EXPORTER="otlp" \
  -e OTEL_METRIC_EXPORT_INTERVAL="60000" \
  -e OTEL_TRACES_EXPORTER="none" \
  -e OTEL_LOGS_EXPORTER="none" \
  my-java-app

The Java agent automatically generates HTTP metrics (http.server.request.duration and http.client.request.duration) for instrumented web frameworks like Spring Boot, JAX-RS, and Servlet containers. See the HTTP metrics semantic conventions for details.

Validate

Once your application is running with the Java agent:

  1. Trigger some application activity to generate metrics.
  2. In SigNoz, go to Metrics > Metrics Explorer.
  3. Search for your custom metric (e.g., orders.processed).
  4. JVM metrics like jvm.memory.used and jvm.cpu.time are collected automatically by the agent. See JVM Runtime Metrics for the full list.

JVM Runtime Metrics

The Java agent automatically collects JVM runtime metrics with zero configuration. These metrics are exported alongside any custom metrics you define, providing visibility into memory usage, garbage collection, threads, and CPU utilization.

Exported Metrics

CategoryMetricDescription
Memoryjvm.memory.usedCurrent memory usage by memory pool
jvm.memory.committedCommitted memory by memory pool
jvm.memory.limitMaximum memory available by memory pool
jvm.memory.used_after_last_gcMemory used after the last garbage collection
GCjvm.gc.durationTime spent in garbage collection (histogram)
Threadsjvm.thread.countNumber of executing threads
Classesjvm.class.loadedNumber of classes loaded since JVM start
jvm.class.unloadedTotal number of classes unloaded
jvm.class.countNumber of classes currently loaded
CPUjvm.cpu.timeCPU time used by the process
jvm.cpu.countNumber of available processors
jvm.cpu.recent_utilizationRecent CPU utilization

Visualize Runtime Metrics

Import the pre-built JVM dashboard to visualize these metrics:

  1. Download the JVM dashboard JSON
  2. In SigNoz, go to Dashboards → New Dashboard → Import JSON
  3. Paste the JSON content or upload the file

See the JVM Dashboard Template for details on available panels.

Custom Metrics Examples

OpenTelemetry provides four metric instrument types. Each example shows how to create and use the instrument.

Counter

A value that only increases (e.g., total requests, orders processed).

import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.Meter;

Meter meter = GlobalOpenTelemetry.getMeter("my-service");

LongCounter requestCounter = meter
        .counterBuilder("http.requests.total")
        .setDescription("Total number of HTTP requests")
        .build();

// Increment the counter
requestCounter.add(1);

UpDownCounter

A value that can increase or decrease (e.g., queue size, active connections).

import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.metrics.LongUpDownCounter;
import io.opentelemetry.api.metrics.Meter;

Meter meter = GlobalOpenTelemetry.getMeter("my-service");

LongUpDownCounter activeRequests = meter
        .upDownCounterBuilder("http.requests.active")
        .setDescription("Number of active requests")
        .build();

// Increment when request starts
activeRequests.add(1);

// Decrement when request ends
activeRequests.add(-1);

Histogram

A distribution of values (e.g., request duration, response size).

import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.Meter;

Meter meter = GlobalOpenTelemetry.getMeter("my-service");

DoubleHistogram requestDuration = meter
        .histogramBuilder("http.request.duration")
        .setDescription("HTTP request duration")
        .setUnit("ms")
        .build();

// Record a duration value
long startTime = System.currentTimeMillis();
// ... process request ...
requestDuration.record(System.currentTimeMillis() - startTime);

Gauge

A point-in-time value via callback (e.g., temperature, memory usage).

import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.ObservableDoubleGauge;

Meter meter = GlobalOpenTelemetry.getMeter("my-service");

ObservableDoubleGauge memoryGauge = meter
        .gaugeBuilder("app.memory.usage")
        .setDescription("Current memory usage")
        .setUnit("By")
        .buildWithCallback(measurement -> {
            Runtime runtime = Runtime.getRuntime();
            measurement.record(runtime.totalMemory() - runtime.freeMemory());
        });

Troubleshooting

Metrics not appearing?

Check environment variables:

echo $OTEL_EXPORTER_OTLP_ENDPOINT
echo $OTEL_METRICS_EXPORTER

Enable debug logging:

OTEL_LOG_LEVEL=debug java -javaagent:./opentelemetry-javaagent.jar -jar app.jar

Verify agent is attached: Look for this log line on startup:

[otel.javaagent] INFO io.opentelemetry.javaagent.tooling.VersionLogger - opentelemetry-javaagent - version: X.X.X

GlobalOpenTelemetry.getMeter() returns no-op?

Make sure the Java agent is attached. Without the agent, GlobalOpenTelemetry returns a no-op implementation.

# Correct - agent flag before -jar
java -javaagent:./agent.jar -jar app.jar

# Wrong - agent flag after -jar is ignored
java -jar app.jar -javaagent:./agent.jar

Metrics delayed or not updating?

OTEL_METRIC_EXPORT_INTERVAL controls how often metrics are exported in milliseconds. The default is 60000 (60 seconds), so metrics may take up to a minute to appear.

To reduce the interval for testing:

export OTEL_METRIC_EXPORT_INTERVAL=10000  # 10 seconds

Authentication errors

If you see "Unauthorized" or "403 Forbidden":

  • Verify your ingestion key is correct in OTEL_EXPORTER_OTLP_HEADERS
  • Ensure the header format is exactly: signoz-ingestion-key=<your-key> (no extra spaces)

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 metrics 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.

Next Steps

  • Create Dashboards to visualize your custom metrics.
  • Set up Alerts on your metrics.
  • Instrument your Java application with traces and logs for complete observability.

Last updated: March 26, 2026

Edit on GitHub

Was this page helpful?

Your response helps us improve this page.

Prev
Application Metrics
Next
JMX Metrics
On this page
Prerequisites
Send metrics to SigNoz
Step 1. Download the OpenTelemetry Java agent
Step 2. Set environment variables
Step 3. Add OpenTelemetry API dependency
Step 4. Add custom metrics to your application
Step 5. Run your application
Step 1. Add the agent to your Dockerfile
Step 2. Add environment variables to your deployment
Step 3. Add OpenTelemetry API and custom metrics
Step 1. Download the OpenTelemetry Java agent
Step 2. Set environment variables
Step 3. Add OpenTelemetry API and custom metrics
Step 4. Run your application
Step 1. Add the agent to your Dockerfile
Step 2. Add OpenTelemetry API and custom metrics
Step 3. Build and run
Validate
JVM Runtime Metrics
Exported Metrics
Visualize Runtime Metrics
Custom Metrics Examples
Counter
UpDownCounter
Histogram
Gauge
Troubleshooting
Metrics not appearing?
GlobalOpenTelemetry.getMeter() returns no-op?
Metrics delayed or not updating?
Authentication errors
Setup OpenTelemetry Collector (Optional)
What is the OpenTelemetry Collector?
Why use it?
Next Steps

Is this page helpful?

Your response helps us improve this page.