DEV Community

ahmet gedik
ahmet gedik

Posted on

Building a Monitoring Dashboard for Multi-Site Video Platforms

When you run multiple video sites across different servers, monitoring is essential. Here's how I built a lightweight monitoring dashboard for TrendVidStream and its sister sites.

What to Monitor

For a multi-site video platform, the critical metrics are:

  1. Site availability - Is each site responding?
  2. Content freshness - When was the last successful fetch?
  3. Database health - SQLite integrity and size
  4. API quota - YouTube API usage
  5. Cache hit rates - Are caches working?
  6. Performance - PageSpeed scores over time

Health Check Endpoint

Each site exposes a /health endpoint:

<?php
// health.php

header('Content-Type: application/json');
header('Cache-Control: no-cache');

$db = new PDO('sqlite:' . __DIR__ . '/data/app.db');

// Check database
$dbOk = false;
try {
    $result = $db->query('PRAGMA integrity_check')->fetchColumn();
    $dbOk = ($result === 'ok');
} catch (Exception $e) {
    $dbOk = false;
}

// Get last fetch time
$lastFetch = $db->query(
    "SELECT MAX(fetched_at) FROM videos"
)->fetchColumn();

// Get video counts per region
$regions = $db->query(
    "SELECT region, COUNT(*) as count FROM videos GROUP BY region"
)->fetchAll(PDO::FETCH_KEY_PAIR);

// Database file size
$dbSize = filesize(__DIR__ . '/data/app.db');

// Cache stats
$cacheDir = __DIR__ . '/data/cache';
$cacheFiles = glob($cacheDir . '/*.cache');
$cacheSize = array_sum(array_map('filesize', $cacheFiles ?: []));

$status = [
    'status' => $dbOk ? 'healthy' : 'degraded',
    'timestamp' => date('c'),
    'php_version' => PHP_VERSION,
    'sapi' => php_sapi_name(),
    'database' => [
        'ok' => $dbOk,
        'size_mb' => round($dbSize / 1024 / 1024, 2),
        'last_fetch' => $lastFetch,
        'freshness_hours' => $lastFetch
            ? round((time() - strtotime($lastFetch)) / 3600, 1)
            : null,
    ],
    'regions' => $regions,
    'cache' => [
        'files' => count($cacheFiles ?: []),
        'size_mb' => round($cacheSize / 1024 / 1024, 2),
    ],
    'opcache' => function_exists('opcache_get_status')
        ? opcache_get_status(false)
        : null,
];

http_response_code($dbOk ? 200 : 503);
echo json_encode($status, JSON_PRETTY_PRINT);
Enter fullscreen mode Exit fullscreen mode

Dashboard Collector

A script that checks all sites periodically:

<?php
// monitor.php - Run from a monitoring server or local machine

$sites = [
    'dwv' => 'https://dailywatch.video/health',
    'tvh' => 'https://topvideohub.com/health',
    'tvs' => 'https://trendvidstream.com/health',
    'vvv' => 'https://viralvidvault.com/health',
];

$results = [];

foreach ($sites as $alias => $url) {
    $start = microtime(true);
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 10,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_HTTPHEADER => ['Accept: application/json'],
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $elapsed = round((microtime(true) - $start) * 1000);
    curl_close($ch);

    $data = json_decode($response, true);

    $results[$alias] = [
        'reachable' => $httpCode === 200,
        'status' => $data['status'] ?? 'unreachable',
        'response_ms' => $elapsed,
        'last_fetch' => $data['database']['last_fetch'] ?? null,
        'freshness_hours' => $data['database']['freshness_hours'] ?? null,
        'db_size_mb' => $data['database']['size_mb'] ?? null,
        'regions' => $data['regions'] ?? [],
        'total_videos' => array_sum($data['regions'] ?? []),
    ];
}

// Display dashboard
echo "\n=== Multi-Site Video Platform Monitor ===";
echo "\n" . date('Y-m-d H:i:s') . "\n";
echo str_repeat('=', 60) . "\n\n";

foreach ($results as $alias => $r) {
    $status = $r['reachable'] ? "OK" : "DOWN";
    $fresh = $r['freshness_hours'] !== null
        ? "{$r['freshness_hours']}h ago"
        : "unknown";

    printf(
        "%-5s | %-8s | %4dms | %5d videos | Last fetch: %s | DB: %sMB\n",
        strtoupper($alias),
        $status,
        $r['response_ms'],
        $r['total_videos'],
        $fresh,
        $r['db_size_mb'] ?? '?'
    );
}

// Alert if any site is down or stale
$alerts = [];
foreach ($results as $alias => $r) {
    if (!$r['reachable']) {
        $alerts[] = "ALERT: {$alias} is unreachable";
    }
    if ($r['freshness_hours'] !== null && $r['freshness_hours'] > 12) {
        $alerts[] = "ALERT: {$alias} last fetch was {$r['freshness_hours']} hours ago";
    }
}

if (!empty($alerts)) {
    echo "\n" . str_repeat('!', 60) . "\n";
    foreach ($alerts as $alert) {
        echo "$alert\n";
    }
}
Enter fullscreen mode Exit fullscreen mode

PageSpeed Monitoring

<?php

class PageSpeedMonitor
{
    private string $apiKey;

    public function __construct(string $apiKey)
    {
        $this->apiKey = $apiKey;
    }

    public function audit(string $url, string $strategy = 'mobile'): array
    {
        $apiUrl = 'https://www.googleapis.com/pagespeedonline/v5/runPagespeed?'
            . http_build_query([
                'url' => $url,
                'strategy' => $strategy,
                'key' => $this->apiKey,
                'category' => 'performance',
            ]);

        $response = json_decode(file_get_contents($apiUrl), true);
        $audit = $response['lighthouseResult'] ?? [];

        return [
            'score' => ($audit['categories']['performance']['score'] ?? 0) * 100,
            'lcp' => $audit['audits']['largest-contentful-paint']['numericValue'] ?? 0,
            'cls' => $audit['audits']['cumulative-layout-shift']['numericValue'] ?? 0,
            'inp' => $audit['audits']['experimental-interaction-to-next-paint']['numericValue'] ?? 0,
        ];
    }
}

// Monitor all sites
$monitor = new PageSpeedMonitor(getenv('PAGESPEED_API_KEY'));
$pages = [
    'https://trendvidstream.com/',
    'https://trendvidstream.com/category/music',
    'https://trendvidstream.com/category/gaming',
];

foreach ($pages as $url) {
    $result = $monitor->audit($url);
    printf(
        "%s\n  Score: %d | LCP: %dms | CLS: %.3f\n",
        $url,
        $result['score'],
        $result['lcp'],
        $result['cls']
    );
}
Enter fullscreen mode Exit fullscreen mode

Cron-Based Monitoring

# Check health every 30 minutes
*/30 * * * * php /path/to/monitor.php >> /var/log/monitor.log 2>&1

# PageSpeed audit twice daily
0 6,18 * * * php /path/to/pagespeed_audit.php >> /var/log/pagespeed.log 2>&1
Enter fullscreen mode Exit fullscreen mode

This monitoring system keeps all 4 TrendVidStream sites healthy. The health endpoint pattern is reusable for any PHP application with SQLite.

Key principle: monitor what matters (availability, freshness, performance), alert on what is actionable, and keep the monitoring infrastructure simpler than what it monitors.

Top comments (0)