Implement PHP application monitoring with New Relic and logging

Intermediate 45 min Apr 09, 2026 55 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up comprehensive PHP application monitoring using New Relic APM with custom metrics and error tracking. Configure structured logging with centralized collection and automated monitoring alerts.

Prerequisites

  • PHP 8.2 or higher installed
  • Apache or Nginx web server running
  • Valid New Relic account with license key
  • Root or sudo access to the server

What this solves

PHP applications require comprehensive monitoring to track performance, errors, and business metrics in production. This tutorial implements New Relic APM for detailed application performance monitoring and configures centralized logging with structured data collection. You'll set up custom metrics, error tracking, and automated alerts to maintain application health and respond quickly to issues.

Step-by-step installation

Update system packages

Start by updating your package manager to ensure you have the latest security patches and package information.

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

Install required dependencies

Install the necessary packages for PHP development, log management, and system monitoring tools.

sudo apt install -y wget curl gnupg2 software-properties-common \
  rsyslog logrotate php-dev php-cli php-fpm apache2-dev
sudo dnf install -y wget curl gnupg2 \
  rsyslog logrotate php-devel php-cli php-fpm httpd-devel

Add New Relic repository

Add the official New Relic repository to install the PHP agent and monitoring tools.

curl -fsSL https://download.newrelic.com/548C16BF.gpg | sudo gpg --dearmor -o /etc/apt/keyrings/newrelic.gpg
echo "deb [signed-by=/etc/apt/keyrings/newrelic.gpg] http://apt.newrelic.com/debian/ newrelic non-free" | sudo tee /etc/apt/sources.list.d/newrelic.list
sudo apt update
sudo rpm -Uvh http://yum.newrelic.com/pub/newrelic/el5/x86_64/newrelic-repo-5-3.noarch.rpm

Install New Relic PHP agent

Install the New Relic PHP agent package which includes the daemon and PHP extension for application monitoring.

sudo apt install -y newrelic-php5
sudo dnf install -y newrelic-php5

Configure New Relic PHP agent

Run the New Relic installation script and configure it with your license key. Replace YOUR_LICENSE_KEY with your actual New Relic license key from your account.

sudo newrelic-install install

Follow the prompts and enter your New Relic license key when prompted

Select your PHP version and web server configuration

Note: You can find your license key in your New Relic account under Account Settings > API Keys.

Configure New Relic PHP settings

Create a comprehensive New Relic configuration with application naming, error collection, and performance settings.

extension = "newrelic.so"

; Application name as it appears in New Relic UI
newrelic.appname = "MyApp Production"

; License key
newrelic.license = "YOUR_LICENSE_KEY"

; Enable the agent
newrelic.enabled = true

; Set daemon address
newrelic.daemon.address = "/tmp/.newrelic.sock"

; High security mode
newrelic.high_security = false

; Transaction tracer settings
newrelic.transaction_tracer.enabled = true
newrelic.transaction_tracer.threshold = "apdex_f"
newrelic.transaction_tracer.detail = 1
newrelic.transaction_tracer.slow_sql = true
newrelic.transaction_tracer.stack_trace_threshold = 500

; Error collector settings
newrelic.error_collector.enabled = true
newrelic.error_collector.record_database_errors = true

; Browser monitoring
newrelic.browser_monitoring.auto_instrument = true

; Database monitoring
newrelic.datastore_tracer.database_name_reporting.enabled = true
newrelic.datastore_tracer.instance_reporting.enabled = true

; Custom event settings
newrelic.custom_events.enabled = true

Configure rsyslog for centralized logging

Set up rsyslog to collect PHP application logs with structured formatting and remote logging capabilities.

# PHP application log configuration
$ModLoad imfile

PHP error log

$InputFileName /var/log/php_errors.log $InputFileTag php-error: $InputFileStateFile stat-php-error $InputFileSeverity error $InputFileFacility local0 $InputRunFileMonitor

PHP application log

$InputFileName /var/log/myapp/application.log $InputFileTag myapp: $InputFileStateFile stat-myapp $InputFileSeverity info $InputFileFacility local1 $InputRunFileMonitor

Custom template for structured logging

$template AppLogFormat,"<%PRI%>%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag% %STRUCTURED-DATA% %msg%\n"

Forward logs to central server (optional)

. @@logserver.example.com:514;AppLogFormat

Local file logging with rotation

local0.* /var/log/php_errors.log;AppLogFormat local1.* /var/log/myapp/application.log;AppLogFormat

Set up log rotation

Configure logrotate to manage log file sizes and retention automatically.

/var/log/php_errors.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    create 644 www-data www-data
    postrotate
        /usr/lib/rsyslog/rsyslog-rotate
    endscript
}

/var/log/myapp/*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    create 644 www-data www-data
    sharedscripts
    postrotate
        /usr/lib/rsyslog/rsyslog-rotate
    endscript
}

Create application logging directories

Set up proper directory structure with correct ownership and permissions for application logs.

sudo mkdir -p /var/log/myapp
sudo chown www-data:www-data /var/log/myapp
sudo chmod 755 /var/log/myapp
sudo touch /var/log/myapp/application.log /var/log/myapp/error.log
sudo chown www-data:www-data /var/log/myapp/*.log
sudo chmod 644 /var/log/myapp/*.log
Never use chmod 777. It gives every user on the system full access to your files. Use proper ownership with chown and minimal required permissions.

Configure PHP error logging

Update PHP configuration to enable comprehensive error logging with proper log levels and destinations.

; Error logging configuration
log_errors = On
error_log = /var/log/php_errors.log

; Log all errors except notices
error_reporting = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED

; Don't display errors to users
display_errors = Off
display_startup_errors = Off

; Log repeated errors
ignore_repeated_errors = Off
ignore_repeated_source = Off

; Maximum log file size
log_errors_max_len = 1024

; Enable syslog logging
openlog.ident = "php"
openlog.facility = LOG_USER

Create PHP monitoring class

Implement a custom PHP class for structured logging and New Relic custom metrics.

logFile = $logFile;
    }
    
    /**
     * Log structured application events
     */
    public function logEvent($level, $message, $context = []) {
        $timestamp = date('c');
        $logEntry = [
            'timestamp' => $timestamp,
            'level' => strtoupper($level),
            'message' => $message,
            'context' => $context,
            'request_id' => $this->getRequestId(),
            'user_id' => $this->getCurrentUserId()
        ];
        
        file_put_contents($this->logFile, json_encode($logEntry) . "\n", FILE_APPEND | LOCK_EX);
        
        // Send to syslog as well
        syslog(LOG_INFO, json_encode($logEntry));
    }
    
    /**
     * Record custom New Relic metrics
     */
    public function recordMetric($name, $value) {
        if (extension_loaded('newrelic')) {
            newrelic_custom_metric($name, $value);
        }
    }
    
    /**
     * Track business events in New Relic
     */
    public function trackEvent($eventType, $attributes = []) {
        if (extension_loaded('newrelic')) {
            newrelic_record_custom_event($eventType, $attributes);
        }
    }
    
    /**
     * Set transaction name for New Relic
     */
    public function setTransactionName($name) {
        if (extension_loaded('newrelic')) {
            newrelic_name_transaction($name);
        }
    }
    
    /**
     * Add custom attributes to New Relic transaction
     */
    public function addCustomAttribute($key, $value) {
        if (extension_loaded('newrelic')) {
            newrelic_add_custom_parameter($key, $value);
        }
    }
    
    /**
     * Notice error in New Relic
     */
    public function noticeError($exception) {
        if (extension_loaded('newrelic')) {
            newrelic_notice_error($exception);
        }
        
        $this->logEvent('error', $exception->getMessage(), [
            'file' => $exception->getFile(),
            'line' => $exception->getLine(),
            'trace' => $exception->getTraceAsString()
        ]);
    }
    
    private function getRequestId() {
        return $_SERVER['HTTP_X_REQUEST_ID'] ?? uniqid('req_');
    }
    
    private function getCurrentUserId() {
        // Implement your user identification logic
        return $_SESSION['user_id'] ?? 'anonymous';
    }
}

Create monitoring configuration

Set up monitoring alerts and thresholds for your application performance metrics.

 [
        'app_name' => 'MyApp Production',
        'license_key' => getenv('NEWRELIC_LICENSE_KEY'),
        'high_security' => false,
        'transaction_tracer_threshold' => 0.5,
        'error_collector' => true,
        'browser_monitoring' => true,
    ],
    
    'logging' => [
        'level' => 'info',
        'file' => '/var/log/myapp/application.log',
        'max_size' => '100MB',
        'rotation' => 30,
        'structured' => true,
    ],
    
    'alerts' => [
        'error_rate_threshold' => 5.0,  // percent
        'response_time_threshold' => 2.0,  // seconds
        'throughput_threshold' => 100,  // requests per minute
        'memory_usage_threshold' => 80,  // percent
    ],
    
    'custom_metrics' => [
        'business_metrics' => [
            'user_registrations',
            'order_completions',
            'payment_failures',
            'api_calls'
        ],
        'performance_metrics' => [
            'database_query_time',
            'cache_hit_rate',
            'external_api_response_time'
        ]
    ]
];

Implement application monitoring

Create an example application that demonstrates comprehensive monitoring integration.

setTransactionName('Home Page');

// Add custom attributes
$monitor->addCustomAttribute('page_type', 'home');
$monitor->addCustomAttribute('user_type', 'guest');

try {
    // Start timing
    $startTime = microtime(true);
    
    // Log page view
    $monitor->logEvent('info', 'Page viewed', [
        'page' => 'home',
        'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
        'ip_address' => $_SERVER['REMOTE_ADDR'] ?? 'unknown'
    ]);
    
    // Simulate some business logic
    $userData = getUserData();
    $products = getProducts();
    
    // Record custom metrics
    $endTime = microtime(true);
    $pageLoadTime = $endTime - $startTime;
    $monitor->recordMetric('Custom/Page/LoadTime', $pageLoadTime);
    $monitor->recordMetric('Custom/Products/Count', count($products));
    
    // Track business event
    $monitor->trackEvent('PageView', [
        'page' => 'home',
        'load_time' => $pageLoadTime,
        'product_count' => count($products)
    ]);
    
    echo "

Welcome to MyApp

"; echo "

Products loaded: " . count($products) . "

"; } catch (Exception $e) { // Handle and report errors $monitor->noticeError($e); http_response_code(500); echo "

Error occurred

"; // Track error event $monitor->trackEvent('Error', [ 'error_message' => $e->getMessage(), 'error_file' => $e->getFile(), 'error_line' => $e->getLine() ]); } function getUserData() { global $monitor; $startTime = microtime(true); // Simulate database call usleep(50000); // 50ms $endTime = microtime(true); $queryTime = $endTime - $startTime; $monitor->recordMetric('Custom/Database/UserQuery', $queryTime); $monitor->logEvent('debug', 'User data retrieved', ['query_time' => $queryTime]); return ['id' => 1, 'name' => 'Test User']; } function getProducts() { global $monitor; $startTime = microtime(true); // Simulate cache miss and database query $products = [ ['id' => 1, 'name' => 'Product 1'], ['id' => 2, 'name' => 'Product 2'], ['id' => 3, 'name' => 'Product 3'] ]; $endTime = microtime(true); $queryTime = $endTime - $startTime; $monitor->recordMetric('Custom/Database/ProductQuery', $queryTime); $monitor->recordMetric('Custom/Cache/MissRate', 0.2); return $products; }

Start services and enable monitoring

Start the required services and verify that monitoring is working correctly.

sudo systemctl restart rsyslog
sudo systemctl restart php8.2-fpm
sudo systemctl restart apache2
sudo systemctl restart newrelic-daemon

Enable services to start on boot

sudo systemctl enable rsyslog php8.2-fpm apache2 newrelic-daemon

Verify your setup

Test that New Relic monitoring and logging are working correctly by checking service status and generating test data.

# Check New Relic daemon status
sudo systemctl status newrelic-daemon

Verify PHP extension is loaded

php -m | grep newrelic

Check log files

sudo tail -f /var/log/myapp/application.log sudo tail -f /var/log/php_errors.log

Test application monitoring

curl -v http://localhost/

Check rsyslog is processing logs

sudo systemctl status rsyslog sudo tail -f /var/log/syslog | grep myapp

Verify log rotation configuration

sudo logrotate -d /etc/logrotate.d/php-apps

Visit your New Relic dashboard to verify that application data is appearing. You should see transaction traces, error reports, and custom metrics within 5-10 minutes of generating traffic.

Configure monitoring alerts

Set up log monitoring script

Create a script to monitor log files for specific patterns and send alerts when issues are detected.

#!/bin/bash

LOG_FILE="/var/log/myapp/application.log"
ERROR_THRESHOLD=10
ALERT_EMAIL="admin@example.com"
TEMP_FILE="/tmp/log-monitor-state"

Create state file if it doesn't exist

if [[ ! -f "$TEMP_FILE" ]]; then echo "0" > "$TEMP_FILE" fi LAST_COUNT=$(cat "$TEMP_FILE") CURRENT_COUNT=$(grep -c '"level":"ERROR"' "$LOG_FILE" 2>/dev/null || echo "0") NEW_ERRORS=$((CURRENT_COUNT - LAST_COUNT)) if [[ $NEW_ERRORS -gt $ERROR_THRESHOLD ]]; then echo "High error rate detected: $NEW_ERRORS new errors" | \ mail -s "PHP Application Alert: High Error Rate" "$ALERT_EMAIL" fi

Update state file

echo "$CURRENT_COUNT" > "$TEMP_FILE"

Check for specific critical errors

if grep -q "CRITICAL\|FATAL" "$LOG_FILE"; then RECENT_CRITICAL=$(tail -n 100 "$LOG_FILE" | grep "CRITICAL\|FATAL") echo "Critical errors detected:\n$RECENT_CRITICAL" | \ mail -s "PHP Application Alert: Critical Error" "$ALERT_EMAIL" fi

Set up monitoring cron job

Configure automated monitoring to run every 5 minutes and send alerts when issues are detected.

sudo chmod +x /usr/local/bin/log-monitor.sh
sudo crontab -e
# Monitor application logs every 5 minutes
/5    * /usr/local/bin/log-monitor.sh

Rotate logs daily at 2 AM

0 2 * /usr/sbin/logrotate -f /etc/logrotate.d/php-apps

For more advanced monitoring setups, check out our Gunicorn performance monitoring tutorial and ELK Stack centralized logging guide.

Common issues

SymptomCauseFix
New Relic agent not reporting data Invalid license key or daemon not running sudo systemctl restart newrelic-daemon and verify license key
Permission denied writing to log files Incorrect file ownership or permissions sudo chown www-data:www-data /var/log/myapp/*.log
Log rotation not working Logrotate configuration syntax error sudo logrotate -d /etc/logrotate.d/php-apps to test config
High memory usage from logging Excessive log verbosity or retention Reduce log level in PHP config and adjust rotation frequency
Custom metrics not appearing in New Relic New Relic extension not loaded properly php -m | grep newrelic to verify, restart PHP-FPM if needed
Structured logs not parsing correctly Invalid JSON format in log entries Validate JSON output and check rsyslog template configuration

Next steps

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.