• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Server Monitoring Best Practices: Keeping Your Laravel App and MongoDB Clusters Alive on OVH

Server Monitoring Best Practices: Keeping Your Laravel App and MongoDB Clusters Alive on OVH

Proactive Monitoring for Laravel & MongoDB on OVH: Beyond Basic Uptime

Maintaining the health and performance of a Laravel application backed by a MongoDB cluster on OVH infrastructure demands a robust, multi-layered monitoring strategy. Simply checking if a server is “up” is insufficient. We need to delve into application-level metrics, database performance, and infrastructure resource utilization to preemptively identify and resolve issues before they impact end-users. This guide focuses on actionable, production-ready techniques and configurations.

1. Application Performance Monitoring (APM) with Laravel Telescope & Prometheus

Laravel Telescope provides invaluable insights into your application’s behavior during development and staging. For production, we’ll leverage its data export capabilities and integrate with a more scalable monitoring solution like Prometheus.

1.1. Enabling and Configuring Telescope for Production

While Telescope is often associated with development, it can be safely enabled in production with proper authorization and configuration. We’ll restrict access to authorized IP addresses and disable features that might incur significant overhead.

// config/telescope.php

return [
    /*
    |--------------------------------------------------------------------------
    | Watchers
    |--------------------------------------------------------------------------
    |
    | This array lists the Telescope watchers that will be registered.
    | You may disable any watchers you do not need.
    |
    */

    'watchers' => [
        // ... other watchers
        \Laravel\Telescope\Watchers\QueryWatcher::class => env('TELESCOPE_WATCHER_QUERY', true),
        \Laravel\Telescope\Watchers\EventWatcher::class => env('TELESCOPE_WATCHER_EVENT', true),
        \Laravel\Telescope\Watchers\JobWatcher::class => env('TELESCOPE_WATCHER_JOB', true),
        \Laravel\Telescope\Watchers\LogWatcher::class => env('TELESCOPE_WATCHER_LOG', true),
        \Laravel\Telescope\Watchers\NotificationWatcher::class => env('TELESCOPE_WATCHER_NOTIFICATION', true),
        \Laravel\Telescope\Watchers\CacheWatcher::class => env('TELESCOPE_WATCHER_CACHE', true),
        \Laravel\Telescope\Watchers\ScheduleWatcher::class => env('TELESCOPE_WATCHER_SCHEDULE', true),
        \Laravel\Telescope\Watchers\CommandWatcher::class => env('TELESCOPE_WATCHER_COMMAND', true),
        \Laravel\Telescope\Watchers\ExceptionWatcher::class => env('TELESCOPE_WATCHER_EXCEPTION', true),
        \Laravel\Telescope\Watchers\ModelWatcher::class => env('TELESCOPE_WATCHER_MODEL', false), // Often too verbose for prod
        \Laravel\Telescope\Watchers\RequestWatcher::class => env('TELESCOPE_WATCHER_REQUEST', true),
        \Laravel\Telescope\Watchers\ViewWatcher::class => env('TELESCOPE_WATCHER_VIEW', false), // Can be heavy
    ],

    /*
    |--------------------------------------------------------------------------
    | Storage Driver
    |--------------------------------------------------------------------------
    |
    | Telescope will store its data in an application-specific way. The
    | `driver` may be `database`, `eloquent`, `redis`, or `custom`.
    |
    */

    'driver' => env('TELESCOPE_DRIVER', 'database'),

    /*
    |--------------------------------------------------------------------------
    | Database Configuration
    |--------------------------------------------------------------------------
    |
    | If the `driver` is set to `database`, Telescope will use the
    | following configuration to connect to the database.
    |
    */

    'database' => [
        'connection' => env('TELESCOPE_DB_CONNECTION', config('database.default')),
    ],

    /*
    |--------------------------------------------------------------------------
    | Authorization
    |--------------------------------------------------------------------------
    |
    | Telescope provides two gates: `authorize` and `can_install`.
    | The `authorize` gate determines who can access Telescope in the
    | application. The `can_install` gate determines who can install
    | Telescope's database migrations.
    |
    */

    'middleware' => [
        // ... other middleware
        \Illuminate\Cookie\Middleware\EncryptCookies::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'path' => env('TELESCOPE_PATH', 'telescope'),

    'domain' => env('TELESCOPE_DOMAIN', null),

    'middleware' => [
        'web',
        // Add your custom authorization middleware here
        // Example: Restrict by IP
        \App\Http\Middleware\AuthorizeTelescopeAccess::class,
    ],

    'storage' => [
        'database' => [
            'connection' => env('TELESCOPE_DB_CONNECTION', config('database.default')),
            'table' => 'telescope_entries',
        ],
    ],

    'enabled' => env('TELESCOPE_ENABLED', true),
];

Create the authorization middleware:

// app/Http/Middleware/AuthorizeTelescopeAccess.php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class AuthorizeTelescopeAccess
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        // Allow access only from specific IP addresses or networks
        if ($request->ip() === 'YOUR_ADMIN_IP_ADDRESS' || $request->ip() === 'ANOTHER_ADMIN_IP') {
            return $next($request);
        }

        // Optionally, allow access if authenticated as a super admin
        // if (auth()->check() && auth()->user()->is_super_admin) {
        //     return $next($request);
        // }

        abort(403, 'Access denied.');
    }
}

In your .env file, ensure Telescope is enabled and configure the database connection if it differs from your default:

TELESCOPE_ENABLED=true
TELESCOPE_PATH=/telescope
TELESCOPE_DRIVER=database
TELESCOPE_DB_CONNECTION=mysql # Or your specific connection name

After deploying these changes, run the migrations:

php artisan telescope:install
php artisan migrate

1.2. Exporting Telescope Data to Prometheus

Telescope’s data is stored in your application’s database. To integrate with Prometheus, we’ll use a custom exporter or a tool that can query the database and expose metrics in Prometheus format. A simple approach is to create a scheduled task that aggregates key metrics and exposes them via a custom endpoint.

Alternatively, for more direct integration, consider using a library like Prometheus Client for PHP. This allows you to instrument your Laravel application directly.

1.3. Prometheus & Grafana Setup (OVH Context)

On your OVH servers, you’ll need to deploy Prometheus and Grafana. This can be done using Docker for easier management.

Prometheus Configuration (prometheus.yml):

global:
  scrape_interval: 15s # By default, scrape targets every 15 seconds.

scrape_configs:
  # Scrape Prometheus itself
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  # Scrape Node Exporter for host metrics
  - job_name: 'node_exporter'
    static_configs:
      - targets: ['localhost:9100'] # Assuming node_exporter is running on the same host

  # Scrape your Laravel application's metrics endpoint
  - job_name: 'laravel_app'
    static_configs:
      - targets: ['your_laravel_app_server_ip:8000'] # Replace with your app's IP and port
    metrics_path: '/metrics' # The endpoint where your app exposes metrics

Grafana Configuration:

1. Install Grafana (e.g., via Docker or package manager).

2. Add Prometheus as a data source in Grafana (Configuration -> Data Sources -> Add data source -> Prometheus). Set the URL to http://localhost:9090 (if Grafana and Prometheus are on the same host).

3. Import pre-built Grafana dashboards for Node Exporter and potentially custom dashboards for your Laravel app metrics. You can find many on Grafana.com/dashboards.

2. MongoDB Cluster Monitoring with Percona Monitoring and Management (PMM)

For MongoDB, a dedicated monitoring solution like Percona Monitoring and Management (PMM) is highly recommended. PMM provides deep insights into MongoDB performance, query analysis, and cluster health.

2.1. Deploying PMM Server

Deploy the PMM Server on a dedicated OVH instance or within a Docker environment. The official documentation provides detailed instructions for various deployment methods.

# Example using Docker
docker run -d \
  --name pmm-server \
  -p 80:80 \
  -p 443:443 \
  -p 3307:3307 \
  perconalab/pmm-server:latest

Access the PMM UI via your browser at http://your_pmm_server_ip.

2.2. Adding MongoDB Instances to PMM

PMM uses agents to collect data. For MongoDB, you’ll typically deploy the mongodb_exporter. This can be done by adding your MongoDB instances directly through the PMM UI or by deploying the agent on the MongoDB hosts.

Adding via PMM UI:

  • Navigate to “MongoDB” in the PMM UI.
  • Click “Add MongoDB Instance”.
  • Provide the MongoDB connection string (e.g., mongodb://user:password@host1:27017,host2:27017/admin?replicaSet=rs0).
  • PMM will automatically deploy and configure the necessary exporter.

Deploying Agent on Host (if preferred):

Follow the PMM documentation to install the PMM client and then register your MongoDB instance with the PMM server.

2.3. Key MongoDB Metrics to Monitor

Within PMM, focus on these critical metrics:

  • Query Performance: Slow queries (count, duration), query execution time, query patterns.
  • Connections: Active connections, connection pool usage, connection errors.
  • Replication Lag: For replica sets, monitor the oplog window and replication lag between members.
  • Disk I/O: Read/write operations per second, I/O wait times.
  • Memory Usage: Resident Set Size (RSS), cache hit rates, page faults.
  • CPU Usage: System and user CPU time.
  • Network Traffic: Bytes sent/received.
  • Locking: Global lock percentage, read/write lock contention.

3. Infrastructure Monitoring with OVH Control Panel & Node Exporter

OVH provides a comprehensive control panel for managing your instances, but for real-time, granular infrastructure metrics, we rely on standard tools like Node Exporter.

3.1. Node Exporter Deployment

Node Exporter collects hardware and OS metrics. Deploy it on each of your OVH instances (web servers, database servers).

# Download the latest version
wget https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz
tar xvfz node_exporter-1.7.0.linux-amd64.tar.gz
cd node_exporter-1.7.0.linux-amd64

# Run Node Exporter (in foreground for testing, use systemd for production)
./node_exporter

# For production, create a systemd service file (e.g., /etc/systemd/system/node_exporter.service)
[Unit]
Description=Node Exporter
Wants=network-online.target
After=network-online.target

[Service]
User=prometheus # Create a dedicated user
ExecStart=/path/to/node_exporter/node_exporter --collector.textfile.directory=/path/to/node_exporter/textfile_collector

[Install]
WantedBy=multi-user.target

# Then enable and start:
# sudo systemctl daemon-reload
# sudo systemctl enable node_exporter
# sudo systemctl start node_exporter

Ensure Node Exporter is accessible by your Prometheus server (usually on port 9100). Configure Prometheus to scrape these targets as shown in the prometheus.yml example above.

3.2. Essential Infrastructure Metrics

Monitor the following via Grafana dashboards connected to Node Exporter:

  • CPU Usage: Overall CPU utilization, per-core usage, load average.
  • Memory Usage: Total, free, buffered, cached memory. Swap usage.
  • Disk I/O: Read/write operations, I/O wait times, disk space utilization.
  • Network: Bandwidth usage (in/out), network errors, packet drops.
  • System Uptime: Ensure instances haven’t unexpectedly rebooted.

4. Log Aggregation and Analysis

Centralized logging is crucial for debugging and auditing. For a Laravel and MongoDB stack, consider using ELK Stack (Elasticsearch, Logstash, Kibana) or a managed service.

4.1. Laravel Logging Configuration

Configure Laravel’s Monolog to send logs to a central logging system. You can use a custom handler or a pre-built package.

// config/logging.php

'channels' => [
    // ... other channels
    'elastic' => [
        'driver' => 'custom',
        'via' => \App\Logging\ElasticsearchLogHandler::class, // Custom handler
        'level' => env('LOG_LEVEL', 'debug'),
    ],
    'stderr' => [
        'driver' => 'single',
        'path' => storage_path('logs/laravel.log'),
        'level' => env('LOG_LEVEL', 'debug'),
    ],
],

// Set default channel to 'elastic' or 'stderr' as needed
'default' => env('LOG_CHANNEL', 'stderr'),

Create the custom handler (example for sending to Logstash via TCP):

// app/Logging/ElasticsearchLogHandler.php

namespace App\Logging;

use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Logger;
use GuzzleHttp\Client; // Assuming you'll use Guzzle to send to Logstash/Elasticsearch

class ElasticsearchLogHandler extends AbstractProcessingHandler
{
    protected $client;
    protected $logstashUrl;

    public function __construct(array $config = [])
    {
        $level = $config['level'] ?? Logger::DEBUG;
        parent::__construct($level, true);

        $this->logstashUrl = $config['url'] ?? 'http://your_logstash_host:8080/_bulk'; // Or your Elasticsearch endpoint
        $this->client = new Client();
    }

    protected function write(array $record): void
    {
        // Format the log record for Logstash/Elasticsearch
        $formattedRecord = [
            'message' => $record['message'],
            'level' => $record['level_name'],
            'context' => $record['context'],
            'extra' => $record['extra'],
            'datetime' => $record['datetime']->format('Y-m-d\TH:i:s.uP'),
            'channel' => $record['channel'],
        ];

        try {
            $this->client->post($this->logstashUrl, [
                'json' => $formattedRecord,
                'headers' => [
                    'Content-Type' => 'application/json',
                ],
            ]);
        } catch (\Exception $e) {
            // Handle exceptions, e.g., log to stderr if Logstash is down
            error_log("Failed to send log to Logstash: " . $e->getMessage());
        }
    }
}

Configure your .env file:

LOG_CHANNEL=elastic
LOG_LEVEL=info
LOG_ELASTICSEARCH_URL=http://your_logstash_host:8080/_bulk

4.2. MongoDB Logging

MongoDB’s own logs are critical. Ensure they are being collected. You can configure MongoDB to log to files and then use a log shipper like Filebeat or Fluentd to send them to your central logging system. Alternatively, if using PMM, it often provides access to MongoDB logs.

5. Alerting Strategy

Proactive monitoring is only effective if it triggers alerts when thresholds are breached or anomalies are detected. Integrate Prometheus Alertmanager with your monitoring stack.

5.1. Prometheus Alertmanager Configuration

Configure Alertmanager rules in Prometheus (e.g., in a separate alert.rules.yml file) and define receivers (e.g., Slack, PagerDuty, email).

# alert.rules.yml

groups:
- name: laravel_alerts
  rules:
  - alert: HighErrorRate
    expr: sum(rate(laravel_exceptions_total[5m])) by (job, instance) > 10
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "High error rate detected on {{ $labels.instance }}"
      description: "The application on {{ $labels.instance }} is experiencing a high rate of errors (more than 10 per 5 minutes)."

  - alert: HighQueryLatency
    expr: avg_over_time(mongodb_mongod_operation_latency_seconds{operation="query"}[5m]) > 0.5
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: "High MongoDB query latency on {{ $labels.instance }}"
      description: "Average query latency on {{ $labels.instance }} has been above 0.5 seconds for 10 minutes."

  - alert: HighReplicationLag
    expr: mongodb_replset_member_state{state="SECONDARY", replica_set="rs0"} == 1 and mongodb_replset_oplog_window_seconds > 300 # 5 minutes lag
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "MongoDB replication lag on {{ $labels.instance }}"
      description: "Replica set member {{ $labels.instance }} is lagging by more than 5 minutes."

- name: infrastructure_alerts
  rules:
  - alert: HighCpuUsage
    expr: 100 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100 > 90
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: "High CPU usage on {{ $labels.instance }}"
      description: "CPU utilization on {{ $labels.instance }} is above 90% for 10 minutes."

  - alert: LowDiskSpace
    expr: (node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100 < 10
    for: 15m
    labels:
      severity: critical
    annotations:
      summary: "Low disk space on {{ $labels.instance }}"
      description: "Filesystem {{ $labels.mountpoint }} on {{ $labels.instance }} has less than 10% free space."
# alertmanager.yml

global:
  resolve_timeout: 5m

route:
  group_by: ['alertname', 'cluster', 'service']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: 'default-receiver' # Default receiver if no specific route matches

  routes:
  - match:
      severity: 'critical'
    receiver: 'pagerduty-critical'
    continue: true # Allows matching other routes

  - match:
      severity: 'warning'
    receiver: 'slack-warning'
    continue: true

receivers:
- name: 'default-receiver'
  slack_configs:
  - api_url: 'YOUR_SLACK_WEBHOOK_URL'
    channel: '#alerts-general'

- name: 'pagerduty-critical'
  pagerduty_configs:
  - service_key: 'YOUR_PAGERDUTY_INTEGRATION_KEY'

- name: 'slack-warning'
  slack_configs:
  - api_url: 'YOUR_SLACK_WEBHOOK_URL'
    channel: '#alerts-warning'

Ensure Prometheus is configured to load these rules and Alertmanager is correctly set up to receive alerts from Prometheus.

6. OVH Specific Considerations

When operating on OVH, keep the following in mind:

  • Network Segmentation: Utilize OVH’s network features to isolate your database cluster from your web servers, enhancing security and performance. Ensure monitoring agents can communicate across segments if necessary.
  • Instance Types: Choose appropriate instance types for your web servers and MongoDB nodes. Monitor resource utilization closely to identify bottlenecks and scale accordingly.
  • Backup Strategy: While not strictly monitoring, ensure your OVH instance snapshots and MongoDB backup strategy are robust and regularly tested. Monitoring should alert you if backups fail.
  • OVH API Monitoring: For critical infrastructure management, consider monitoring OVH API health and quotas if you heavily rely on them for automated tasks.

Conclusion

A comprehensive monitoring strategy for a Laravel and MongoDB stack on OVH involves integrating application-level insights (Telescope, APM tools), database-specific metrics (PMM), infrastructure health (Node Exporter), and centralized logging. By setting up proactive alerting with Prometheus and Alertmanager, you can significantly reduce downtime and ensure the stability and performance of your critical applications.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • How to build custom Elementor custom widgets extensions utilizing modern Heartbeat API schemas
  • Implementing automated compliance reporting for custom user transaction ledgers ledgers using FPDF customized scripts
  • Troubleshooting Zend memory limit exceed in production when using modern FSE Block Themes wrappers
  • Troubleshooting Zend memory limit exceed in production when using modern Classic Core PHP wrappers
  • Step-by-Step Guide to building a custom two-factor authentication block for Gutenberg using SolidJS high-performance reactive components

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (588)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (814)
  • PHP (5)
  • PHP Development (23)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (557)
  • SEO & Growth (492)
  • Server (23)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (39)
  • WordPress Theme Development (357)

Recent Posts

  • How to build custom Elementor custom widgets extensions utilizing modern Heartbeat API schemas
  • Implementing automated compliance reporting for custom user transaction ledgers ledgers using FPDF customized scripts
  • Troubleshooting Zend memory limit exceed in production when using modern FSE Block Themes wrappers

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (814)
  • Debugging & Troubleshooting (588)
  • Security & Compliance (557)
  • SEO & Growth (492)
  • Business & Monetization (390)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala