Skip to main content

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 .log files in /home/<user>/.pm2/logs/
  • Assigns standardized labels (job, service, env, and instance)
  • 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