Transform Your Prometheus Metrics into AppDynamics Custom Metrics in Minutes
As organizations adopt cloud-native architectures, monitoring becomes increasingly complex. You might have applications exposing Prometheus metrics, but your enterprise standardizes on AppDynamics for observability, alerting, and business dashboards.
What if you could monitor ANY Prometheus-enabled application in AppDynamics without changing a single line of code?
In this article, I’ll show you how to build a Universal Prometheus to AppDynamics converter that automatically transforms any Prometheus metrics into AppDynamics Custom Metrics, complete with organized hierarchies and human-readable names.
The gap? No native way to import Prometheus metrics into AppDynamics while preserving the rich label context and maintaining organized metric hierarchies.
Our solution uses AppDynamics Machine Agent Custom Extensions to:
┌─────────────────┐ ┌──────────────────┐ ┌────────────────────┐
│ Application │ │ Machine Agent │ │ AppDynamics │
│ │ │ │ │ Controller │
│ Prometheus │───▶│ Universal │───▶│ │
│ /metrics │ │ Converter │ │ Custom Metrics │
│ Endpoint │ │ Extension │ │ Dashboards │
└─────────────────┘ └──────────────────┘ └────────────────────┘
Data Flow:
Our sample application is a comprehensive e-commerce microservice that demonstrates realistic Prometheus metrics for AppDynamics integration.
# Clone the repository
git clone https://github.com/Abhimanyu9988/universal-prometheus-appdynamics
cd universal-prometheus-appdynamics
# Install dependencies
pip install -r requirements.txt
# Start the sample application
python sample-app/microservice.py
Application will start with:
Our sample application simulates a realistic e-commerce microservice with comprehensive business and infrastructure metrics:
Key Features:
Quick Start:
# Clone the repository
git clone https://github.com/Abhimanyu9988/universal-prometheus-appdynamics
cd universal-prometheus-appdynamics
# Install dependencies
pip install -r requirements.txt
# Start the sample application
python sample-app/microservice.py
Sample Metrics Generated:
Curl below
http://localhost:8080/actuator/prometheus
to see metrics like:
# Business Metrics
orders_processed_total{product_category="electronics",region="us_east",payment_method="credit_card"} 15
order_value_dollars{product_category="electronics",customer_tier="gold"} 750
active_users_current{user_type="premium",subscription_tier="pro"} 45
conversion_rate_percentage{traffic_source="organic",product_category="electronics"} 6.2
# Infrastructure Metrics
database_connections_active{database_name="user_db",connection_type="read"} 12
cache_hits_total{cache_type="redis",cache_key_pattern="user_*"} 1247
memory_usage_bytes{memory_type="heap"} 856000000
api_requests_total{method="POST",endpoint="/api/orders",status_code="200"} 89
Generate Test Data:
# Create orders
curl -X POST http://localhost:8080/api/orders
curl -X POST http://localhost:8080/api/orders
# User sessions
curl -X POST http://localhost:8080/api/users/user123/session
# Cart abandonment
curl -X POST http://localhost:8080/api/cart/abandon
The complete application code is available in the GitHub repository at sample-app/microservice.py with additional features including:
📁 Full Implementation: View on GitHub
python3 sample_microservice.py
Visit http://localhost:8080/actuator/prometheus to see metrics like:
# HELP orders_processed_total Total orders processed
# TYPE orders_processed_total counter
orders_processed_total{product_type="electronics",region="us-east"} 15.0
orders_processed_total{product_type="clothing",region="europe"} 8.0
# HELP active_users_current Current number of active users
# TYPE active_users_current gauge
active_users_current{user_type="premium"} 45.0
active_users_current{user_type="standard"} 78.0
Now let’s create the Universal Converter that transforms ANY Prometheus metrics into AppDynamics format:
The Universal Converter transforms any Prometheus metrics into AppDynamics format. Here’s how it works with our sample application:
Input (Prometheus Format):
orders_processed_total{product_category="electronics",region="us_east",payment_method="credit_card"} 15
active_users_current{user_type="premium",subscription_tier="pro"} 45
database_connections_active{database_name="user_db",connection_type="read"} 12
Output (AppDynamics Format):
name=Custom Metrics|App|Orders Processed Total|Product Category Electronics|Region Us East|Payment Method Credit Card,value=15,aggregator=OBSERVATION,time-rollup=CURRENT,cluster-rollup=COLLECTIVE
name=Custom Metrics|App|Active Users Current|User Type Premium|Subscription Tier Pro,value=45,aggregator=OBSERVATION,time-rollup=CURRENT,cluster-rollup=INDIVIDUAL
name=Custom Metrics|App|Database Connections Active|Database Name User Db|Connection Type Read,value=12,aggregator=OBSERVATION,time-rollup=CURRENT,cluster-rollup=INDIVIDUAL
Core Conversion Functions:
Complete code :
#!/bin/bash
# Universal Prometheus to AppDynamics Converter
# Transforms: orders_processed_total{product_type="electronics"} 15
# Into: Custom Metrics|App|Orders Processed Total|Product Type Electronics,value=15
PROMETHEUS_ENDPOINT="http://localhost:8080/actuator/prometheus"
MAX_METRICS=100
# Convert snake_case to Title Case
convert_to_title_case() {
echo "$1" | sed 's/_/ /g' | sed 's/\b\w/\U&/g'
}
# Clean label values for AppDynamics hierarchy
clean_label_value() {
echo "$1" | sed 's/"//g' | sed 's/[^a-zA-Z0-9.]/ /g' | sed 's/\b\w/\U&/g'
}
# Process each metric line
process_metric_line() {
local line="$1"
# Parse: metric_name{labels} value
if [[ "$line" =~ ^([a-zA-Z_][a-zA-Z0-9_]*)(.*)[[:space:]]+([0-9.]+)$ ]]; then
local metric_name="${BASH_REMATCH[1]}"
local labels_part="${BASH_REMATCH[2]}"
local value="${BASH_REMATCH[3]}"
# Convert to human readable
local readable_name=$(convert_to_title_case "$metric_name")
local metric_path="Custom Metrics|App|$readable_name"
# Process labels into hierarchy
if [[ "$labels_part" =~ ^\{.*\}$ ]]; then
labels_part="${labels_part#\{}"
labels_part="${labels_part%\}}"
IFS=',' read -ra LABELS <<< "$labels_part"
for label in "${LABELS[@]}"; do
if [[ "$label" =~ ^[[:space:]]*([^=]+)=[[:space:]]*\"?([^\"]+)\"?$ ]]; then
local key=$(convert_to_title_case "${BASH_REMATCH[1]}")
local val=$(clean_label_value "${BASH_REMATCH[2]}")
metric_path="$metric_path|$key $val"
fi
done
fi
# Output AppDynamics format
echo "name=$metric_path,value=${value%.*},aggregator=OBSERVATION,time-rollup=CURRENT,cluster-rollup=INDIVIDUAL"
fi
}
# Main execution
METRICS_DATA=$(curl -s --max-time 30 "$PROMETHEUS_ENDPOINT")
if [ $? -ne 0 ]; then
echo "name=Custom Metrics|App|Connection Status,value=0,aggregator=OBSERVATION,time-rollup=CURRENT,cluster-rollup=INDIVIDUAL"
exit 1
fi
echo "name=Custom Metrics|App|Connection Status,value=1,aggregator=OBSERVATION,time-rollup=CURRENT,cluster-rollup=INDIVIDUAL"
# Process all metrics
metric_count=0
while IFS= read -r line && [ $metric_count -lt $MAX_METRICS ]; do
result=$(process_metric_line "$line")
if [ ! -z "$result" ]; then
echo "$result"
((metric_count++))
fi
done <<< "$METRICS_DATA"
Before (Prometheus):
orders_processed_total{product_category="electronics",region="us_east",payment_method="credit_card"} 15
active_users_current{user_type="premium",subscription_tier="pro"} 45
database_connections_active{database_name="user_db",connection_type="read"} 12
After (AppDynamics Hierarchy):
Custom Metrics
└── App
├── Orders Processed Total
│ └── Product Category Electronics
│ └── Region Us East
│ └── Payment Method Credit Card = 15
├── Active Users Current
│ └── User Type Premium
│ └── Subscription Tier Pro = 45
└── Database Connections Active
└── Database Name User Db
└── Connection Type Read = 12
mkdir -p /opt/appdynamics/machine-agent/monitors/UniversalPrometheusMonitor
cd /opt/appdynamics/machine-agent/monitors/UniversalPrometheusMonitor
# Save the full converter script
cat > UniversalPrometheusMonitor.sh << 'EOF'
[Full script content from above]
EOF
chmod +x UniversalPrometheusMonitor.sh
<?xml version="1.0" encoding="UTF-8"?>
<monitor>
<name>UniversalPrometheusMonitor</name>
<type>managed</type>
<description>Universal Prometheus to AppDynamics Converter</description>
<monitor-run-task>
<execution-style>periodic</execution-style>
<execution-frequency-in-seconds>60</execution-frequency-in-seconds>
<name>Universal Prometheus Collection</name>
<type>executable</type>
<execution-timeout-in-secs>60</execution-timeout-in-secs>
<task-arguments>
</task-arguments>
<executable-task>
<type>file</type>
<file>UniversalPrometheusMonitor.sh</file>
</executable-task>
</monitor-run-task>
</monitor>
# Test manually
./UniversalPrometheusMonitor.sh
# Restart Machine Agent
sudo systemctl restart machine-agent
After 2–3 minutes, navigate to:
Metric Browser → Application Infrastructure Performance → [Machine Agent] → Custom Metrics → App
You’ll see organized metrics like:
This solution works perfectly for:
# Filter specific metrics
INCLUDE_PATTERNS="orders_|users_|database_"
EXCLUDE_PATTERNS="_bucket|_sum|_count"
if [[ "$metric_name" =~ $INCLUDE_PATTERNS ]] && [[ ! "$metric_name" =~ $EXCLUDE_PATTERNS ]]; then
# Process metric
fi
# Map technical names to business terms
case "$metric_name" in
"orders_processed_total") readable_name="Revenue Orders";;
"active_users_current") readable_name="Online Customers";;
"database_connections_active") readable_name="DB Performance";;
*) readable_name=$(convert_to_title_case "$metric_name");;
esac
# Set appropriate aggregation based on metric type
if [[ "$metric_name" =~ _total$ ]]; then
aggregator="OBSERVATION"
cluster_rollup="COLLECTIVE"
elif [[ "$metric_name" =~ _current$ ]]; then
aggregator="OBSERVATION"
cluster_rollup="INDIVIDUAL"
fi
The converter includes built-in monitoring:
# Connection status
name=Custom Metrics|App|Connection Status,value=1
# Metrics processed
name=Custom Metrics|App|Monitoring|Total Metrics Processed,value=67
# Test the converter manually
./UniversalPrometheusMonitor.sh | head -20
# Check Machine Agent logs
tail -f /opt/appdynamics/machine-agent/logs/machine-agent.log | grep Universal
# Verify endpoint connectivity
curl http://localhost:8080/actuator/prometheus | head -10
MAX_METRICS=100 # Prevent overwhelming AppDynamics
BATCH_SIZE=50 # Process in batches for large metric sets
# For high-volume environments
TIMEOUT=10 # Shorter timeouts
FREQUENCY=120 # Less frequent collection (2 minutes)
# Use local endpoints when possible
PROMETHEUS_ENDPOINT="http://localhost:8080/actuator/prometheus"
# Add retry logic
for i in {1..3}; do
METRICS_DATA=$(curl -s --max-time $TIMEOUT "$PROMETHEUS_ENDPOINT")
[ $? -eq 0 ] && break
sleep 5
done
# For secured Prometheus endpoints
curl -H "Authorization: Bearer $TOKEN" "$PROMETHEUS_ENDPOINT"
# Or with basic auth
curl -u "$USERNAME:$PASSWORD" "$PROMETHEUS_ENDPOINT"
# For HTTPS endpoints
curl --cacert /path/to/ca.crt "$PROMETHEUS_ENDPOINT"
# Development
PROMETHEUS_ENDPOINT="http://dev-app:8080/actuator/prometheus"
METRIC_PREFIX="Custom Metrics|Dev|App"
# Production
PROMETHEUS_ENDPOINT="http://prod-app:8080/actuator/prometheus"
METRIC_PREFIX="Custom Metrics|Prod|App"
Create separate extensions for each application:
monitors/
├── App1PrometheusMonitor/
├── App2PrometheusMonitor/
└── CamundaPrometheusMonitor/
This Universal Prometheus to AppDynamics converter bridges the gap between cloud-native monitoring and enterprise observability platforms.
The solution is production-ready, scalable, and maintainable — giving you the best of both worlds: Prometheus’s flexibility with AppDynamics’s enterprise capabilities.
Found this helpful? ⭐ Star the repository and share your success stories in the comments below!
Have questions? 💬 Join the discussion and let’s build better monitoring solutions together.
This article is part of a series on enterprise observability and monitoring best practices. Follow for more practical guides on AppDynamics, Prometheus, and modern monitoring architectures.