{"slug": "tomcat-opentelemetry-instrumentation-guide", "title": "Tomcat OpenTelemetry Instrumentation Guide", "summary": "SigNoz released a guide for instrumenting Apache Tomcat with OpenTelemetry to send traces to its observability platform. The guide covers setup via setenv.sh on Linux/Windows, Docker, and Kubernetes, requiring the OpenTelemetry Java agent and SigNoz ingestion keys. This enables developers to monitor Tomcat applications with distributed tracing.", "body_md": "This guide shows how to instrument your Apache Tomcat application server with OpenTelemetry and send traces to SigNoz. Tomcat uses `setenv.sh`\n\n(Linux/Mac) or `setenv.bat`\n\n(Windows) to configure JVM options, making it straightforward to attach the OpenTelemetry Java agent.\n\nPrerequisites\n\n-\n[Java 8+](https://github.com/open-telemetry/opentelemetry-java-instrumentation) -\n[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\n\nSend traces to SigNoz\n\nStep 1. Download the OpenTelemetry Java agent to your Tomcat directory\n\n```\nwget -P /opt/tomcat/lib/ https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar\n```\n\nReplace `/opt/tomcat`\n\nwith your actual `$CATALINA_HOME`\n\npath if different.\n\nStep 2. Create setenv.sh in Tomcat's bin folder\n\nCreate a file at `$CATALINA_HOME/bin/setenv.sh`\n\nwith the following contents:\n\n```\nexport CATALINA_OPTS=\"$CATALINA_OPTS -javaagent:/opt/tomcat/lib/opentelemetry-javaagent.jar\"\nexport OTEL_RESOURCE_ATTRIBUTES=\"service.name=<service-name>,service.version=<service-version>\"\nexport OTEL_EXPORTER_OTLP_ENDPOINT=\"https://ingest.<region>.signoz.cloud:443\"\nexport OTEL_EXPORTER_OTLP_HEADERS=\"signoz-ingestion-key=<your-ingestion-key>\"\nexport OTEL_METRICS_EXPORTER=\"none\"\nexport OTEL_LOGS_EXPORTER=\"none\"\n```\n\nMake the script executable:\n\n```\nchmod +x $CATALINA_HOME/bin/setenv.sh\n```\n\nVerify these values:\n\n`<region>`\n\n: Your[SigNoz Cloud region](https://signoz.io/docs/ingestion/signoz-cloud/overview/#endpoint)`<your-ingestion-key>`\n\n: Your SigNoz[ingestion key](https://signoz.io/docs/ingestion/signoz-cloud/keys/).`<service-name>`\n\n: A descriptive name for your service (e.g.,`tomcat-app`\n\n).`<service-version>`\n\n(optional): Your release version, image tag, or git SHA (e.g.,`1.4.2`\n\n,`a01dbef8`\n\n).\n\nSet `service.version`\n\nto a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:\n\n**Bash / shell**:`service.version=$(git rev-parse --short HEAD)`\n\n**GitHub Actions**:`service.version=${{ github.sha }}`\n\n**GitLab CI**:`service.version=$CI_COMMIT_SHORT_SHA`\n\n**Kubernetes**: inject from your Helm chart image tag or CI variable\n\nStep 3. Restart Tomcat\n\n```\n$CATALINA_HOME/bin/shutdown.sh\n$CATALINA_HOME/bin/startup.sh\n```\n\nOr if using systemd:\n\n```\nsudo systemctl restart tomcat\n```\n\nStep 1. Create a Dockerfile with the OpenTelemetry agent\n\n```\nFROM tomcat:10-jdk17\n\n# Download the OpenTelemetry Java agent\nRUN wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar \\\n    -O /usr/local/tomcat/lib/opentelemetry-javaagent.jar\n\n# Create setenv.sh to configure the agent\nRUN echo 'export CATALINA_OPTS=\"$CATALINA_OPTS -javaagent:/usr/local/tomcat/lib/opentelemetry-javaagent.jar\"' > /usr/local/tomcat/bin/setenv.sh && \\\n    chmod +x /usr/local/tomcat/bin/setenv.sh\n\n# Copy your WAR file(s)\nCOPY target/*.war /usr/local/tomcat/webapps/\n\nEXPOSE 8080\nCMD [\"catalina.sh\", \"run\"]\n```\n\nStep 2. Deploy to Kubernetes\n\nAdd these environment variables to your deployment manifest:\n\n```\nenv:\n- name: OTEL_RESOURCE_ATTRIBUTES\n  value: 'service.name=<service-name>,service.version=<service-version>'\n- name: OTEL_EXPORTER_OTLP_ENDPOINT\n  value: 'https://ingest.<region>.signoz.cloud:443'\n- name: OTEL_EXPORTER_OTLP_HEADERS\n  value: 'signoz-ingestion-key=<your-ingestion-key>'\n- name: OTEL_METRICS_EXPORTER\n  value: 'none'\n- name: OTEL_LOGS_EXPORTER\n  value: 'none'\n```\n\nVerify these values:\n\n`<region>`\n\n: Your[SigNoz Cloud region](https://signoz.io/docs/ingestion/signoz-cloud/overview/#endpoint)`<your-ingestion-key>`\n\n: Your SigNoz[ingestion key](https://signoz.io/docs/ingestion/signoz-cloud/keys/).`<service-name>`\n\n: A descriptive name for your service (e.g.,`tomcat-app`\n\n).`<service-version>`\n\n(optional): Your release version, image tag, or git SHA (e.g.,`1.4.2`\n\n,`a01dbef8`\n\n).\n\nSet `service.version`\n\nto a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:\n\n**Bash / shell**:`service.version=$(git rev-parse --short HEAD)`\n\n**GitHub Actions**:`service.version=${{ github.sha }}`\n\n**GitLab CI**:`service.version=$CI_COMMIT_SHORT_SHA`\n\n**Kubernetes**: inject from your Helm chart image tag or CI variable\n\nThe [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.\n\nStep 1. Set up the OpenTelemetry Operator\n\nInstall the Operator and Collector following the [K8s OTel Operator installation guide](https://signoz.io/docs/opentelemetry-collection-agents/k8s/otel-operator/install/).\n\nStep 2. Create the Instrumentation resource\n\nCreate `instrumentation.yaml`\n\nto configure Java auto-instrumentation:\n\n```\napiVersion: opentelemetry.io/v1alpha1\nkind: Instrumentation\nmetadata:\n  name: java-instrumentation\nspec:\n  exporter:\n    endpoint: http://otel-collector-collector:4318\n  propagators:\n    - tracecontext\n    - baggage\n  env:\n    - name: OTEL_METRICS_EXPORTER\n      value: \"none\"\n    - name: OTEL_LOGS_EXPORTER\n      value: \"none\"\n  java:\n    image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:latest\n```\n\nApply the instrumentation:\n\n```\nkubectl apply -f instrumentation.yaml\n```\n\nStep 3. Add annotations to your Tomcat deployment\n\nAdd these annotations to your pod template's `metadata.annotations`\n\n:\n\n```\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: tomcat-app\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: tomcat-app\n  template:\n    metadata:\n      labels:\n        app: tomcat-app\n      annotations:\n        instrumentation.opentelemetry.io/inject-java: \"true\"\n        resource.opentelemetry.io/service.name: \"<service-name>\"\n        resource.opentelemetry.io/service.version: \"<service-version>\"\n    spec:\n      containers:\n      - name: tomcat\n        image: tomcat:10-jdk17\n        ports:\n        - containerPort: 8080\n```\n\nApply the deployment:\n\n```\nkubectl apply -f deployment.yaml\n```\n\nThe operator will automatically inject the Java agent into your Tomcat pods.\n\nVerify these values:\n\n`<service-name>`\n\n: A descriptive name for your service (e.g.,`tomcat-app`\n\n).`<service-version>`\n\n(optional): Your release version, image tag, or git SHA (e.g.,`1.4.2`\n\n,`a01dbef8`\n\n).\n\nSet `service.version`\n\nto a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:\n\n**Bash / shell**:`service.version=$(git rev-parse --short HEAD)`\n\n**GitHub Actions**:`service.version=${{ github.sha }}`\n\n**GitLab CI**:`service.version=$CI_COMMIT_SHORT_SHA`\n\n**Kubernetes**: inject from your Helm chart image tag or CI variable\n\nStep 1. Download the OpenTelemetry Java agent\n\n```\nInvoke-WebRequest -Uri \"https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar\" -OutFile \"C:\\tomcat\\lib\\opentelemetry-javaagent.jar\"\n```\n\nReplace `C:\\tomcat`\n\nwith your actual Tomcat installation path.\n\nStep 2. Create setenv.bat in Tomcat's bin folder\n\nCreate a file at `%CATALINA_HOME%\\bin\\setenv.bat`\n\nwith the following contents:\n\n```\nset \"CATALINA_OPTS=%CATALINA_OPTS% -javaagent:C:\\tomcat\\lib\\opentelemetry-javaagent.jar\"\nset \"OTEL_RESOURCE_ATTRIBUTES=service.name=<service-name>,service.version=<service-version>\"\nset \"OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.<region>.signoz.cloud:443\"\nset \"OTEL_EXPORTER_OTLP_HEADERS=signoz-ingestion-key=<your-ingestion-key>\"\nset \"OTEL_METRICS_EXPORTER=none\"\nset \"OTEL_LOGS_EXPORTER=none\"\n```\n\nVerify these values:\n\n`<region>`\n\n: Your[SigNoz Cloud region](https://signoz.io/docs/ingestion/signoz-cloud/overview/#endpoint)`<your-ingestion-key>`\n\n: Your SigNoz[ingestion key](https://signoz.io/docs/ingestion/signoz-cloud/keys/).`<service-name>`\n\n: A descriptive name for your service (e.g.,`tomcat-app`\n\n).`<service-version>`\n\n(optional): Your release version, image tag, or git SHA (e.g.,`1.4.2`\n\n,`a01dbef8`\n\n).- Update the agent path if your Tomcat is installed elsewhere.\n\nSet `service.version`\n\nto a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:\n\n**Bash / shell**:`service.version=$(git rev-parse --short HEAD)`\n\n**GitHub Actions**:`service.version=${{ github.sha }}`\n\n**GitLab CI**:`service.version=$CI_COMMIT_SHORT_SHA`\n\n**Kubernetes**: inject from your Helm chart image tag or CI variable\n\nStep 3. Restart Tomcat\n\nUsing the command prompt:\n\n```\n%CATALINA_HOME%\\bin\\shutdown.bat\n%CATALINA_HOME%\\bin\\startup.bat\n```\n\nOr if running as a Windows service:\n\n```\nRestart-Service Tomcat10\n```\n\nStep 1. Create a Dockerfile\n\n```\nFROM tomcat:10-jdk17\n\n# Download the OpenTelemetry Java agent\nRUN wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar \\\n    -O /usr/local/tomcat/lib/opentelemetry-javaagent.jar\n\n# Create setenv.sh to configure the agent\nRUN echo 'export CATALINA_OPTS=\"$CATALINA_OPTS -javaagent:/usr/local/tomcat/lib/opentelemetry-javaagent.jar\"' > /usr/local/tomcat/bin/setenv.sh && \\\n    chmod +x /usr/local/tomcat/bin/setenv.sh\n\n# Copy your WAR file(s)\nCOPY target/*.war /usr/local/tomcat/webapps/\n\n# Set default environment variables (can be overridden at runtime)\nENV OTEL_RESOURCE_ATTRIBUTES=\"service.name=<service-name>,service.version=<service-version>\"\nENV OTEL_EXPORTER_OTLP_ENDPOINT=\"https://ingest.<region>.signoz.cloud:443\"\nENV OTEL_EXPORTER_OTLP_HEADERS=\"signoz-ingestion-key=<your-ingestion-key>\"\nENV OTEL_METRICS_EXPORTER=\"none\"\nENV OTEL_LOGS_EXPORTER=\"none\"\n\nEXPOSE 8080\nCMD [\"catalina.sh\", \"run\"]\n```\n\nVerify these values:\n\n`<region>`\n\n: Your[SigNoz Cloud region](https://signoz.io/docs/ingestion/signoz-cloud/overview/#endpoint).`<your-ingestion-key>`\n\n: Your SigNoz[ingestion key](https://signoz.io/docs/ingestion/signoz-cloud/keys/).`<service-name>`\n\n: A descriptive name for your service (e.g.,`tomcat-app`\n\n).`<service-version>`\n\n(optional): Your release version, image tag, or git SHA (e.g.,`1.4.2`\n\n,`a01dbef8`\n\n).\n\nSet `service.version`\n\nto a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:\n\n**Bash / shell**:`service.version=$(git rev-parse --short HEAD)`\n\n**GitHub Actions**:`service.version=${{ github.sha }}`\n\n**GitLab CI**:`service.version=$CI_COMMIT_SHORT_SHA`\n\n**Kubernetes**: inject from your Helm chart image tag or CI variable\n\nStep 2. Build and run\n\n```\ndocker build -t my-tomcat-app .\ndocker run -p 8080:8080 my-tomcat-app\n```\n\nOr pass environment variables at runtime to avoid hardcoding credentials:\n\n```\ndocker run -p 8080:8080 \\\n  -e OTEL_RESOURCE_ATTRIBUTES=\"service.name=my-tomcat-app\" \\\n  -e OTEL_EXPORTER_OTLP_ENDPOINT=\"https://ingest.<region>.signoz.cloud:443\" \\\n  -e OTEL_EXPORTER_OTLP_HEADERS=\"signoz-ingestion-key=<key>\" \\\n  -e OTEL_METRICS_EXPORTER=\"none\" \\\n  -e OTEL_LOGS_EXPORTER=\"none\" \\\n  my-tomcat-app\n```\n\nValidate\n\nWith your Tomcat application running, verify traces are being sent to SigNoz:\n\n- Make a few requests to your deployed web applications.\n- In SigNoz, open the\n**Services** tab and click**Refresh**. Your service should appear. - Go to the\n**Traces** tab to see your application's traces.\n\nTroubleshooting\n\n[Troubleshooting](#troubleshooting)\n\nTraces not showing up in SigNoz?\n\n**Check that setenv.sh/setenv.bat is being loaded:**\n\nAdd a debug line to your setenv script:\n\n```\necho \"setenv.sh is being loaded\" >> /tmp/tomcat-debug.log\n```\n\nThen restart Tomcat and check if the log file was created.\n\n**Verify the agent is attached:**\n\nCheck your Tomcat logs (`catalina.out`\n\n) for OpenTelemetry startup messages:\n\n```\n[otel.javaagent] opentelemetry-javaagent - version: X.X.X\n```\n\n**Enable debug logging:**\n\nAdd to your setenv.sh:\n\n```\nexport OTEL_LOG_LEVEL=debug\n```\n\nLook for span output in Tomcat's logs. If spans appear locally but not in SigNoz, check your endpoint URL and ingestion key.\n\n**Test connectivity:**\n\n```\ncurl -v https://ingest.<region>.signoz.cloud:443/v1/traces\n```\n\nAgent not attaching?\n\n**Check file permissions:**\n\n```\nls -la /opt/tomcat/lib/opentelemetry-javaagent.jar\n```\n\nThe Tomcat user must have read access to the agent JAR.\n\n**Verify CATALINA_HOME:**\n\n```\necho $CATALINA_HOME\n```\n\nMake sure your setenv.sh is in the correct `bin`\n\ndirectory.\n\nsetenv.sh not found or not executed?\n\nOn some Linux distributions, Tomcat may be configured differently. Check:\n\n- The file is named exactly\n`setenv.sh`\n\n(case-sensitive) - The file is in\n`$CATALINA_HOME/bin/`\n\nor`$CATALINA_BASE/bin/`\n\n- The file has execute permissions:\n`chmod +x setenv.sh`\n\nConfiguring the agent (Optional)\n\n[Configuring the agent (Optional)](#configuring-the-agent-optional)\n\nWhat can you configure?\n\nThe Java agent auto-instruments most libraries out of the box. Configuration lets you fine-tune what gets captured and how traces are exported.\n\nWhy configure?\n\n**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\n\nCommon options\n\nAdd these to your `CATALINA_OPTS`\n\nin setenv.sh:\n\n**Disable specific instrumentations:**\n\n```\nexport CATALINA_OPTS=\"$CATALINA_OPTS -Dotel.instrumentation.jdbc-datasource.enabled=false\"\n```\n\n**Sample traces:**\n\n```\nexport OTEL_TRACES_SAMPLER=parentbased_traceidratio\nexport OTEL_TRACES_SAMPLER_ARG=0.1  # Sample 10% of traces\n```\n\n**Add resource attributes:**\n\n```\nexport OTEL_RESOURCE_ATTRIBUTES=\"service.name=my-tomcat-app,deployment.environment=production,service.version=1.2.3\"\n```\n\nSee the [full configuration reference](https://opentelemetry.io/docs/languages/java/automatic/agent-config/) for all available options.\n\nNext steps\n\n[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", "url": "https://wpnews.pro/news/tomcat-opentelemetry-instrumentation-guide", "canonical_source": "https://signoz.io/docs/instrumentation/java/opentelemetry-tomcat", "published_at": "2026-06-23 00:00:00+00:00", "updated_at": "2026-06-24 06:45:35.379855+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools"], "entities": ["Apache Tomcat", "OpenTelemetry", "SigNoz", "Java", "Docker", "Kubernetes"], "alternates": {"html": "https://wpnews.pro/news/tomcat-opentelemetry-instrumentation-guide", "markdown": "https://wpnews.pro/news/tomcat-opentelemetry-instrumentation-guide.md", "text": "https://wpnews.pro/news/tomcat-opentelemetry-instrumentation-guide.txt", "jsonld": "https://wpnews.pro/news/tomcat-opentelemetry-instrumentation-guide.jsonld"}}