PM2 Monitoring Integration (Metrics + Logs)
This document outlines how to enable full observability for PM2-managed Node.js applications using Prometheus metrics and Loki logs, integrated via Grafana Alloy.
1. Install and Run PM2 Prometheus Exporter
The PM2 Prometheus exporter exposes metrics such as CPU usage, memory, uptime, and restarts per process, which can be scraped by Grafana Alloy and visualized in Grafana Cloud.
Installation Steps
cd ~
mkdir pm2-exporter
cd pm2-exporter
# Initialize Node.js project
npm init -y
# Install PM2 Prometheus Exporter
npm install pm2-prometheus-exporter
Start the Exporter
Run the exporter under PM2 so it restarts automatically on reboot:
pm2 start ./node_modules/pm2-prometheus-exporter/exporter.js --name pm2-exporter -- --port 9209
This will expose metrics at http://localhost:9209/metrics.
You can verify it’s working with:
curl http://localhost:9209/metrics | head
You should see metrics like pm2_up, pm2_cpu, pm2_memory, and pm2_restart_count.
2. Scrape PM2 Metrics via Grafana Alloy
Add the following block to your Alloy configuration file (/etc/alloy/config.alloy):
prometheus.scrape "pm2_exporter" {
targets = [
{ __address__ = "127.0.0.1:9209" },
]
job_name = "pm2_exporter"
metrics_path = "/metrics"
scrape_interval = "15s"
forward_to = [prometheus.relabel.metrics_instance.receiver]
}
This ensures Alloy scrapes the PM2 exporter every 15 seconds and forwards the data to Grafana Cloud via Prometheus Remote Write.
After saving the configuration, restart Alloy:
sudo systemctl restart alloy
sudo systemctl status alloy
3. Monitor PM2 Logs in Grafana (via Loki)
To collect PM2 process logs, Alloy can tail the .pm2/logs directory and forward them to Grafana Cloud Loki.
Add the following to your Alloy configuration:
local.file_match "pm2_logs" {
path_targets = [
{ __path__ = "/home/<user>/.pm2/logs/*.log" },
]
sync_period = "5s"
}
loki.source.file "pm2_logs" {
targets = local.file_match.pm2_logs.targets
tail_from_end = true
forward_to = [loki.relabel.pm2_labels.receiver]
}
loki.relabel "pm2_labels" {
forward_to = [loki.write.grafana_cloud_loki.receiver]
rule {
action = "replace"
target_label = "job"
replacement = "pm2"
}
rule {
action = "replace"
target_label = "service"
replacement = "pm2"
}
rule {
action = "replace"
target_label = "env"
replacement = "prod"
}
rule {
action = "replace"
target_label = "instance"
replacement = constants.hostname
}
}
This configuration:
- Tails all
.logfiles in/home/<user>/.pm2/logs/ - Assigns standardized labels (
job,service,env, andinstance) - Sends the logs directly to Grafana Cloud Loki
4. Verify Logs in Grafana
In Grafana → Explore → Loki, run this query to confirm log ingestion:
{job="pm2"} | logfmt
You should see live PM2 process logs. Use filters like:
{job="pm2"} |= "Error"→ only errors{job="pm2"} |= "backoffice"→ logs from a specific app