1) Prerequisites
- Elastic Cloud deployment with Observability enabled (free trial works).
In the Elastic Cloud console, you’ll later copy:- APM Server URL (looks like
https://<hash>.apm.<region>.cloud.es.io:443
) - Secret token or an APM Agent key (API key). (Elastic, Microsoft Learn)
- APM Server URL (looks like
- Tomcat on Linux (e.g.,
/opt/tomcat
or distro path like/usr/share/tomcat
). - Java 8+ (Java 17/21 are fine); outbound HTTPS (443) to
*.cloud.es.io
. - Shell access (sudo) to install files and restart Tomcat.
About auth
2) Get your APM endpoint & token/key from Elastic Cloud
- Open your Elastic Cloud deployment
- Go to Observability → APM (or APM & Fleet), copy the APM Server URL and either the Secret token or generate an APM Agent key. (Elastic, Microsoft Learn)
3) Download the Elastic APM Java Agent
Create a directory for the agent and download the current jar:
sudo mkdir -p /opt/elastic/apm
# (Replace <version> with the latest, e.g., 1.46.0)
sudo curl -L -o /opt/elastic/apm/elastic-apm-agent-<version>.jar \
"https://search.maven.org/remotecontent?filepath=co/elastic/apm/elastic-apm-agent/<version>/elastic-apm-agent-<version>.jar"
sudo chmod 644 /opt/elastic/apm/elastic-apm-agent-<version>.jar
Code language: HTML, XML (xml)
The agent jar is published by Elastic; latest versions and source are here if you need to verify: elastic/apm-agent-java. (GitHub)
4) (Recommended) Keep credentials out of ps
output
Create a tiny env file readable only by root/Tomcat that holds your token or API key:
# Pick ONE: secret token OR API key
# Secret token variant
sudo bash -c 'cat >/etc/elastic-apm.env' <<'EOF'
ELASTIC_APM_SECRET_TOKEN=YOUR_SECRET_TOKEN_HERE
# or, API key variant (preferred)
# ELASTIC_APM_API_KEY=YOUR_API_KEY_HERE
EOF
sudo chmod 600 /etc/elastic-apm.env
Code language: PHP (php)
You’ll reference this file from setenv.sh
so the secrets don’t appear in process lists.
5) Wire the agent into Tomcat (setenv.sh)
Tomcat reads a setenv.sh
(same folder as catalina.sh
) on startup. Create it if missing.
# Find your Tomcat base; examples:
# export CATALINA_HOME=/opt/tomcat
# or distro paths like /usr/share/tomcat or /usr/share/tomcat9
cd "$CATALINA_HOME/bin"
sudo bash -c 'cat >setenv.sh' <<'EOF'
#!/usr/bin/env bash
# Load secrets
[ -f /etc/elastic-apm.env ] && . /etc/elastic-apm.env
# Path to the agent
AGENT_JAR="/opt/elastic/apm/elastic-apm-agent-<version>.jar"
# Core APM config (minimal)
CATALINA_OPTS="$CATALINA_OPTS -javaagent:${AGENT_JAR}"
CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.service_name=my-tomcat-app"
CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.server_url=https://<your-cloud-apm-endpoint>:443"
CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.environment=prod"
CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.application_packages=com.yourcompany,org.example"
# Auth: use ONE of the following (API key preferred)
# Secret token
[ -n "$ELASTIC_APM_SECRET_TOKEN" ] && \
CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.secret_token=${ELASTIC_APM_SECRET_TOKEN}"
# API key
[ -n "$ELASTIC_APM_API_KEY" ] && \
CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.api_key=${ELASTIC_APM_API_KEY}"
# Useful production defaults / hygiene
CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.capture_body=errors"
CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.global_labels=org=MyCo,team=platform,region=jp"
# (Log correlation is ON by default in recent agent versions)
# CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.log_level=info"
export CATALINA_OPTS
EOF
sudo chmod +x setenv.sh
Code language: PHP (php)
Why these options?
service_name
,server_url
,application_packages
are the key minimums for Java agent. (Elastic)global_labels
adds useful searchable tags across all APM events. (Elastic)- Log correlation with your logs is enabled by default in agent ≥ 1.30 (no extra flag needed). (Elastic)
If you prefer central configuration (set most options from Kibana APM UI), that’s also supported and can override local settings. (Elastic)
6) Restart Tomcat
For a tarball install:
$CATALINA_HOME/bin/shutdown.sh || true
$CATALINA_HOME/bin/startup.sh
Code language: PHP (php)
For a systemd install:
sudo systemctl daemon-reload
sudo systemctl restart tomcat # or tomcat9, etc.
sudo journalctl -u tomcat -f
Code language: PHP (php)
You should see the agent initialize in catalina.out
/service logs.
7) Generate traffic & verify in Kibana
- Hit a few app endpoints (e.g., your web app pages or APIs).
- In Kibana → Observability → APM → Services, your
service_name
should appear with transactions and traces. (Elastic)
Connectivity check (optional):
# Quick probe that APM server is up (expects 200)
curl -s -o /dev/null -w "%{http_code}\n" https://<your-cloud-apm-endpoint>/
Code language: PHP (php)
The APM Server Information endpoint returns 200 when reachable. (Auth is still required by the agent for sending data.) (Elastic)
8) Production hardening & nice-to-haves
- Use an APM Agent key instead of a secret token for better control/rotation. (Elastic)
- Sampling: adjust volume vs. detail
-Delastic.apm.transaction_sample_rate=0.2 # 20% traces
- Sensitive data: keep request bodies off by default (
capture_body=off
) or restrict toerrors
/transactions
only; you can fine-tune per endpoint in Kibana later. (Elastic) - Proxies / firewalls: ensure egress to your Cloud APM URL:443; add standard JVM proxy flags if needed (
-Dhttps.proxyHost
,-Dhttps.proxyPort
). - Multiple apps on one Tomcat: use separate
service_name
per instance (simplest via separate start wrappers/env). (Stack Overflow) - Central config: once data flows, you can flip tuning options in Kibana APM without restarts. (Elastic)
9) Troubleshooting checklist
- Agent loaded? Look for “Elastic APM agent initialized” in Tomcat logs.
- Auth errors? Re-copy the Secret token or APM Agent key from Kibana; mismatches are the most common issue. (Elastic)
- Endpoint reachable?
curl
the APM server URL as above; if blocked, fix firewall/egress rules. (Elastic) - Verbose logs (temporarily):
CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.log_level=debug"
- Handshake/SSL issues? The agent uses your JVM CA truststore; ensure up-to-date CA certificates.
- No services showing? Make sure
service_name
is set and generate a few real requests. (Elastic)
10) Copy-paste example (using your values)
Note: replace placeholder values; keep your token/key secret.
# /opt/tomcat/bin/setenv.sh (snippet)
export CATALINA_OPTS="$CATALINA_OPTS -javaagent:/opt/elastic/apm/elastic-apm-agent-<version>.jar"
export CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.service_name=my-service-name"
export CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.server_url=https://fb97fae75f1b43b4b6ccfc4921e8b13d.apm.us-central1.gcp.cloud.es.io:443"
export CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.environment=my-environment"
export CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.application_packages=org.example"
# ONE of the following:
export CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.secret_token=********"
# export CATALINA_OPTS="$CATALINA_OPTS -Delastic.apm.api_key=********"
Code language: PHP (php)
That’s it! Once Tomcat restarts and traffic hits your app, you’ll see your service in Kibana → APM with traces, spans, errors, and metrics.
I’m a DevOps/SRE/DevSecOps/Cloud Expert passionate about sharing knowledge and experiences. I have worked at Cotocus. I share tech blog at DevOps School, travel stories at Holiday Landmark, stock market tips at Stocks Mantra, health and fitness guidance at My Medic Plus, product reviews at TrueReviewNow , and SEO strategies at Wizbrand.
Do you want to learn Quantum Computing?
Please find my social handles as below;
Rajesh Kumar Personal Website
Rajesh Kumar at YOUTUBE
Rajesh Kumar at INSTAGRAM
Rajesh Kumar at X
Rajesh Kumar at FACEBOOK
Rajesh Kumar at LINKEDIN
Rajesh Kumar at WIZBRAND