cd /news/developer-tools/send-metrics-from-java-application-u… · home topics developer-tools article
[ARTICLE · art-37376] src=signoz.io ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Send Metrics from Java Application using OpenTelemetry

SigNoz released a guide for sending custom and JVM runtime metrics from Java applications to its observability platform using the OpenTelemetry Java agent, enabling developers to monitor application performance with minimal code changes.

read7 min views1 publishedJun 23, 2026

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

Prerequisites

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

Send metrics to SigNoz

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_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE="delta"
export OTEL_TRACES_EXPORTER="none"
export OTEL_LOGS_EXPORTER="none"

Replace the following:

<region>

: Your SigNoz Cloud region. Seeendpoints.<your-ingestion-key>

: Your SigNozingestion key.<service-name>

: A descriptive name for your service (e.g.,payment-service

).

Step 3. Add OpenTelemetry API dependency

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

<dependency>
  <groupId>io.opentelemetry</groupId>
  <artifactId>opentelemetry-api</artifactId>
  <version>1.57.0</version>
</dependency>
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.

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_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE
  value: 'delta'
- 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_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE = "delta"
$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_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE="delta"
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.<region>.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_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE="delta" \
  -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:

  • Trigger some application activity to generate metrics.
  • In SigNoz, go to Metrics>** Metrics Explorer**. - Search for your custom metric (e.g., orders.processed

). - JVM metrics like jvm.memory.used

andjvm.cpu.time

are collected automatically by the agent. SeeJVM Runtime Metricsfor the full list.

JVM Runtime Metrics

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

Category Metric Description
Memory jvm.memory.used Current memory usage by memory pool
jvm.memory.committed Committed memory by memory pool
jvm.memory.limit Maximum memory available by memory pool
jvm.memory.used_after_last_gc Memory used after the last garbage collection
GC jvm.gc.duration Time spent in garbage collection (histogram)
Threads jvm.thread.count Number of executing threads
Classes jvm.class.loaded Number of classes loaded since JVM start
jvm.class.unloaded Total number of classes unloaded
jvm.class.count Number of classes currently loaded
CPU jvm.cpu.time CPU time used by the process
jvm.cpu.count Number of available processors
jvm.cpu.recent_utilization Recent CPU utilization

Visualize Runtime Metrics

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

  • Download the JVM dashboard JSON - In SigNoz, go to Dashboards→** New Dashboard Import JSON** - Paste the JSON content or upload the file

See the JVM Dashboard Template for details on available panels.

Custom Metrics Examples

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

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.

java -javaagent:./agent.jar -jar app.jar

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)

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 Dashboardsto visualize your custom metrics.Set up Alertson your metrics.- Instrument your Java application with tracesandlogsfor complete observability.

── more in #developer-tools 4 stories · sorted by recency
── more on @signoz 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/send-metrics-from-ja…] indexed:0 read:7min 2026-06-23 ·