cd /news/developer-tools/tomcat-performance-monitoring-with-o… Β· home β€Ί topics β€Ί developer-tools β€Ί article
[ARTICLE Β· art-43428] src=signoz.io β†— pub= topic=developer-tools verified=true sentiment=Β· neutral

Tomcat Performance Monitoring with OpenTelemetry - Key Metrics and Setup Guide

Apache Tomcat performance monitoring can be enhanced using OpenTelemetry, which provides a vendor-neutral pipeline for collecting traces, metrics, and logs. The OpenTelemetry Java agent attaches to Tomcat with zero code changes, enabling historical retention, alerting, and correlation of metrics with request traces. This guide outlines setting up Tomcat monitoring with OpenTelemetry, including Dockerized deployment and verification in SigNoz Cloud.

read9 min views1 publishedJun 29, 2026
Tomcat Performance Monitoring with OpenTelemetry - Key Metrics and Setup Guide
Image: Signoz (auto-discovered)

Apache Tomcat exposes performance data via JMX (Java Management Extensions), giving you access to thread pool usage, request throughput, session counts, and JVM metrics such as heap memory usage and garbage collection. While built-in tools like the Tomcat Manager and JConsole can display this data in real time, they lack historical retention, alerting, and the ability to correlate metrics with request traces. OpenTelemetry solves this by giving you a single, vendor-neutral pipeline for collecting traces, metrics, and logs from Tomcat. The OpenTelemetry Java agent attaches to Tomcat with zero code changes and exports telemetry directly to your observability backend.

In this guide, we will set up Tomcat performance monitoring using the OpenTelemetry Java agent, build a Dockerized Tomcat application with demo endpoints, instrument it, and verify traces, metrics, and logs flowing into the observability backend.

Prerequisites

Before starting, make sure you have the following ready:

  • Docker and Docker Compose are installed on your machine
  • A SigNoz account ( SigNoz Cloud) - Basic familiarity with Tomcat (you don't need a running Tomcat instance; we will set one up)
  • You will also need Ingestion Key and Ingestion URL from your SigNoz account. For a detailed walkthrough on getting these credentials, see how to get the ingestion key and ingestion url from SigNoz Cloud.

Implementation Roadmap

Setting up Tomcat monitoring with OpenTelemetry involves four steps:

  • Create the project structure with a Dockerfile and demo endpoints
  • Configure OpenTelemetry environment variables to send telemetry to SigNoz Cloud
  • Start the stack with Docker Compose
  • Verify data in SigNoz Cloud

The architecture follows the SigNoz Tomcat instrumentation docs. Because Tomcat runs on the JVM, the cleanest way to instrument it is the OpenTelemetry Java agent attached with -javaagent

: it auto-instruments servlets and common libraries with no code changes, which is why the steps below rely on it instead of a manual SDK setup. The agent handles all three signals (traces, metrics, and logs) and exports them directly to SigNoz Cloud via OTLP. Let's walk through each step.

Step 1: Create the Project Structure

Create a project directory with the Dockerfile, demo web application, and supporting files:

mkdir -p tomcat-monitoring/webapps/ROOT
cd tomcat-monitoring

Create Dockerfile

The Dockerfile uses a multi-stage build: an Alpine stage downloads the OpenTelemetry Java agent, and the Tomcat stage copies it in and attaches it via CATALINA_OPTS

.

FROM alpine:3.20 AS otel
ARG OTEL_JAVA_AGENT_VERSION=2.13.3
RUN apk add --no-cache curl \
    && mkdir -p /otel \
    && curl -fL "https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v${OTEL_JAVA_AGENT_VERSION}/opentelemetry-javaagent.jar" \
    -o /otel/opentelemetry-javaagent.jar

FROM tomcat:10.1-jdk17-temurin
COPY --from=otel /otel/opentelemetry-javaagent.jar /opt/otel/opentelemetry-javaagent.jar
COPY webapps/ROOT /usr/local/tomcat/webapps/ROOT

ENV CATALINA_OPTS="-javaagent:/opt/otel/opentelemetry-javaagent.jar"

The agent version is pinned via a build argument (OTEL_JAVA_AGENT_VERSION=2.13.3

). This makes upgrades explicit and reproducible. The agent attaches to Tomcat through the standard -javaagent

JVM flag, which Tomcat picks up from CATALINA_OPTS

(an environment variable that Tomcat reads at startup to pass extra JVM arguments specifically to the Tomcat process).

Demo Web Application

Create three JSP pages that give you different types of telemetry to verify in SigNoz: normal requests, slow requests, and errors.

** /webapps/ROOT/index.jsp** is the landing page, which generates standard request traces:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Tomcat + OpenTelemetry + SigNoz</title>
</head>
<body>
  <h1>Apache Tomcat Monitoring Demo</h1>
  <p>This app is instrumented using the OpenTelemetry Java agent.</p>
  <ul>
    <li><a href="/slow.jsp?delayMs=500">Slow endpoint (500 ms)</a></li>
    <li><a href="/slow.jsp?delayMs=1200">Slow endpoint (1200 ms)</a></li>
    <li><a href="/error.jsp">Error endpoint</a></li>
  </ul>
</body>
</html>

** /webapps/ROOT/slow.jsp** has the sow endpoint that generates traces with configurable latency, useful for testing latency alerts:

<%@ page language="java" contentType="text/plain; charset=UTF-8" pageEncoding="UTF-8"%>
<%
  String delayParam = request.getParameter("delayMs");
  int delayMs = 250;
  if (delayParam != null) {
    try {
      delayMs = Integer.parseInt(delayParam);
    } catch (NumberFormatException ignored) {
      delayMs = 250;
    }
  }
  Thread.sleep(Math.max(delayMs, 0));
  out.println("Slept for " + delayMs + " ms");
%>

** /webapps/ROOT/error.jsp** exposes the error endpoint to generate traces with error status, useful for testing error rate alerts:

<%-- webapps/ROOT/error.jsp --%>
<%@ page language="java" contentType="text/plain; charset=UTF-8" pageEncoding="UTF-8"%>
<%
  throw new RuntimeException("Intentional demo error for telemetry");
%>

Step 2: Configure OpenTelemetry Environment Variables

The OpenTelemetry Java agent can be configured via environment variables, system properties, or a properties configuration file. The key variables for SigNoz Cloud are OTEL_EXPORTER_OTLP_ENDPOINT

and OTEL_EXPORTER_OTLP_HEADERS

.

Create a .env

file to store your SigNoz Cloud credentials:

SIGNOZ_INGESTION_ENDPOINT=https://ingest.<region>.signoz.cloud:443
SIGNOZ_INGESTION_KEY=<your-ingestion-key>

OTEL_SERVICE_NAME=tomcat-monitoring-demo
OTEL_RESOURCE_ATTRIBUTES=deployment.environment=demo,service.version=1.0.0
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf

Replace <region>

with your SigNoz Cloud region (us

, in

, or eu

) and <your-ingestion-key>

with your SigNoz ingestion key.

Now create the**docker-compose.yml

**file that wires the environment variables to the Tomcat container:

services:
  tomcat:
    build:
      context: .
    container_name: tomcat-otel-signoz-demo
    ports:
      - "8080:8080"
    environment:
      OTEL_SERVICE_NAME: "${OTEL_SERVICE_NAME:-tomcat-monitoring-demo}"
      OTEL_RESOURCE_ATTRIBUTES: "${OTEL_RESOURCE_ATTRIBUTES:-deployment.environment=demo,service.version=1.0.0}"
      OTEL_TRACES_EXPORTER: "otlp"
      OTEL_METRICS_EXPORTER: "otlp"
      OTEL_LOGS_EXPORTER: "otlp"
      OTEL_EXPORTER_OTLP_PROTOCOL: "${OTEL_EXPORTER_OTLP_PROTOCOL:-http/protobuf}"
      OTEL_EXPORTER_OTLP_ENDPOINT: "${SIGNOZ_INGESTION_ENDPOINT}"
      OTEL_EXPORTER_OTLP_HEADERS: "signoz-ingestion-key=${SIGNOZ_INGESTION_KEY}"

The Java agent enables all three signals (traces, metrics, and logs) and sends them directly to SigNoz Cloud.

Your project directory should look like this:

tomcat-monitoring/
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ .env
└── webapps/
    └── ROOT/
        β”œβ”€β”€ index.jsp
        β”œβ”€β”€ slow.jsp
        └── error.jsp

Step 3: Start the Stack

Build and start the container:

docker compose up --build -d

Verify Tomcat is running:

curl http://localhost:8080

You should see the demo landing page HTML with links to the slow and error endpoints.

Check that the OTel Java agent attached successfully:

docker logs tomcat-otel-signoz-demo 2>&1 | grep -i "opentelemetry"

You should see a line like [otel.javaagent] opentelemetry-javaagent - version: 2.13.3

.

Generate Traffic

To produce meaningful telemetry data across all three endpoint types, create a load generation script:

#!/usr/bin/env bash
set -euo pipefail

BASE_URL="${1:-http://localhost:8080}"
ROUNDS="${2:-20}"

echo "Generating traffic against ${BASE_URL} for ${ROUNDS} rounds..."
for i in $(seq 1 "${ROUNDS}"); do
  curl -fsS "${BASE_URL}/" >/dev/null
  curl -fsS "${BASE_URL}/slow.jsp?delayMs=$((200 + (RANDOM % 1000)))" >/dev/null
  curl -s "${BASE_URL}/error.jsp" >/dev/null || true
done

echo "Done. Check SigNoz Cloud for traces/metrics/logs from service: tomcat-monitoring-demo"

Run it:

chmod +x scripts/generate-load.sh
./scripts/generate-load.sh

This sends 20 rounds of normal, slow (200-1200ms random delay), and error requests.

Step 4: Verify in SigNoz

Navigate to theServices tab (under APM) in your SigNoz dashboard. You should see tomcat-monitoring-demo

listed with the automatically generated RED metrics (Rate, Errors, Duration).

Click on tomcat-monitoring-demo

to view

Application Metrics: Request rate, average latency, error percentage, and p99 latencyThis gives you a high-level view of request rate, latency distribution, and error percentage for your Tomcat service.

Traces: Click any trace to see the span waterfall. You should see spans forGET /

,GET /slow.jsp

, andGET /error.jsp

.Each span represents a single HTTP request handled by Tomcat, including slow and error endpoints.

If you want a broader view, switch to the Traces

tab to see all captured requests.

Finally, move to the Logs

tab to inspect correlated application logs.

Apache Tomcat Performance Key Metrics

Now that data is flowing, here are the metrics that matter most. The OpenTelemetry Java agent exports JVM runtime metrics automatically when OTEL_METRICS_EXPORTER=otlp

is set. You can use these metric names directly in the SigNozMetrics→** Query Builder**to create dashboard panels.

JVM Metrics (Exported by Java Agent)

Metric Description What to Watch For
jvm.memory.used{jvm.memory.type="heap"} Current heap memory usage in bytes Baseline climbing toward 90%+ of max after full GC cycles indicates a memory leak
jvm.memory.committed{jvm.memory.type="heap"} Heap memory committed by the JVM Should stay well below jvm.memory.max
jvm.memory.limit{jvm.memory.type="heap"} Maximum heap memory available Use with jvm.memory.used to calculate utilization percentage
jvm.memory.used{jvm.memory.type="nonheap"} Non-heap memory (metaspace, code cache) Steady growth may indicate class leaks
jvm.thread.count Current number of live JVM threads A sustained climb without traffic increase suggests thread leaks
jvm.gc.duration.sum Cumulative GC time Use rate(jvm.gc.duration.sum[5m]) to track GC overhead; s above 200ms cause request timeouts
jvm.gc.duration.count Number of GC events Sudden spikes in GC frequency often precede OOM errors
jvm.class.loaded Number of currently loaded classes Should stabilize after startup; continuous growth indicates class leaks

Dashboards and Alerts

SigNoz provides a built-in RED metrics dashboard (Rate, Errors, Duration) out of the box for any service instrumented with the OpenTelemetry Java agent. You can find this under the Services

tab β†’ click on tomcat-monitoring-demo

to see request rate, error percentage, and latency percentiles without any manual configuration.

If you want to create custom dashboards for JVM metrics or Tomcat-specific panels, follow the SigNoz dashboard creation guide.

SigNoz also supports threshold-based alerts on any metric. For Tomcat monitoring, configure alerts for these conditions:

Condition Threshold Severity
Error rate spike error_rate > 5% for 3 min Critical
Request latency P95 > 2000ms for 5 min Warning
Heap memory pressure heap_used / heap_max > 0.9 after GC Warning
Thread pool saturation busy_threads / max_threads > 0.85 for 5 min Warning
Active sessions growing delta(active_sessions[1h]) > 500 without traffic increase Info

For instructions on configuring notification channels (Slack, email, PagerDuty), see the SigNoz alerts documentation.

Related reading: the same agent-based approach extends to broader Java application monitoring, and the patterns here mirror Node.js performance monitoring on the metrics side. If you're new to reading the trace data, this primer on traces vs spans is a good starting point, and our roundup of APM tools covers how SigNoz compares to other options.

Frequently Asked Questions

Why is my Tomcat server running out of memory (Heap)?

This is usually due to improper heap size settings or a memory leak in the application. Monitoring tools focus on JVM Garbage Collection (GC) activity to assess whether memory is reclaimed efficiently.

How much overhead does the Java agent add?

The Overhead varies by workload and configuration. Benchmark in staging, then reduce cost/overhead using sampling and by disabling unnecessary instrumentations.

How do I monitor multiple Tomcat instances?

Each Tomcat instance runs its own Java agent and exports directly to SigNoz Cloud. Use OTEL_SERVICE_NAME

and OTEL_RESOURCE_ATTRIBUTES

to distinguish between instances:

OTEL_SERVICE_NAME: "tomcat-app-1"
OTEL_RESOURCE_ATTRIBUTES: "deployment.environment=production,host.name=server-1"

OTEL_SERVICE_NAME: "tomcat-app-2"
OTEL_RESOURCE_ATTRIBUTES: "deployment.environment=production,host.name=server-2"

What are the most important Tomcat metrics to track?

If you're setting up a dashboard, these are the "Golden Signals":

  • Request Latency: Average processing time per request.
  • Error Counts: Tracking 4xx and 5xx HTTP status codes.
  • Throughput: Requests per second (RPS). JVM Metrics: Heap usage, non-heap usage, and GC overhead.
── more in #developer-tools 4 stories Β· sorted by recency
── more on @apache tomcat 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/tomcat-performance-m…] indexed:0 read:9min 2026-06-29 Β· β€”