本文目录导读:

我来为您提供一个完整的PHP监控报警系统示例,包含多种监控场景:
基础系统监控类
<?php
/**
* 系统资源监控类
*/
class SystemMonitor {
private $thresholds;
private $alertChannel;
public function __construct($thresholds = [], $alertChannel = null) {
$this->thresholds = array_merge([
'cpu_usage' => 80, // CPU使用率阈值
'memory_usage' => 80, // 内存使用率阈值
'disk_usage' => 85, // 磁盘使用率阈值
'load_average' => 10 // 负载均衡阈值
], $thresholds);
$this->alertChannel = $alertChannel ?? new AlertChannel();
}
/**
* 检查CPU使用率
*/
public function checkCpuUsage() {
$cpuUsage = $this->getCpuUsage();
$threshold = $this->thresholds['cpu_usage'];
if ($cpuUsage > $threshold) {
$this->alertChannel->send("CPU使用率过高: {$cpuUsage}%", 'critical');
}
return [
'metric' => 'cpu',
'value' => $cpuUsage,
'threshold' => $threshold,
'status' => $cpuUsage > $threshold ? 'ALERT' : 'OK'
];
}
/**
* 获取CPU使用率
*/
private function getCpuUsage() {
$load = sys_getloadavg();
if (function_exists('proc_open')) {
$cmd = "top -b -n1 | grep 'Cpu(s)' | awk '{print $2}'";
$result = exec($cmd);
return floatval($result);
}
return $load[0] * 100;
}
/**
* 检查内存使用率
*/
public function checkMemoryUsage() {
$memInfo = file('/proc/meminfo');
$totalMem = 0;
$freeMem = 0;
foreach ($memInfo as $line) {
if (strpos($line, 'MemTotal:') === 0) {
$parts = explode(':', $line);
$totalMem = (int)trim(str_replace('kB', '', $parts[1]));
} elseif (strpos($line, 'MemAvailable:') === 0) {
$parts = explode(':', $line);
$freeMem = (int)trim(str_replace('kB', '', $parts[1]));
}
}
if ($totalMem > 0) {
$usagePercent = (($totalMem - $freeMem) / $totalMem) * 100;
$threshold = $this->thresholds['memory_usage'];
if ($usagePercent > $threshold) {
$this->alertChannel->send("内存使用率过高: " . round($usagePercent, 2) . "%", 'warning');
}
return [
'metric' => 'memory',
'value' => round($usagePercent, 2),
'threshold' => $threshold,
'status' => $usagePercent > $threshold ? 'ALERT' : 'OK'
];
}
return null;
}
/**
* 检查磁盘使用率
*/
public function checkDiskUsage() {
$diskPath = '/';
$diskFree = disk_free_space($diskPath);
$diskTotal = disk_total_space($diskPath);
if ($diskTotal > 0) {
$usagePercent = (($diskTotal - $diskFree) / $diskTotal) * 100;
$threshold = $this->thresholds['disk_usage'];
if ($usagePercent > $threshold) {
$this->alertChannel->send("磁盘空间不足: " . round($usagePercent, 2) . "%", 'critical');
}
return [
'metric' => 'disk',
'value' => round($usagePercent, 2),
'threshold' => $threshold,
'status' => $usagePercent > $threshold ? 'ALERT' : 'OK'
];
}
return null;
}
/**
* 检查负载均衡
*/
public function checkLoadAverage() {
$load = sys_getloadavg();
if ($load[0] > $this->thresholds['load_average']) {
$this->alertChannel->send("系统负载过高: {$load[0]}", 'warning');
}
return [
'metric' => 'load_average',
'value' => $load[0],
'threshold' => $this->thresholds['load_average'],
'status' => $load[0] > $this->thresholds['load_average'] ? 'ALERT' : 'OK'
];
}
}
Web服务监控类
<?php
/**
* Web服务监控类
*/
class WebMonitor {
private $sites = [];
private $alertChannel;
public function __construct($sites = [], $alertChannel = null) {
$this->sites = $sites;
$this->alertChannel = $alertChannel ?? new AlertChannel();
}
/**
* 检查网站可用性
*/
public function checkWebsite($url) {
$startTime = microtime(true);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_NOBODY => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_CONNECTTIMEOUT => 5
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$responseTime = microtime(true) - $startTime;
curl_close($ch);
// 检查HTTP状态码
if ($httpCode >= 400) {
$this->alertChannel->send("网站 {$url} 返回错误状态码: {$httpCode}", 'critical');
}
// 检查响应时间
if ($responseTime > 3.0) {
$this->alertChannel->send("网站 {$url} 响应过慢: " . round($responseTime, 2) . "s", 'warning');
}
return [
'url' => $url,
'http_code' => $httpCode,
'response_time' => round($responseTime, 2),
'status' => $httpCode >= 400 ? 'ALERT' : ($responseTime > 3.0 ? 'WARNING' : 'OK')
];
}
/**
* 监控API接口
*/
public function checkApi($url, $method = 'GET', $data = null) {
$ch = curl_init($url);
$headers = [
'Content-Type: application/json',
'Accept: application/json'
];
$options = [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_TIMEOUT => 10,
CURLOPT_CUSTOMREQUEST => $method
];
if ($data && in_array($method, ['POST', 'PUT', 'PATCH'])) {
$options[CURLOPT_POSTFIELDS] = json_encode($data);
}
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 解析JSON响应
$responseData = json_decode($response, true);
// 检查是否包含错误信息
if (isset($responseData['error']) || isset($responseData['code']) && $responseData['code'] > 0) {
$this->alertChannel->send("API {$url} 返回错误: " . json_encode($responseData), 'critical');
}
return [
'url' => $url,
'http_code' => $httpCode,
'response' => $responseData,
'status' => $httpCode >= 400 ? 'ALERT' : 'OK'
];
}
/**
* 监控网页内容变化
*/
public function checkContent($url, $expectedContent) {
$content = file_get_contents($url);
if (strpos($content, $expectedContent) === false) {
$this->alertChannel->send("网站 {$url} 内容异常,未找到预期内容", 'warning');
return ['status' => 'ALERT', 'message' => 'Content mismatch'];
}
return ['status' => 'OK', 'message' => 'Content OK'];
}
}
数据库监控类
<?php
/**
* 数据库监控类
*/
class DatabaseMonitor {
private $pdo;
private $alertChannel;
public function __construct($config, $alertChannel = null) {
try {
$dsn = "mysql:host={$config['host']};dbname={$config['dbname']};charset=utf8mb4";
$this->pdo = new PDO($dsn, $config['user'], $config['password'], [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_TIMEOUT => 3
]);
$this->alertChannel = $alertChannel ?? new AlertChannel();
} catch (Exception $e) {
$this->alertChannel->send("数据库连接失败: " . $e->getMessage(), 'critical');
}
}
/**
* 检查数据库连接
*/
public function checkConnection() {
try {
$this->pdo->query('SELECT 1');
return ['status' => 'OK', 'message' => 'Connection successful'];
} catch (Exception $e) {
$this->alertChannel->send("数据库连接失败: " . $e->getMessage(), 'critical');
return ['status' => 'ALERT', 'error' => $e->getMessage()];
}
}
/**
* 检查表空间使用率
*/
public function checkTableSpace($tableName) {
$sql = "SELECT DATA_LENGTH + INDEX_LENGTH as table_size
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = :table";
$stmt = $this->pdo->prepare($sql);
$stmt->execute(['table' => $tableName]);
$size = $stmt->fetchColumn();
return [
'table' => $tableName,
'size_mb' => round($size / 1024 / 1024, 2),
'status' => 'OK'
];
}
/**
* 检查慢查询
*/
public function checkSlowQueries($threshold = 2.0) {
$sql = "SHOW FULL PROCESSLIST";
$queries = $this->pdo->query($sql)->fetchAll();
$slowQueries = array_filter($queries, function($query) use ($threshold) {
return $query['Time'] > $threshold && !empty($query['Info']);
});
if (count($slowQueries) > 0) {
foreach ($slowQueries as $query) {
$this->alertChannel->send(
"慢查询检测到: SQL='{$query['Info']}' 耗时={$query['Time']}s",
'warning'
);
}
}
return [
'total_queries' => count($queries),
'slow_queries' => count($slowQueries),
'status' => count($slowQueries) > 0 ? 'ALERT' : 'OK'
];
}
/**
* 监控连接池使用率
*/
public function checkConnections() {
$maxConnections = 100;
$sql = "SHOW STATUS WHERE Variable_name = 'Threads_connected'";
$current = $this->pdo->query($sql)->fetchColumn();
$usagePercent = ($current / $maxConnections) * 100;
if ($usagePercent > 80) {
$this->alertChannel->send("数据库连接数过高: {$current}/{$maxConnections}", 'warning');
}
return [
'current_connections' => $current,
'max_connections' => $maxConnections,
'usage_percent' => round($usagePercent, 2),
'status' => $usagePercent > 80 ? 'ALERT' : 'OK'
];
}
}
应用日志监控
<?php
/**
* 日志监控类
*/
class LogMonitor {
private $logFile;
private $alertChannel;
private $tailCount = 100;
public function __construct($logFile = '/var/log/php_errors.log', $alertChannel = null) {
$this->logFile = $logFile;
$this->alertChannel = $alertChannel ?? new AlertChannel();
}
/**
* 监控错误日志
*/
public function checkErrorLog($keywords = ['ERROR', 'FATAL', 'CRITICAL']) {
if (!file_exists($this->logFile)) {
return ['status' => 'OK', 'message' => 'Log file not found'];
}
$lines = $this->tailFile($this->tailCount);
$matches = [];
foreach ($lines as $line) {
foreach ($keywords as $keyword) {
if (stripos($line, $keyword) !== false) {
$matches[] = $line;
break;
}
}
}
if (count($matches) > 0) {
$this->alertChannel->send(
"日志中发现错误: " . count($matches) . "条\n" . implode("\n", array_slice($matches, 0, 5)),
'critical'
);
}
return [
'total_lines' => count($lines),
'error_lines' => count($matches),
'status' => count($matches) > 0 ? 'ALERT' : 'OK'
];
}
/**
* 读取文件末尾内容
*/
private function tailFile($lines) {
$file = new SplFileObject($this->logFile);
$file->seek(PHP_INT_MAX);
$totalLines = $file->key();
$startLine = max(0, $totalLines - $lines);
$file->seek($startLine);
$result = [];
while (!$file->eof()) {
$result[] = $file->fgets();
}
return $result;
}
}
报警通知渠道
<?php
/**
* 报警通知渠道
*/
class AlertChannel {
private $webhook;
private $emailConfig;
public function __construct() {
// 可以配置多个通知渠道
$this->webhook = 'https://example.com/webhook'; // Slack/DingTalk/企业微信
$this->emailConfig = [
'host' => 'smtp.example.com',
'port' => 465,
'username' => 'alert@example.com',
'password' => 'your_password',
'to' => 'admin@example.com'
];
}
/**
* 发送报警通知
*/
public function send($message, $level = 'warning') {
// 1. 发送到Webhook
$this->sendToWebhook($message, $level);
// 2. 发送邮件
$this->sendEmail($message, $level);
// 3. 发送短信(可选)
// $this->sendSMS($message, $level);
// 4. 记录到数据库
$this->logToDatabase($message, $level);
}
/**
* 发送Webhook通知
*/
private function sendToWebhook($message, $level) {
$data = [
'message' => $message,
'level' => $level,
'timestamp' => date('Y-m-d H:i:s'),
'host' => gethostname()
];
$ch = curl_init($this->webhook);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => ['Content-Type: application/json']
]);
curl_exec($ch);
curl_close($ch);
}
/**
* 发送邮件通知
*/
private function sendEmail($message, $level) {
// 使用PHP内置mail函数或其他邮件库
// 这里使用简单的示例
$subject = "[服务器报警] {$level} - " . date('Y-m-d H:i');
// mail($this->emailConfig['to'], $subject, $message);
}
/**
* 记录到数据库
*/
private function logToDatabase($message, $level) {
// 使用PDO连接数据库并记录报警信息
// 这里简化处理
$logEntry = [
'timestamp' => date('Y-m-d H:i:s'),
'level' => $level,
'message' => $message,
'host' => gethostname()
];
// 可以写入数据库或文件
$logFile = '/var/log/monitor_alerts.log';
file_put_contents($logFile, json_encode($logEntry) . "\n", FILE_APPEND);
}
}
主监控程序
<?php
/**
* 主监控调度器
*/
class MonitorScheduler {
private $monitors = [];
private $alerts = [];
private $runInterval = 60; // 运行间隔(秒)
public function __construct() {
$this->initializeMonitors();
}
/**
* 初始化所有监控任务
*/
private function initializeMonitors() {
// 系统监控
$this->monitors['system'] = new SystemMonitor([
'cpu_usage' => 80,
'memory_usage' => 80,
'disk_usage' => 85
]);
// Web监控
$this->monitors['web'] = new WebMonitor([
['url' => 'https://example.com', 'name' => '主站'],
['url' => 'https://api.example.com', 'name' => 'API服务']
]);
// 数据库监控
$this->monitors['database'] = new DatabaseMonitor([
'host' => 'localhost',
'dbname' => 'monitor_db',
'user' => 'monitor',
'password' => 'monitor_password'
]);
// 日志监控
$this->monitors['logs'] = new LogMonitor('/var/log/app.log');
}
/**
* 运行监控任务
*/
public function run() {
while (true) {
echo "\n=========== 开始监控 " . date('Y-m-d H:i:s') . " ===========\n";
// 执行所有监控
$results = [];
$results['system_cpu'] = $this->monitors['system']->checkCpuUsage();
$results['system_memory'] = $this->monitors['system']->checkMemoryUsage();
$results['system_disk'] = $this->monitors['system']->checkDiskUsage();
$results['system_load'] = $this->monitors['system']->checkLoadAverage();
// 打印结果
$this->printResults($results);
// 等待下一次运行
echo "\n等待 {$this->runInterval} 秒后继续监控...\n";
sleep($this->runInterval);
}
}
/**
* 打印监控结果
*/
private function printResults($results) {
foreach ($results as $name => $result) {
if ($result && isset($result['status'])) {
$status = $result['status'];
$color = $status === 'OK' ? "\033[32m" : ($status === 'ALERT' ? "\033[31m" : "\033[33m");
$reset = "\033[0m";
echo "{$color}[{$status}]{$reset} {$name}: ";
if (isset($result['value'])) {
echo "value = " . $result['value'];
}
echo "\n";
}
}
}
/**
* 单次运行(用于cron定时任务)
*/
public function runOnce() {
$this->initializeMonitors();
// 执行所有监控
$this->monitors['system']->checkCpuUsage();
$this->monitors['system']->checkMemoryUsage();
$this->monitors['system']->checkDiskUsage();
$this->monitors['system']->checkLoadAverage();
// Web监控
foreach ($this->monitors['web']->getSites() as $site) {
$this->monitors['web']->checkWebsite($site['url']);
}
// 数据库监控
$this->monitors['database']->checkConnection();
$this->monitors['database']->checkSlowQueries(2);
// 日志监控
$this->monitors['logs']->checkErrorLog();
}
}
使用示例
<?php // 启动监控程序 require_once 'monitor.php'; // 创建调度器并启动 $scheduler = new MonitorScheduler(); // 方式1:连续运行(适合开发和测试) // $scheduler->run(); // 方式2:单次运行(配合cron定时任务) // 在crontab中添加:*/5 * * * * php /path/to/monitor.php $scheduler->runOnce();
配置文件
<?php
// config.php
return [
'system' => [
'cpu_threshold' => 80,
'memory_threshold' => 80,
'disk_threshold' => 85
],
'websites' => [
['url' => 'https://example.com', 'name' => '主页'],
['url' => 'https://api.example.com', 'name' => 'API']
],
'database' => [
'host' => 'localhost',
'dbname' => 'monitor',
'user' => 'monitor_user',
'password' => 'monitor_password'
],
'alert' => [
'webhook' => 'https://hooks.slack.com/services/xxx',
'email' => 'admin@example.com',
'levels' => ['warning', 'critical']
]
];
这个监控系统包含:
- 系统监控:CPU、内存、磁盘、负载
- Web监控:网站可用性、响应时间、API状态
- 数据库监控:连接状态、慢查询、表空间
- 日志监控:错误日志检测
- 多通道报警:Webhook、邮件、短信等
- 定时调度:支持连续运行和cron定时方式
您可以根据实际需求进行调整和扩展。