# Tomcat OpenTelemetry Instrumentation Guide

> Source: <https://signoz.io/docs/instrumentation/java/opentelemetry-tomcat>
> Published: 2026-06-23 00:00:00+00:00

This guide shows how to instrument your Apache Tomcat application server with OpenTelemetry and send traces to SigNoz. Tomcat uses `setenv.sh`

(Linux/Mac) or `setenv.bat`

(Windows) to configure JVM options, making it straightforward to attach the OpenTelemetry Java agent.

Prerequisites

-
[Java 8+](https://github.com/open-telemetry/opentelemetry-java-instrumentation) -
[Supported Tomcat version](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/supported-libraries.md#application-servers) - A SigNoz Cloud account or self-hosted SigNoz instance

Send traces to SigNoz

Step 1. Download the OpenTelemetry Java agent to your Tomcat directory

```
wget -P /opt/tomcat/lib/ https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
```

Replace `/opt/tomcat`

with your actual `$CATALINA_HOME`

path if different.

Step 2. Create setenv.sh in Tomcat's bin folder

Create a file at `$CATALINA_HOME/bin/setenv.sh`

with the following contents:

```
export CATALINA_OPTS="$CATALINA_OPTS -javaagent:/opt/tomcat/lib/opentelemetry-javaagent.jar"
export OTEL_RESOURCE_ATTRIBUTES="service.name=<service-name>,service.version=<service-version>"
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="none"
export OTEL_LOGS_EXPORTER="none"
```

Make the script executable:

```
chmod +x $CATALINA_HOME/bin/setenv.sh
```

Verify these values:

`<region>`

: Your[SigNoz Cloud region](https://signoz.io/docs/ingestion/signoz-cloud/overview/#endpoint)`<your-ingestion-key>`

: Your SigNoz[ingestion key](https://signoz.io/docs/ingestion/signoz-cloud/keys/).`<service-name>`

: A descriptive name for your service (e.g.,`tomcat-app`

).`<service-version>`

(optional): Your release version, image tag, or git SHA (e.g.,`1.4.2`

,`a01dbef8`

).

Set `service.version`

to a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:

**Bash / shell**:`service.version=$(git rev-parse --short HEAD)`

**GitHub Actions**:`service.version=${{ github.sha }}`

**GitLab CI**:`service.version=$CI_COMMIT_SHORT_SHA`

**Kubernetes**: inject from your Helm chart image tag or CI variable

Step 3. Restart Tomcat

```
$CATALINA_HOME/bin/shutdown.sh
$CATALINA_HOME/bin/startup.sh
```

Or if using systemd:

```
sudo systemctl restart tomcat
```

Step 1. Create a Dockerfile with the OpenTelemetry agent

```
FROM tomcat:10-jdk17

# Download the OpenTelemetry Java agent
RUN wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar \
    -O /usr/local/tomcat/lib/opentelemetry-javaagent.jar

# Create setenv.sh to configure the agent
RUN echo 'export CATALINA_OPTS="$CATALINA_OPTS -javaagent:/usr/local/tomcat/lib/opentelemetry-javaagent.jar"' > /usr/local/tomcat/bin/setenv.sh && \
    chmod +x /usr/local/tomcat/bin/setenv.sh

# Copy your WAR file(s)
COPY target/*.war /usr/local/tomcat/webapps/

EXPOSE 8080
CMD ["catalina.sh", "run"]
```

Step 2. Deploy to Kubernetes

Add these environment variables to your deployment manifest:

```
env:
- name: OTEL_RESOURCE_ATTRIBUTES
  value: 'service.name=<service-name>,service.version=<service-version>'
- 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: 'none'
- name: OTEL_LOGS_EXPORTER
  value: 'none'
```

Verify these values:

`<region>`

: Your[SigNoz Cloud region](https://signoz.io/docs/ingestion/signoz-cloud/overview/#endpoint)`<your-ingestion-key>`

: Your SigNoz[ingestion key](https://signoz.io/docs/ingestion/signoz-cloud/keys/).`<service-name>`

: A descriptive name for your service (e.g.,`tomcat-app`

).`<service-version>`

(optional): Your release version, image tag, or git SHA (e.g.,`1.4.2`

,`a01dbef8`

).

Set `service.version`

to a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:

**Bash / shell**:`service.version=$(git rev-parse --short HEAD)`

**GitHub Actions**:`service.version=${{ github.sha }}`

**GitLab CI**:`service.version=$CI_COMMIT_SHORT_SHA`

**Kubernetes**: inject from your Helm chart image tag or CI variable

The [OpenTelemetry Operator](https://signoz.io/docs/opentelemetry-collection-agents/k8s/otel-operator/overview/) auto-injects the Java agent into your pods without modifying your container image.

Step 1. Set up the OpenTelemetry Operator

Install the Operator and Collector following the [K8s OTel Operator installation guide](https://signoz.io/docs/opentelemetry-collection-agents/k8s/otel-operator/install/).

Step 2. Create the Instrumentation resource

Create `instrumentation.yaml`

to configure Java auto-instrumentation:

```
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: java-instrumentation
spec:
  exporter:
    endpoint: http://otel-collector-collector:4318
  propagators:
    - tracecontext
    - baggage
  env:
    - name: OTEL_METRICS_EXPORTER
      value: "none"
    - name: OTEL_LOGS_EXPORTER
      value: "none"
  java:
    image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:latest
```

Apply the instrumentation:

```
kubectl apply -f instrumentation.yaml
```

Step 3. Add annotations to your Tomcat deployment

Add these annotations to your pod template's `metadata.annotations`

:

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tomcat-app
  template:
    metadata:
      labels:
        app: tomcat-app
      annotations:
        instrumentation.opentelemetry.io/inject-java: "true"
        resource.opentelemetry.io/service.name: "<service-name>"
        resource.opentelemetry.io/service.version: "<service-version>"
    spec:
      containers:
      - name: tomcat
        image: tomcat:10-jdk17
        ports:
        - containerPort: 8080
```

Apply the deployment:

```
kubectl apply -f deployment.yaml
```

The operator will automatically inject the Java agent into your Tomcat pods.

Verify these values:

`<service-name>`

: A descriptive name for your service (e.g.,`tomcat-app`

).`<service-version>`

(optional): Your release version, image tag, or git SHA (e.g.,`1.4.2`

,`a01dbef8`

).

Set `service.version`

to a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:

**Bash / shell**:`service.version=$(git rev-parse --short HEAD)`

**GitHub Actions**:`service.version=${{ github.sha }}`

**GitLab CI**:`service.version=$CI_COMMIT_SHORT_SHA`

**Kubernetes**: inject from your Helm chart image tag or CI variable

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 "C:\tomcat\lib\opentelemetry-javaagent.jar"
```

Replace `C:\tomcat`

with your actual Tomcat installation path.

Step 2. Create setenv.bat in Tomcat's bin folder

Create a file at `%CATALINA_HOME%\bin\setenv.bat`

with the following contents:

```
set "CATALINA_OPTS=%CATALINA_OPTS% -javaagent:C:\tomcat\lib\opentelemetry-javaagent.jar"
set "OTEL_RESOURCE_ATTRIBUTES=service.name=<service-name>,service.version=<service-version>"
set "OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.<region>.signoz.cloud:443"
set "OTEL_EXPORTER_OTLP_HEADERS=signoz-ingestion-key=<your-ingestion-key>"
set "OTEL_METRICS_EXPORTER=none"
set "OTEL_LOGS_EXPORTER=none"
```

Verify these values:

`<region>`

: Your[SigNoz Cloud region](https://signoz.io/docs/ingestion/signoz-cloud/overview/#endpoint)`<your-ingestion-key>`

: Your SigNoz[ingestion key](https://signoz.io/docs/ingestion/signoz-cloud/keys/).`<service-name>`

: A descriptive name for your service (e.g.,`tomcat-app`

).`<service-version>`

(optional): Your release version, image tag, or git SHA (e.g.,`1.4.2`

,`a01dbef8`

).- Update the agent path if your Tomcat is installed elsewhere.

Set `service.version`

to a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:

**Bash / shell**:`service.version=$(git rev-parse --short HEAD)`

**GitHub Actions**:`service.version=${{ github.sha }}`

**GitLab CI**:`service.version=$CI_COMMIT_SHORT_SHA`

**Kubernetes**: inject from your Helm chart image tag or CI variable

Step 3. Restart Tomcat

Using the command prompt:

```
%CATALINA_HOME%\bin\shutdown.bat
%CATALINA_HOME%\bin\startup.bat
```

Or if running as a Windows service:

```
Restart-Service Tomcat10
```

Step 1. Create a Dockerfile

```
FROM tomcat:10-jdk17

# Download the OpenTelemetry Java agent
RUN wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar \
    -O /usr/local/tomcat/lib/opentelemetry-javaagent.jar

# Create setenv.sh to configure the agent
RUN echo 'export CATALINA_OPTS="$CATALINA_OPTS -javaagent:/usr/local/tomcat/lib/opentelemetry-javaagent.jar"' > /usr/local/tomcat/bin/setenv.sh && \
    chmod +x /usr/local/tomcat/bin/setenv.sh

# Copy your WAR file(s)
COPY target/*.war /usr/local/tomcat/webapps/

# Set default environment variables (can be overridden at runtime)
ENV OTEL_RESOURCE_ATTRIBUTES="service.name=<service-name>,service.version=<service-version>"
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="none"
ENV OTEL_LOGS_EXPORTER="none"

EXPOSE 8080
CMD ["catalina.sh", "run"]
```

Verify these values:

`<region>`

: Your[SigNoz Cloud region](https://signoz.io/docs/ingestion/signoz-cloud/overview/#endpoint).`<your-ingestion-key>`

: Your SigNoz[ingestion key](https://signoz.io/docs/ingestion/signoz-cloud/keys/).`<service-name>`

: A descriptive name for your service (e.g.,`tomcat-app`

).`<service-version>`

(optional): Your release version, image tag, or git SHA (e.g.,`1.4.2`

,`a01dbef8`

).

Set `service.version`

to a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:

**Bash / shell**:`service.version=$(git rev-parse --short HEAD)`

**GitHub Actions**:`service.version=${{ github.sha }}`

**GitLab CI**:`service.version=$CI_COMMIT_SHORT_SHA`

**Kubernetes**: inject from your Helm chart image tag or CI variable

Step 2. Build and run

```
docker build -t my-tomcat-app .
docker run -p 8080:8080 my-tomcat-app
```

Or pass environment variables at runtime to avoid hardcoding credentials:

```
docker run -p 8080:8080 \
  -e OTEL_RESOURCE_ATTRIBUTES="service.name=my-tomcat-app" \
  -e OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.signoz.cloud:443" \
  -e OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<key>" \
  -e OTEL_METRICS_EXPORTER="none" \
  -e OTEL_LOGS_EXPORTER="none" \
  my-tomcat-app
```

Validate

With your Tomcat application running, verify traces are being sent to SigNoz:

- Make a few requests to your deployed web applications.
- In SigNoz, open the
**Services** tab and click**Refresh**. Your service should appear. - Go to the
**Traces** tab to see your application's traces.

Troubleshooting

[Troubleshooting](#troubleshooting)

Traces not showing up in SigNoz?

**Check that setenv.sh/setenv.bat is being loaded:**

Add a debug line to your setenv script:

```
echo "setenv.sh is being loaded" >> /tmp/tomcat-debug.log
```

Then restart Tomcat and check if the log file was created.

**Verify the agent is attached:**

Check your Tomcat logs (`catalina.out`

) for OpenTelemetry startup messages:

```
[otel.javaagent] opentelemetry-javaagent - version: X.X.X
```

**Enable debug logging:**

Add to your setenv.sh:

```
export OTEL_LOG_LEVEL=debug
```

Look for span output in Tomcat's logs. If spans appear locally but not in SigNoz, check your endpoint URL and ingestion key.

**Test connectivity:**

```
curl -v https://ingest.<region>.signoz.cloud:443/v1/traces
```

Agent not attaching?

**Check file permissions:**

```
ls -la /opt/tomcat/lib/opentelemetry-javaagent.jar
```

The Tomcat user must have read access to the agent JAR.

**Verify CATALINA_HOME:**

```
echo $CATALINA_HOME
```

Make sure your setenv.sh is in the correct `bin`

directory.

setenv.sh not found or not executed?

On some Linux distributions, Tomcat may be configured differently. Check:

- The file is named exactly
`setenv.sh`

(case-sensitive) - The file is in
`$CATALINA_HOME/bin/`

or`$CATALINA_BASE/bin/`

- The file has execute permissions:
`chmod +x setenv.sh`

Configuring the agent (Optional)

[Configuring the agent (Optional)](#configuring-the-agent-optional)

What can you configure?

The Java agent auto-instruments most libraries out of the box. Configuration lets you fine-tune what gets captured and how traces are exported.

Why configure?

**Reduce noise**— Disable instrumentation for internal health checks or chatty libraries** Control costs**— Sample a percentage of traces instead of capturing everything** Add context**— Tag traces with environment, version, or team info for easier filtering

Common options

Add these to your `CATALINA_OPTS`

in setenv.sh:

**Disable specific instrumentations:**

```
export CATALINA_OPTS="$CATALINA_OPTS -Dotel.instrumentation.jdbc-datasource.enabled=false"
```

**Sample traces:**

```
export OTEL_TRACES_SAMPLER=parentbased_traceidratio
export OTEL_TRACES_SAMPLER_ARG=0.1  # Sample 10% of traces
```

**Add resource attributes:**

```
export OTEL_RESOURCE_ATTRIBUTES="service.name=my-tomcat-app,deployment.environment=production,service.version=1.2.3"
```

See the [full configuration reference](https://opentelemetry.io/docs/languages/java/automatic/agent-config/) for all available options.

Next steps

[Add manual instrumentation](https://signoz.io/docs/instrumentation/java/manual-instrumentation/)for custom spans and business context[Collect Java application logs](https://signoz.io/docs/logs-management/send-logs/java-logs/)with OpenTelemetry[Set up alerts](https://signoz.io/docs/setup-alerts-notification/)for your Tomcat application
