Set up comprehensive Jetty monitoring using JMX metrics collection with Prometheus JMX Exporter and visualize performance data through custom Grafana dashboards with automated alerting.
Prerequisites
- Root or sudo access
- At least 4GB RAM
- Java 11 or later
- Network access for downloads
What this solves
Jetty web server performance monitoring requires collecting JMX metrics and visualizing them through dashboards. This setup enables you to track connection pools, thread usage, request processing times, and memory consumption in real-time. You'll configure Prometheus JMX Exporter to collect Jetty metrics and create Grafana dashboards for comprehensive application server observability.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest versions of all components.
sudo apt update && sudo apt upgrade -yInstall Java and required packages
Jetty requires Java 11 or later. Install OpenJDK along with wget for downloading components.
sudo apt install -y openjdk-17-jdk wget curl unzipDownload and install Jetty 12
Download Jetty 12 from the official repository and extract it to a dedicated directory.
cd /opt
sudo wget https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-home/12.0.5/jetty-home-12.0.5.tar.gz
sudo tar -xzf jetty-home-12.0.5.tar.gz
sudo mv jetty-home-12.0.5 jetty-home
sudo chown -R jetty:jetty /opt/jetty-homeCreate Jetty user and directories
Create a dedicated user for running Jetty and set up the required directory structure.
sudo useradd -r -s /bin/false jetty
sudo mkdir -p /opt/jetty-base
sudo mkdir -p /opt/jetty-base/webapps
sudo mkdir -p /opt/jetty-base/logs
sudo chown -R jetty:jetty /opt/jetty-baseConfigure Jetty base directory
Initialize the Jetty base directory with required modules including JMX support.
cd /opt/jetty-base
sudo -u jetty java -jar /opt/jetty-home/start.jar --add-module=server,http,deploy,jsp,jstl,websocket,jmxDownload Prometheus JMX Exporter
Download the JMX Exporter JAR file that will collect Jetty metrics for Prometheus.
sudo mkdir -p /opt/jmx-exporter
cd /opt/jmx-exporter
sudo wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.20.0/jmx_prometheus_javaagent-0.20.0.jar
sudo chown jetty:jetty jmx_prometheus_javaagent-0.20.0.jarCreate JMX Exporter configuration
Configure the JMX Exporter to collect specific Jetty metrics including connection pools, threads, and request statistics.
rules:
# Jetty Server metrics
- pattern: 'org.eclipse.jetty.server<>(.+):(.+)'
name: jetty_server_$3
labels:
type: "$1"
id: "$2"
attribute: "$4"
# Jetty Handler metrics
- pattern: 'org.eclipse.jetty.server.handler<>(.+)'
name: jetty_handler_$3
labels:
type: "$1"
id: "$2"
# Jetty ThreadPool metrics
- pattern: 'org.eclipse.jetty.util.thread<>(.+)'
name: jetty_threadpool_$3
labels:
type: "$1"
id: "$2"
# Jetty Connector metrics
- pattern: 'org.eclipse.jetty.server<>(.+)'
name: jetty_connector_$4
labels:
type: "$1"
context: "$2"
id: "$3"
# JVM metrics
- pattern: 'java.lang(.+)'
name: jvm_memory_heap_$1
- pattern: 'java.lang(.+)'
name: jvm_memory_nonheap_$1
- pattern: 'java.lang<>CollectionCount'
name: jvm_gc_collections_total
labels:
gc: "$1"
- pattern: 'java.lang<>CollectionTime'
name: jvm_gc_collection_time_seconds
labels:
gc: "$1"
valueFactor: 0.001 Configure Jetty JVM options
Create a configuration file to enable JMX and attach the Prometheus JMX Exporter to Jetty.
# Enable JMX
--module=jmx
JMX configuration
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=1099
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
JMX Exporter configuration
-javaagent:/opt/jmx-exporter/jmx_prometheus_javaagent-0.20.0.jar=8081:/opt/jmx-exporter/jetty-config.yamlCreate systemd service for Jetty
Set up a systemd service to manage Jetty with proper user permissions and automatic startup.
[Unit]
Description=Jetty Web Server
After=network.target
[Service]
Type=forking
User=jetty
Group=jetty
Environment="JETTY_HOME=/opt/jetty-home"
Environment="JETTY_BASE=/opt/jetty-base"
Environment="JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64"
WorkingDirectory=/opt/jetty-base
ExecStart=/usr/bin/java -jar /opt/jetty-home/start.jar
ExecStop=/usr/bin/java -jar /opt/jetty-home/start.jar --stop
PIDFile=/opt/jetty-base/jetty.pid
Restart=on-failure
RestartSec=10
Security settings
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/jetty-base
[Install]
WantedBy=multi-user.targetInstall Prometheus
Install Prometheus to collect metrics from the JMX Exporter endpoint.
sudo apt install -y prometheusConfigure Prometheus to scrape Jetty metrics
Add the JMX Exporter endpoint to Prometheus configuration for metric collection.
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'jetty'
static_configs:
- targets: ['localhost:8081']
scrape_interval: 10s
metrics_path: /metrics
static_configs:
- targets: ['localhost:8081']
labels:
instance: 'jetty-server'
service: 'jetty'Install and configure Grafana
Install Grafana for creating dashboards and visualization of Jetty metrics.
sudo apt install -y software-properties-common
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt update
sudo apt install -y grafanaEnable and start all services
Start Jetty, Prometheus, and Grafana services and enable them for automatic startup.
sudo systemctl daemon-reload
sudo systemctl enable --now jetty
sudo systemctl enable --now prometheus
sudo systemctl enable --now grafana-serverConfigure firewall rules
Open the necessary ports for Jetty web interface, JMX metrics, Prometheus, and Grafana.
sudo ufw allow 8080/tcp comment 'Jetty Web Server'
sudo ufw allow 8081/tcp comment 'JMX Exporter'
sudo ufw allow 9090/tcp comment 'Prometheus'
sudo ufw allow 3000/tcp comment 'Grafana'Create Grafana data source
Configure Prometheus as a data source in Grafana for accessing Jetty metrics.
curl -X POST -H "Content-Type: application/json" -d '{
"name": "Prometheus",
"type": "prometheus",
"url": "http://localhost:9090",
"access": "proxy",
"basicAuth": false
}' http://admin:admin@localhost:3000/api/datasourcesImport Jetty dashboard
Create a comprehensive Grafana dashboard for monitoring Jetty performance metrics.
{
"dashboard": {
"id": null,
"title": "Jetty Performance Monitoring",
"tags": ["jetty", "jmx", "performance"],
"timezone": "browser",
"panels": [
{
"id": 1,
"title": "HTTP Requests Rate",
"type": "graph",
"targets": [
{
"expr": "rate(jetty_server_requests_total[5m])",
"legendFormat": "Requests/sec"
}
],
"yAxes": [
{
"label": "Requests per second"
}
],
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 0}
},
{
"id": 2,
"title": "Response Times",
"type": "graph",
"targets": [
{
"expr": "jetty_server_response_time_seconds",
"legendFormat": "Response Time"
}
],
"yAxes": [
{
"label": "Seconds"
}
],
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 0}
},
{
"id": 3,
"title": "Thread Pool Status",
"type": "graph",
"targets": [
{
"expr": "jetty_threadpool_threads",
"legendFormat": "Total Threads"
},
{
"expr": "jetty_threadpool_idle_threads",
"legendFormat": "Idle Threads"
},
{
"expr": "jetty_threadpool_busy_threads",
"legendFormat": "Busy Threads"
}
],
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 8}
},
{
"id": 4,
"title": "JVM Memory Usage",
"type": "graph",
"targets": [
{
"expr": "jvm_memory_heap_used",
"legendFormat": "Heap Used"
},
{
"expr": "jvm_memory_heap_max",
"legendFormat": "Heap Max"
}
],
"yAxes": [
{
"label": "Bytes",
"logBase": 1
}
],
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 8}
}
],
"time": {
"from": "now-1h",
"to": "now"
},
"refresh": "10s"
}
}Import the dashboard using the Grafana API:
curl -X POST -H "Content-Type: application/json" -d @/tmp/jetty-dashboard.json \
http://admin:admin@localhost:3000/api/dashboards/dbConfigure alerting rules
Set up Prometheus alerting rules for critical Jetty performance thresholds.
groups:
- name: jetty.rules
rules:
- alert: JettyHighResponseTime
expr: jetty_server_response_time_seconds > 2
for: 5m
labels:
severity: warning
annotations:
summary: "Jetty response time is high"
description: "Response time has been above 2 seconds for more than 5 minutes"
- alert: JettyThreadPoolExhaustion
expr: (jetty_threadpool_busy_threads / jetty_threadpool_threads) > 0.9
for: 2m
labels:
severity: critical
annotations:
summary: "Jetty thread pool near exhaustion"
description: "Thread pool utilization is above 90%"
- alert: JettyHighMemoryUsage
expr: (jvm_memory_heap_used / jvm_memory_heap_max) > 0.85
for: 5m
labels:
severity: warning
annotations:
summary: "Jetty JVM memory usage high"
description: "JVM heap memory usage is above 85%"
- alert: JettyDown
expr: up{job="jetty"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Jetty server is down"
description: "Jetty server has been down for more than 1 minute"Update Prometheus configuration for alerts
Add the alerting rules to Prometheus configuration and restart the service.
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "jetty-alerts.yml"
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'jetty'
static_configs:
- targets: ['localhost:8081']
scrape_interval: 10s
metrics_path: /metrics
static_configs:
- targets: ['localhost:8081']
labels:
instance: 'jetty-server'
service: 'jetty'Restart Prometheus to apply the new configuration:
sudo systemctl restart prometheusVerify your setup
Check that all services are running and metrics are being collected properly.
sudo systemctl status jetty
sudo systemctl status prometheus
sudo systemctl status grafana-server
Test Jetty is responding
curl http://localhost:8080
Test JMX metrics endpoint
curl http://localhost:8081/metrics | grep jetty
Test Prometheus targets
curl http://localhost:9090/api/v1/targetsAccess the web interfaces:
- Jetty:
http://your-server:8080 - Prometheus:
http://your-server:9090 - Grafana:
http://your-server:3000(admin/admin)
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| JMX metrics not appearing | JMX not enabled in Jetty | Check /opt/jetty-base/start.d/jmx-monitoring.ini configuration |
| Prometheus can't scrape metrics | JMX Exporter not running | Check if port 8081 is accessible: netstat -tlnp | grep 8081 |
| Grafana shows no data | Data source not configured | Verify Prometheus data source URL in Grafana settings |
| Jetty won't start | Port already in use | Check port usage: sudo lsof -i :8080 |
| Alerts not firing | Alert rules not loaded | Check Prometheus rules: curl http://localhost:9090/api/v1/rules |
| High memory usage | Insufficient JVM heap | Adjust JVM heap size in Jetty service configuration |
Next steps
- Set up Jetty clustering and session replication for high availability deployments
- Configure system time monitoring to ensure accurate metrics timestamps
- Set up backup monitoring for your Jetty configuration and data
- Configure advanced Grafana alerting with webhook notifications
- Configure Jetty with SSL termination using NGINX reverse proxy
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Configuration
JETTY_VERSION="12.0.5"
JMX_EXPORTER_VERSION="0.20.0"
JETTY_HOME="/opt/jetty-home"
JETTY_BASE="/opt/jetty-base"
JMX_EXPORTER_DIR="/opt/jmx-exporter"
# Functions
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
usage() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " -h, --help Show this help message"
echo ""
echo "This script installs Jetty with JMX monitoring and Prometheus exporter"
exit 1
}
cleanup() {
log_error "Installation failed. Cleaning up..."
systemctl stop jetty 2>/dev/null || true
userdel jetty 2>/dev/null || true
rm -rf "$JETTY_HOME" "$JETTY_BASE" "$JMX_EXPORTER_DIR" 2>/dev/null || true
rm -f /etc/systemd/system/jetty.service 2>/dev/null || true
systemctl daemon-reload 2>/dev/null || true
}
trap cleanup ERR
check_prerequisites() {
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root"
exit 1
fi
if ! command -v systemctl &> /dev/null; then
log_error "systemd is required but not found"
exit 1
fi
}
detect_distro() {
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update && apt upgrade -y"
JAVA_PACKAGE="openjdk-17-jdk"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
JAVA_PACKAGE="java-17-openjdk-devel"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum update -y"
JAVA_PACKAGE="java-17-openjdk-devel"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
else
log_error "Cannot detect distribution"
exit 1
fi
log_info "Detected distribution: $ID"
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
usage
;;
*)
log_error "Unknown option: $1"
usage
;;
esac
done
# Main installation
check_prerequisites
detect_distro
echo "[1/10] Updating system packages..."
$PKG_UPDATE
echo "[2/10] Installing Java and required packages..."
$PKG_INSTALL $JAVA_PACKAGE wget curl unzip
echo "[3/10] Creating Jetty user..."
if ! id jetty &>/dev/null; then
useradd -r -s /bin/false jetty
log_info "Created jetty user"
fi
echo "[4/10] Downloading and installing Jetty..."
cd /opt
wget -q "https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-home/${JETTY_VERSION}/jetty-home-${JETTY_VERSION}.tar.gz"
tar -xzf "jetty-home-${JETTY_VERSION}.tar.gz"
mv "jetty-home-${JETTY_VERSION}" jetty-home
rm "jetty-home-${JETTY_VERSION}.tar.gz"
chown -R jetty:jetty "$JETTY_HOME"
echo "[5/10] Setting up Jetty base directory..."
mkdir -p "$JETTY_BASE"/{webapps,logs}
chown -R jetty:jetty "$JETTY_BASE"
echo "[6/10] Configuring Jetty modules..."
cd "$JETTY_BASE"
sudo -u jetty java -jar "$JETTY_HOME/start.jar" --add-module=server,http,deploy,jsp,jstl,websocket,jmx
echo "[7/10] Downloading Prometheus JMX Exporter..."
mkdir -p "$JMX_EXPORTER_DIR"
cd "$JMX_EXPORTER_DIR"
wget -q "https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/${JMX_EXPORTER_VERSION}/jmx_prometheus_javaagent-${JMX_EXPORTER_VERSION}.jar"
chown -R jetty:jetty "$JMX_EXPORTER_DIR"
echo "[8/10] Creating JMX Exporter configuration..."
cat > "$JMX_EXPORTER_DIR/jetty-config.yaml" << 'EOF'
rules:
- pattern: 'org.eclipse.jetty.server(.+):(.+)'
name: jetty_server_$3
labels:
type: "$1"
id: "$2"
- pattern: 'org.eclipse.jetty.util.thread(.+)'
name: jetty_threadpool_$3
labels:
type: "$1"
id: "$2"
- pattern: 'java.lang:type=Memory,name=(.+)'
name: jvm_memory_$1
- pattern: 'java.lang:type=GarbageCollector,name=(.+)'
name: jvm_gc_$1
EOF
chown jetty:jetty "$JMX_EXPORTER_DIR/jetty-config.yaml"
chmod 644 "$JMX_EXPORTER_DIR/jetty-config.yaml"
echo "[9/10] Creating Jetty JVM configuration..."
cat > "$JETTY_BASE/start.ini" << EOF
--module=jmx
# JMX configuration
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=1099
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
# JMX Exporter configuration
-javaagent:$JMX_EXPORTER_DIR/jmx_prometheus_javaagent-$JMX_EXPORTER_VERSION.jar=8081:$JMX_EXPORTER_DIR/jetty-config.yaml
EOF
chown jetty:jetty "$JETTY_BASE/start.ini"
chmod 644 "$JETTY_BASE/start.ini"
echo "[10/10] Creating systemd service..."
cat > /etc/systemd/system/jetty.service << EOF
[Unit]
Description=Jetty Web Server
After=network.target
[Service]
Type=forking
User=jetty
Group=jetty
WorkingDirectory=$JETTY_BASE
ExecStart=/usr/bin/java -jar $JETTY_HOME/start.jar
ExecReload=/bin/kill -HUP \$MAINPID
KillMode=mixed
SuccessExitStatus=143
StandardOutput=journal
StandardError=journal
SyslogIdentifier=jetty
PIDFile=$JETTY_BASE/jetty.pid
[Install]
WantedBy=multi-user.target
EOF
chmod 644 /etc/systemd/system/jetty.service
systemctl daemon-reload
systemctl enable jetty
systemctl start jetty
# Configure firewall
if command -v firewall-cmd &> /dev/null; then
firewall-cmd --permanent --add-port=8080/tcp --add-port=8081/tcp --add-port=1099/tcp 2>/dev/null || true
firewall-cmd --reload 2>/dev/null || true
elif command -v ufw &> /dev/null; then
ufw allow 8080/tcp 2>/dev/null || true
ufw allow 8081/tcp 2>/dev/null || true
ufw allow 1099/tcp 2>/dev/null || true
fi
# Verification
sleep 5
if systemctl is-active --quiet jetty; then
log_info "Jetty service is running"
else
log_error "Jetty service failed to start"
systemctl status jetty
exit 1
fi
if curl -s localhost:8081/metrics | grep -q jetty; then
log_info "JMX metrics are available at http://localhost:8081/metrics"
else
log_warn "JMX metrics endpoint not responding yet (may need more time)"
fi
log_info "Installation completed successfully!"
log_info "Jetty web server: http://localhost:8080"
log_info "JMX metrics: http://localhost:8081/metrics"
log_info "JMX port: 1099"
log_info "Service logs: journalctl -u jetty -f"
Review the script before running. Execute with: bash install.sh