Set up PHP application performance monitoring with APM tools and real-time metrics collection

Intermediate 35 min May 13, 2026 30 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Monitor PHP application performance with New Relic APM and Elastic APM, implement custom metrics collection, and set up comprehensive Grafana dashboards for real-time application observability and performance optimization.

Prerequisites

  • PHP 8.4 or higher installed
  • Web server (Apache/Nginx) running
  • Database server (MySQL/PostgreSQL) configured
  • Root or sudo access

What this solves

PHP applications need continuous monitoring to identify performance bottlenecks, track user experience metrics, and ensure optimal resource utilization. Application Performance Monitoring (APM) tools provide deep insights into database queries, external API calls, error rates, and response times. This tutorial shows you how to implement comprehensive PHP monitoring with New Relic APM, Elastic APM, custom metrics collection, and Grafana dashboards for production-ready observability.

Step-by-step installation

Update system packages

Start by updating your package manager to ensure you get the latest versions of all dependencies.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install PHP development tools

Install PHP development packages needed for compiling APM extensions and managing dependencies.

sudo apt install -y php-dev php-cli php-curl php-json curl build-essential
sudo dnf install -y php-devel php-cli php-curl php-json curl gcc gcc-c++ make

Download and install New Relic PHP agent

New Relic provides comprehensive APM monitoring with automatic instrumentation for popular PHP frameworks.

curl -L https://download.newrelic.com/php_agent/archive/10.15.0.4/newrelic-php5-10.15.0.4-linux.tar.gz -o newrelic-php-agent.tar.gz
tar -xzf newrelic-php-agent.tar.gz
cd newrelic-php5-*
sudo ./newrelic-install install

Configure New Relic APM

Set up New Relic with your license key and application settings for optimal monitoring coverage.

extension = "newrelic.so"
newrelic.license = "YOUR_NEW_RELIC_LICENSE_KEY"
newrelic.appname = "PHP Production App"
newrelic.daemon.location = "/usr/bin/newrelic-daemon"
newrelic.logfile = "/var/log/newrelic/php_agent.log"
newrelic.loglevel = "info"
newrelic.daemon.logfile = "/var/log/newrelic/newrelic-daemon.log"
newrelic.daemon.loglevel = "info"
newrelic.capture_params = true
newrelic.ignored_params = "credit_card,ssn,password"
newrelic.error_collector.enabled = true
newrelic.browser_monitoring.auto_instrument = true
newrelic.transaction_tracer.enabled = true
newrelic.transaction_tracer.threshold = "apdex_f"
newrelic.transaction_tracer.detail = 1
newrelic.transaction_tracer.record_sql = "obfuscated"
newrelic.transaction_tracer.explain_enabled = true
newrelic.transaction_tracer.explain_threshold = 500
newrelic.framework = "laravel,symfony,codeigniter"

Install Elastic APM PHP agent

Elastic APM provides open-source monitoring with deep integration into the Elastic Stack for log correlation and custom dashboards.

curl -L https://github.com/elastic/apm-agent-php/releases/latest/download/apm-agent-php_all.deb -o elastic-apm-php.deb
sudo dpkg -i elastic-apm-php.deb || sudo apt-get install -f

Configure Elastic APM

Configure the Elastic APM agent with your server details and application-specific settings for comprehensive monitoring.

extension=elastic_apm.so
elastic_apm.server_url=http://localhost:8200
elastic_apm.service_name=php-production-app
elastic_apm.service_version=1.0.0
elastic_apm.environment=production
elastic_apm.application_packages=app,src
elastic_apm.enabled=true
elastic_apm.recording=true
elastic_apm.instrument=true
elastic_apm.capture_errors=true
elastic_apm.error_reporting=E_ALL & ~E_DEPRECATED & ~E_STRICT
elastic_apm.capture_spans=true
elastic_apm.span_frames_min_duration=5ms
elastic_apm.stack_trace_limit=50
elastic_apm.transaction_sample_rate=1.0
elastic_apm.central_config=true
elastic_apm.breakdown_metrics=true
elastic_apm.capture_body=transactions
elastic_apm.transaction_max_spans=500
elastic_apm.span_stack_trace_min_duration=5ms
elastic_apm.log_level=INFO

Install APM Server for Elastic Stack

Install and configure APM Server to receive and process monitoring data from your PHP applications.

wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list
sudo apt update
sudo apt install -y apm-server
sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
sudo tee /etc/yum.repos.d/elastic.repo << 'EOF'
[elastic-8.x]
name=Elastic repository for 8.x packages
baseurl=https://artifacts.elastic.co/packages/8.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
EOF
sudo dnf install -y apm-server

Configure APM Server

Set up APM Server to handle incoming monitoring data and forward it to Elasticsearch for storage and analysis.

apm-server:
  host: "0.0.0.0:8200"
  max_header_size: 1048576
  idle_timeout: 45s
  read_timeout: 30s
  write_timeout: 30s
  shutdown_timeout: 5s
  capture_personal_data: true
  expvar:
    enabled: true
    url: "/debug/vars"
  pprof:
    enabled: true

output.elasticsearch:
  hosts: ["localhost:9200"]
  protocol: "http"
  username: "elastic"
  password: "your_elasticsearch_password"
  index: "apm-%{[observer.version]}-{type}-%{+yyyy.MM.dd}"
  template.settings:
    index.number_of_shards: 1
    index.number_of_replicas: 1
    index.refresh_interval: 5s

setup.template:
  enabled: true
  pattern: "apm-*"
  settings:
    index:
      number_of_shards: 1
      number_of_replicas: 1
      refresh_interval: 5s

setup.kibana:
  host: "localhost:5601"

logging.level: info
logging.to_files: true
logging.files:
  path: /var/log/apm-server
  name: apm-server
  keepfiles: 7
  permissions: 0644

processors:
  - add_host_metadata:
      when.not.contains.tags: forwarded
  - add_docker_metadata: ~
  - add_kubernetes_metadata: ~

Install Prometheus for custom metrics

Install Prometheus to collect custom application metrics and system performance data for comprehensive monitoring.

sudo apt install -y prometheus prometheus-node-exporter
sudo dnf install -y prometheus2 node_exporter

Configure custom PHP metrics collection

Create a custom PHP script to expose application-specific metrics in Prometheus format for detailed performance tracking.

query('SELECT COUNT(*) FROM users');
    $queryTime = microtime(true) - $start;
    $userCount = $stmt->fetchColumn();
    
} catch (PDOException $e) {
    $dbConnected = 0;
    $queryTime = 0;
    $userCount = 0;
}

// Memory usage metrics
$memoryUsage = memory_get_usage(true);
$memoryPeak = memory_get_peak_usage(true);

// Cache hit rate (example with Redis)
try {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $info = $redis->info('stats');
    $cacheHits = $info['keyspace_hits'] ?? 0;
    $cacheMisses = $info['keyspace_misses'] ?? 0;
    $cacheTotal = $cacheHits + $cacheMisses;
    $cacheHitRate = $cacheTotal > 0 ? ($cacheHits / $cacheTotal) : 0;
    $redisConnected = 1;
} catch (Exception $e) {
    $cacheHitRate = 0;
    $redisConnected = 0;
}

// Output Prometheus metrics
echo "# HELP php_app_db_connected Database connection status\n";
echo "# TYPE php_app_db_connected gauge\n";
echo "php_app_db_connected $dbConnected\n";

echo "# HELP php_app_query_duration_seconds Database query execution time\n";
echo "# TYPE php_app_query_duration_seconds gauge\n";
echo "php_app_query_duration_seconds $queryTime\n";

echo "# HELP php_app_users_total Total number of users\n";
echo "# TYPE php_app_users_total gauge\n";
echo "php_app_users_total $userCount\n";

echo "# HELP php_app_memory_usage_bytes Current memory usage\n";
echo "# TYPE php_app_memory_usage_bytes gauge\n";
echo "php_app_memory_usage_bytes $memoryUsage\n";

echo "# HELP php_app_memory_peak_bytes Peak memory usage\n";
echo "# TYPE php_app_memory_peak_bytes gauge\n";
echo "php_app_memory_peak_bytes $memoryPeak\n";

echo "# HELP php_app_cache_hit_rate Cache hit rate ratio\n";
echo "# TYPE php_app_cache_hit_rate gauge\n";
echo "php_app_cache_hit_rate $cacheHitRate\n";

echo "# HELP php_app_redis_connected Redis connection status\n";
echo "# TYPE php_app_redis_connected gauge\n";
echo "php_app_redis_connected $redisConnected\n";

// Application-specific business metrics
$todayOrders = 0; // Your business logic here
echo "# HELP php_app_orders_today_total Orders created today\n";
echo "# TYPE php_app_orders_today_total counter\n";
echo "php_app_orders_today_total $todayOrders\n";
?>

Configure Prometheus scraping

Configure Prometheus to scrape metrics from your PHP application endpoint and system monitoring targets.

global:
  scrape_interval: 15s
  evaluation_interval: 15s
  external_labels:
    monitor: 'php-production-monitor'

rule_files:
  - "/etc/prometheus/php_rules.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets:
          - localhost:9093

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node-exporter'
    static_configs:
      - targets: ['localhost:9100']

  - job_name: 'php-app-metrics'
    static_configs:
      - targets: ['localhost:80']
    metrics_path: '/metrics.php'
    scrape_interval: 30s
    scrape_timeout: 10s

  - job_name: 'nginx-exporter'
    static_configs:
      - targets: ['localhost:9113']

  - job_name: 'mysql-exporter'
    static_configs:
      - targets: ['localhost:9104']

  - job_name: 'redis-exporter'
    static_configs:
      - targets: ['localhost:9121']

Create PHP performance alerting rules

Define Prometheus alerting rules for critical PHP application performance metrics and system health indicators.

groups:
  - name: php_app_alerts
    rules:
      - alert: PHPAppDatabaseDown
        expr: php_app_db_connected == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "PHP application database connection failed"
          description: "Database connection has been down for more than 1 minute"

      - alert: PHPAppHighMemoryUsage
        expr: php_app_memory_usage_bytes > 134217728  # 128MB
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "PHP application high memory usage"
          description: "Memory usage is {{ $value | humanize }} bytes"

      - alert: PHPAppSlowQueries
        expr: php_app_query_duration_seconds > 1
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "PHP application slow database queries"
          description: "Database queries taking more than 1 second"

      - alert: PHPAppLowCacheHitRate
        expr: php_app_cache_hit_rate < 0.8
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "PHP application low cache hit rate"
          description: "Cache hit rate is {{ $value | humanizePercentage }}"

      - alert: PHPAppRedisDown
        expr: php_app_redis_connected == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "PHP application Redis connection failed"
          description: "Redis connection has been down for more than 1 minute"

Install and configure Grafana

Install Grafana for comprehensive visualization of your PHP application performance metrics and system monitoring data.

sudo apt install -y software-properties-common
sudo add-apt-repository "deb https://packages.grafana.com/oss/deb stable main"
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
sudo apt update
sudo apt install -y grafana
sudo tee /etc/yum.repos.d/grafana.repo << 'EOF'
[grafana]
name=grafana
baseurl=https://packages.grafana.com/oss/rpm
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://packages.grafana.com/gpg.key
EOF
sudo dnf install -y grafana

Create PHP application dashboard

Import a comprehensive Grafana dashboard configuration for monitoring PHP application performance, database metrics, and system resources.

{
  "dashboard": {
    "id": null,
    "title": "PHP Application Performance Monitor",
    "tags": ["php", "application", "performance"],
    "timezone": "browser",
    "time": {
      "from": "now-1h",
      "to": "now"
    },
    "refresh": "30s",
    "panels": [
      {
        "id": 1,
        "title": "Database Connection Status",
        "type": "stat",
        "targets": [{
          "expr": "php_app_db_connected",
          "legendFormat": "Database Connected"
        }],
        "fieldConfig": {
          "defaults": {
            "color": {
              "mode": "thresholds"
            },
            "thresholds": {
              "steps": [
                {"color": "red", "value": 0},
                {"color": "green", "value": 1}
              ]
            }
          }
        }
      },
      {
        "id": 2,
        "title": "Memory Usage",
        "type": "timeseries",
        "targets": [
          {
            "expr": "php_app_memory_usage_bytes",
            "legendFormat": "Current Memory"
          },
          {
            "expr": "php_app_memory_peak_bytes",
            "legendFormat": "Peak Memory"
          }
        ]
      },
      {
        "id": 3,
        "title": "Query Response Time",
        "type": "timeseries",
        "targets": [{
          "expr": "php_app_query_duration_seconds",
          "legendFormat": "Query Time (seconds)"
        }]
      },
      {
        "id": 4,
        "title": "Cache Hit Rate",
        "type": "timeseries",
        "targets": [{
          "expr": "php_app_cache_hit_rate * 100",
          "legendFormat": "Hit Rate %"
        }]
      }
    ]
  }
}

Set correct permissions

Set appropriate file ownership and permissions for monitoring components to ensure security and proper functionality.

sudo chown www-data:www-data /var/www/metrics.php
sudo chmod 644 /var/www/metrics.php
sudo chown prometheus:prometheus /etc/prometheus/php_rules.yml
sudo chmod 644 /etc/prometheus/php_rules.yml
sudo chown grafana:grafana /var/lib/grafana/dashboards/php-app-dashboard.json
sudo chmod 644 /var/lib/grafana/dashboards/php-app-dashboard.json
Never use chmod 777. It gives every user on the system full access to your files. Instead, fix ownership with chown and use minimal permissions.

Enable and start all services

Enable and start all monitoring services to begin collecting and visualizing PHP application performance data.

sudo systemctl enable --now newrelic-daemon
sudo systemctl enable --now apm-server
sudo systemctl enable --now prometheus
sudo systemctl enable --now node_exporter
sudo systemctl enable --now grafana-server
sudo systemctl restart php8.4-fpm
sudo systemctl restart nginx

Verify your setup

Test all monitoring components to ensure they are collecting and displaying PHP application performance data correctly.

# Check service status
sudo systemctl status newrelic-daemon apm-server prometheus grafana-server

Test custom metrics endpoint

curl http://localhost/metrics.php

Check Prometheus targets

curl http://localhost:9090/api/v1/targets

Verify APM server is receiving data

curl http://localhost:8200/

Check New Relic agent logs

sudo tail -f /var/log/newrelic/php_agent.log

Test Grafana access

curl -I http://localhost:3000

Verify Elastic APM data collection

curl http://localhost:8200/config/v1/agents

Access your monitoring dashboards:

  • Grafana: http://localhost:3000 (admin/admin)
  • Prometheus: http://localhost:9090
  • New Relic: https://one.newrelic.com
  • Kibana (for Elastic APM): http://localhost:5601

Common issues

Symptom Cause Fix
New Relic not collecting data Invalid license key or agent not loaded Check /var/log/newrelic/php_agent.log and verify extension in php -m
Elastic APM connection errors APM server not running or wrong URL sudo systemctl status apm-server and verify server_url setting
Custom metrics endpoint 404 PHP file not accessible or wrong location Check web server configuration and file permissions with ls -la
Prometheus targets down Services not running or firewall blocking Verify service status and check netstat -tlnp for listening ports
Grafana dashboard empty Data source not configured or wrong queries Add Prometheus data source at http://localhost:9090 and test connection
High memory usage alerts Memory leaks or inefficient code Review APM transaction traces and optimize database queries

Next steps

Running this in production?

Need this managed for you? Setting this up once is straightforward. Keeping it patched, monitored, backed up and performant across environments is the harder part. See how we run infrastructure like this for European teams.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle managed devops services for businesses that depend on uptime. From initial setup to ongoing operations.