本文目录导读:

我来为您提供一个完整的PHP自动化巡检脚本方案,包含服务器健康检查、安全检查和性能监控等功能。
基础巡检脚本
server_check.php
<?php
/**
* PHP服务器自动化巡检脚本
* 用于监控服务器健康状态、性能指标和安全状况
*/
class ServerHealthCheck {
private $results = [];
private $thresholds = [
'cpu_load' => 0.8, // CPU使用率阈值 80%
'memory_limit' => 0.9, // 内存使用率阈值 90%
'disk_limit' => 0.85, // 磁盘使用率阈值 85%
'response_time' => 2.0, // 响应时间阈值(秒)
];
public function __construct($thresholds = []) {
if (!empty($thresholds)) {
$this->thresholds = array_merge($this->thresholds, $thresholds);
}
}
/**
* 运行所有检查项目
*/
public function runAllChecks() {
$this->checkSystemInfo();
$this->checkCPUUsage();
$this->checkMemoryUsage();
$this->checkDiskUsage();
$this->checkNetworkConnection();
$this->checkWebServerStatus();
$this->checkPhpExtensions();
$this->checkFilePermissions();
$this->checkSecurity();
$this->checkErrorLogs();
return $this->generateReport();
}
/**
* 检查系统基本信息
*/
private function checkSystemInfo() {
$this->results['system'] = [
'os' => php_uname(),
'php_version' => PHP_VERSION,
'server_software' => $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown',
'server_ip' => $_SERVER['SERVER_ADDR'] ?? gethostbyname(gethostname()),
'uptime' => $this->getSystemUptime(),
'date' => date('Y-m-d H:i:s')
];
}
/**
* 检查CPU使用率
*/
private function checkCPUUsage() {
$cpuInfo = $this->getCPUUsage();
$status = $cpuInfo['usage'] < ($this->thresholds['cpu_load'] * 100) ? 'OK' : 'WARNING';
$this->results['cpu'] = [
'status' => $status,
'usage_percent' => round($cpuInfo['usage'], 2),
'cores' => $cpuInfo['cores'],
'details' => $cpuInfo['details']
];
}
/**
* 获取CPU使用率
*/
private function getCPUUsage() {
// Linux系统实现
if (PHP_OS_FAMILY === 'Linux') {
$load = sys_getloadavg();
$cores = $this->getCpuCoreCount();
$usage = $load[0] / $cores * 100;
return [
'usage' => $usage,
'cores' => $cores,
'details' => "Load average: " . implode(', ', array_map(fn($v) => round($v, 2), $load))
];
}
// Windows系统实现(简化版)
$info = exec('wmic cpu get loadpercentage /value');
preg_match('/LoadPercentage=(\d+)/', $info, $matches);
$usage = isset($matches[1]) ? (float)$matches[1] : 0;
return [
'usage' => $usage,
'cores' => 1,
'details' => 'Windows CPU info'
];
}
/**
* 获取CPU核心数
*/
private function getCpuCoreCount() {
if (PHP_OS_FAMILY === 'Linux') {
return (int)shell_exec('nproc') ?: 1;
}
return 1;
}
/**
* 检查内存使用率
*/
private function checkMemoryUsage() {
$memoryInfo = $this->getMemoryUsage();
$usagePercent = $memoryInfo['used'] / $memoryInfo['total'] * 100;
$status = $usagePercent < ($this->thresholds['memory_limit'] * 100) ? 'OK' : 'WARNING';
$this->results['memory'] = [
'status' => $status,
'total' => $this->formatBytes($memoryInfo['total']),
'used' => $this->formatBytes($memoryInfo['used']),
'free' => $this->formatBytes($memoryInfo['free']),
'usage_percent' => round($usagePercent, 2),
'details' => $memoryInfo['raw']
];
}
/**
* 获取内存使用信息
*/
private function getMemoryUsage() {
if (PHP_OS_FAMILY === 'Linux') {
$meminfo = file_get_contents('/proc/meminfo');
preg_match('/MemTotal:\s+(\d+)/', $meminfo, $total);
preg_match('/MemAvailable:\s+(\d+)/', $meminfo, $available);
$totalBytes = $total[1] * 1024; // KB to bytes
$availableBytes = $available[1] * 1024;
return [
'total' => $totalBytes,
'used' => $totalBytes - $availableBytes,
'free' => $availableBytes,
'raw' => $meminfo
];
}
// Windows系统
$output = [];
exec('wmic OS get TotalVisibleMemorySize,FreePhysicalMemory /Value', $output);
$totalKb = 0;
$freeKb = 0;
foreach ($output as $line) {
if (strpos($line, 'TotalVisibleMemorySize=') !== false) {
$totalKb = (int)str_replace('TotalVisibleMemorySize=', '', $line);
}
if (strpos($line, 'FreePhysicalMemory=') !== false) {
$freeKb = (int)str_replace('FreePhysicalMemory=', '', $line);
}
}
return [
'total' => $totalKb * 1024,
'used' => ($totalKb - $freeKb) * 1024,
'free' => $freeKb * 1024,
'raw' => 'Windows memory info'
];
}
/**
* 检查磁盘使用率
*/
private function checkDiskUsage() {
$disks = [];
$issues = [];
if (PHP_OS_FAMILY === 'Linux') {
$df = shell_exec('df -h');
$lines = explode("\n", $df);
array_shift($lines); // 移除标题行
foreach ($lines as $line) {
if (trim($line) === '') continue;
$parts = preg_split('/\s+/', $line);
if (count($parts) >= 5) {
$disk = [
'filesystem' => $parts[0],
'size' => $parts[1],
'used' => $parts[2],
'available' => $parts[3],
'usage_percent' => (int)str_replace('%', '', $parts[4]),
'mounted_on' => $parts[5] ?? ''
];
$disks[] = $disk;
if ($disk['usage_percent'] > ($this->thresholds['disk_limit'] * 100)) {
$issues[] = "磁盘 {$disk['mounted_on']} 使用率超过阈值: {$disk['usage_percent']}%";
}
}
}
} else {
// Windows等其他系统检查
$output = [];
exec('wmic logicaldisk get deviceid,size,freespace /Value', $output);
// 解析输出...
}
$this->results['disk'] = [
'status' => empty($issues) ? 'OK' : 'WARNING',
'disks' => $disks,
'issues' => $issues
];
}
/**
* 检查网络连接
*/
private function checkNetworkConnection() {
$connections = [];
$issues = [];
// 检查外部连接
$externalHosts = [
'google' => 'google.com',
'github' => 'github.com'
];
foreach ($externalHosts as $name => $host) {
$pingTime = $this->pingHost($host);
$connections[$name] = $pingTime;
if ($pingTime === false) {
$issues[] = "无法连接到 $host";
}
}
// 检查数据库连接(如果配置了)
if (defined('DB_HOST')) {
$dbConnection = $this->checkDatabaseConnection();
$connections['database'] = $dbConnection;
if (!$dbConnection['success']) {
$issues[] = "数据库连接失败";
}
}
$this->results['network'] = [
'status' => empty($issues) ? 'OK' : 'WARNING',
'connections' => $connections,
'issues' => $issues
];
}
/**
* Ping外部主机
*/
private function pingHost($host) {
$startTime = microtime(true);
if (PHP_OS_FAMILY === 'Linux') {
$output = [];
exec("ping -c 1 -w 2 $host", $output, $returnCode);
if ($returnCode === 0) {
$time = microtime(true) - $startTime;
return round($time * 1000); // 毫秒
}
return false;
} else {
// Windows
$output = [];
exec("ping -n 1 -w 2000 $host", $output, $returnCode);
if ($returnCode === 0) {
$time = microtime(true) - $startTime;
return round($time * 1000);
}
return false;
}
}
/**
* 检查数据库连接
*/
private function checkDatabaseConnection() {
try {
$pdo = new PDO(
'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME,
DB_USER,
DB_PASS,
[PDO::ATTR_TIMEOUT => 2]
);
return [
'success' => true,
'info' => 'Database connection OK'
];
} catch (Exception $e) {
return [
'success' => false,
'info' => 'Database connection failed: ' . $e->getMessage()
];
}
}
/**
* 检查Web服务器状态
*/
private function checkWebServerStatus() {
$issues = [];
$serverInfo = [];
// 检查Apache/Nginx进程
if (PHP_OS_FAMILY === 'Linux') {
foreach (['apache2', 'nginx', 'httpd'] as $service) {
$output = [];
exec("ps aux | grep -v grep | grep $service", $output);
if (!empty($output)) {
$serverInfo[$service] = 'Running';
} else {
$serverInfo[$service] = 'Not running';
$issues[] = "$service is not running";
}
}
}
// 检查PHP-FPM
if (PHP_OS_FAMILY === 'Linux') {
$output = [];
exec("ps aux | grep -v grep | grep php-fpm", $output);
$serverInfo['php-fpm'] = !empty($output) ? 'Running' : 'Not running';
if (empty($output)) {
$issues[] = 'PHP-FPM is not running';
}
}
$this->results['web_server'] = [
'status' => empty($issues) ? 'OK' : 'WARNING',
'services' => $serverInfo,
'issues' => $issues
];
}
/**
* 检查PHP扩展
*/
private function checkPhpExtensions() {
$requiredExtensions = [
'mysqli', 'pdo_mysql', 'curl', 'json', 'gd', 'mbstring',
'xml', 'zip', 'openssl', 'redis', 'memcached'
];
$extensions = [];
$missingExtensions = [];
foreach ($requiredExtensions as $ext) {
$extensions[$ext] = extension_loaded($ext) ? 'Enabled' : 'Disabled';
if (!extension_loaded($ext)) {
$missingExtensions[] = $ext;
}
}
$this->results['php_extensions'] = [
'status' => empty($missingExtensions) ? 'OK' : 'WARNING',
'extensions' => $extensions,
'missing' => $missingExtensions
];
}
/**
* 检查文件权限
*/
private function checkFilePermissions() {
$criticalPaths = [
'web_root' => $_SERVER['DOCUMENT_ROOT'] ?? '.',
'upload_dir' => 'uploads',
'log_dir' => 'logs',
'config' => 'config.php'
];
$issues = [];
$permissions = [];
foreach ($criticalPaths as $name => $path) {
if (file_exists($path)) {
$perms = fileperms($path);
$writable = is_writable($path);
$permissions[$name] = [
'path' => $path,
'permissions' => substr(sprintf('%o', $perms), -4),
'writable' => $writable
];
if (!$writable) {
$issues[] = "目录/文件 $path 不可写";
}
}
}
// 检查敏感文件是否可访问
$sensitiveFiles = ['.env', 'config.php', 'database.sql'];
foreach ($sensitiveFiles as $file) {
if (file_exists($file) && !$this->isFileProtected($file)) {
$issues[] = "敏感文件 $file 可能暴露在Web环境下";
}
}
$this->results['permissions'] = [
'status' => empty($issues) ? 'OK' : 'WARNING',
'permissions' => $permissions,
'issues' => $issues
];
}
/**
* 检查文件是否受保护
*/
private function isFileProtected($file) {
// 检查是否在web根目录之外
$absolutePath = realpath($file);
$webRoot = realpath($_SERVER['DOCUMENT_ROOT'] ?? '.');
return strpos($absolutePath, $webRoot) !== 0;
}
/**
* 安全检查
*/
private function checkSecurity() {
$securityIssues = [];
$checks = [];
// 检查PHP版本安全性
$phpVersion = PHP_VERSION;
$checks['php_version'] = "PHP版本: $phpVersion";
if (version_compare($phpVersion, '7.4', '<')) {
$securityIssues[] = "PHP版本过低,建议升级到7.4以上";
}
// 检查显示错误设置
$displayErrors = ini_get('display_errors');
$checks['display_errors'] = $displayErrors ? 'Enabled' : 'Disabled';
if ($displayErrors) {
$securityIssues[] = "display_errors已开启,建议在生产环境关闭";
}
// 检查错误报告级别
$errorReporting = error_reporting();
$checks['error_reporting'] = $errorReporting;
// 检查文件上传设置
$fileUploads = ini_get('file_uploads');
$checks['file_uploads'] = $fileUploads ? 'Enabled' : 'Disabled';
// 检查open_basedir
$openBasedir = ini_get('open_basedir');
$checks['open_basedir'] = $openBasedir ? $openBasedir : 'Not Set';
if (empty($openBasedir)) {
$securityIssues[] = "open_basedir未设置,可能存在目录遍历风险";
}
// 检查关键函数是否被禁用
$dangerousFunctions = ['exec', 'system', 'passthru', 'shell_exec', 'proc_open'];
$disabledFunctions = array_filter(explode(',', ini_get('disable_functions')));
foreach ($dangerousFunctions as $func) {
if (!in_array(trim($func), $disabledFunctions)) {
$checks["func_$func"] = "未禁用 $func()";
$securityIssues[] = "高风险函数 $func() 未被禁用";
}
}
// 检查HTTPS
$https = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
$checks['https'] = $https ? 'Enabled' : 'Disabled';
if (!$https && PHP_SAPI !== 'cli') {
$securityIssues[] = "当前未使用HTTPS连接";
}
$this->results['security'] = [
'status' => empty($securityIssues) ? 'OK' : 'WARNING',
'checks' => $checks,
'issues' => $securityIssues
];
}
/**
* 检查错误日志
*/
private function checkErrorLogs() {
$logFile = ini_get('error_log');
$issues = [];
$recentErrors = [];
if (file_exists($logFile)) {
$logSize = filesize($logFile);
$mtime = filemtime($logFile);
// 读取最后100行日志
$lines = $this->getLastLines($logFile, 100);
foreach ($lines as $line) {
if (preg_match('/\[error\]|\[warning\]|Fatal error/i', $line)) {
$recentErrors[] = trim($line);
if (strpos($line, 'Fatal error') !== false) {
$issues[] = "发现致命错误: $line";
}
}
}
$this->results['error_log'] = [
'status' => empty($issues) ? 'OK' : 'WARNING',
'log_file' => $logFile,
'log_size' => $this->formatBytes($logSize),
'last_modified' => date('Y-m-d H:i:s', $mtime),
'recent_errors' => array_slice($recentErrors, -5),
'issues' => $issues
];
} else {
$this->results['error_log'] = [
'status' => 'WARNING',
'issues' => ['未找到错误日志文件: ' . $logFile]
];
}
}
/**
* 读取文件最后几行
*/
private function getLastLines($file, $lines = 100) {
if (PHP_OS_FAMILY === 'Linux') {
return explode("\n", shell_exec("tail -n $lines $file"));
}
// 其他系统使用PHP实现
$content = file_get_contents($file);
$contentLines = explode("\n", $content);
return array_slice($contentLines, -$lines);
}
/**
* 生成报告
*/
private function generateReport() {
$summary = [
'total_checks' => 0,
'ok' => 0,
'warnings' => 0,
'errors' => 0
];
foreach ($this->results as $category => $result) {
if (isset($result['status'])) {
$summary['total_checks']++;
switch ($result['status']) {
case 'OK':
$summary['ok']++;
break;
case 'WARNING':
$summary['warnings']++;
break;
case 'ERROR':
$summary['errors']++;
break;
}
}
}
// 设置整体状态
$overallStatus = 'OK';
if ($summary['errors'] > 0) {
$overallStatus = 'ERROR';
} elseif ($summary['warnings'] > 0) {
$overallStatus = 'WARNING';
}
return [
'overall_status' => $overallStatus,
'summary' => $summary,
'timestamp' => date('Y-m-d H:i:s'),
'details' => $this->results
];
}
/**
* 格式化字节
*/
private function formatBytes($bytes, $precision = 2) {
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= pow(1024, $pow);
return round($bytes, $precision) . ' ' . $units[$pow];
}
/**
* 获取系统运行时间
*/
private function getSystemUptime() {
if (PHP_OS_FAMILY === 'Linux') {
$uptime = shell_exec('cat /proc/uptime');
$seconds = floatval(explode(' ', $uptime)[0]);
$days = floor($seconds / 86400);
$hours = floor(($seconds % 86400) / 3600);
$minutes = floor(($seconds % 3600) / 60);
return "$days天 $hours小时 $minutes分钟";
}
return 'System uptime info unavailable';
}
}
// 使用方法示例
if (PHP_SAPI === 'cli') {
// 命令行模式
$healthCheck = new ServerHealthCheck();
$report = $healthCheck->runAllChecks();
echo json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . PHP_EOL;
}
数据库巡检脚本
database_check.php
<?php
/**
* 数据库巡检脚本
*/
function checkDatabaseHealth() {
// 数据库配置
$dbConfig = [
'host' => 'localhost',
'name' => 'your_database',
'user' => 'your_user',
'pass' => 'your_password',
'port' => 3306
];
$results = [
'status' => 'OK',
'checks' => []
];
try {
$pdo = new PDO(
"mysql:host={$dbConfig['host']};dbname={$dbConfig['name']};charset=utf8mb4",
$dbConfig['user'],
$dbConfig['pass'],
[
PDO::ATTR_TIMEOUT => 5,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]
);
// 1. 数据库版本
$version = $pdo->query('SELECT VERSION()')->fetchColumn();
$results['checks']['version'] = $version;
// 2. 数据库状态
$status = $pdo->query('SHOW STATUS')->fetchAll(PDO::FETCH_KEY_PAIR);
$results['checks']['qps'] = $status['Questions'] ?? 'N/A'; // 查询次数
// 3. 连接数
$connections = $pdo->query('SHOW STATUS LIKE "Threads_connected"')->fetch();
$maxConnections = $pdo->query('SHOW VARIABLES LIKE "max_connections"')->fetch();
$currentConn = (int)$connections['Value'];
$maxConn = (int)$maxConnections['Value'];
$usagePercent = ($currentConn / $maxConn) * 100;
$results['checks']['connections'] = [
'current' => $currentConn,
'max' => $maxConn,
'usage_percent' => round($usagePercent, 2)
];
if ($usagePercent > 85) {
$results['status'] = 'WARNING';
$results['issues'][] = "数据库连接数使用率过高: {$usagePercent}%";
}
// 4. 慢查询
$slowQueries = $pdo->query('SHOW STATUS LIKE "Slow_queries"')->fetch();
$results['checks']['slow_queries'] = $slowQueries['Value'] ?? 'N/A';
// 5. InnoDB状态
$innodbStatus = $pdo->query('SHOW ENGINE INNODB STATUS')->fetch();
if ($innodbStatus) {
preg_match('/Active transactions: (\d+)/', $innodbStatus['Status'], $matches);
$results['checks']['active_transactions'] = $matches[1] ?? 'N/A';
}
// 6. 数据库表检查
$tables = $pdo->query('SHOW TABLES')->fetchAll(PDO::FETCH_COLUMN);
$brokenTables = [];
foreach ($tables as $table) {
$checkResult = $pdo->query("CHECK TABLE $table")->fetch();
if ($checkResult['Msg_type'] === 'error') {
$brokenTables[] = $table;
}
}
$results['checks']['tables'] = [
'total' => count($tables),
'broken' => $brokenTables
];
// 7. 数据库大小
$dbSize = $pdo->query(
"SELECT table_schema AS 'database',
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS 'size_mb'
FROM information_schema.tables
WHERE table_schema = '{$dbConfig['name']}'
GROUP BY table_schema"
)->fetch();
$results['checks']['database_size'] = $dbSize['size_mb'] . ' MB';
// 8. 最后一次备份时间
$backupDir = '/path/to/backup/dir'; // 配置备份目录
if (is_dir($backupDir)) {
$backupFiles = glob($backupDir . '/*');
if (!empty($backupFiles)) {
$latestBackup = max(array_map('filemtime', $backupFiles));
$daysSinceBackup = (time() - $latestBackup) / 86400;
$results['checks']['last_backup'] = date('Y-m-d H:i:s', $latestBackup);
$results['checks']['backup_age_days'] = round($daysSinceBackup, 2);
if ($daysSinceBackup > 1) {
$results['status'] = 'WARNING';
$results['issues'][] = "数据库超过1天未备份";
}
}
}
} catch (PDOException $e) {
$results['status'] = 'ERROR';
$results['message'] = '数据库连接失败: ' . $e->getMessage();
}
return $results;
}
// 执行检查
$report = checkDatabaseHealth();
echo json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
配置文件和定时任务
config.php
<?php
// 数据库配置(用于巡检脚本)
define('DB_HOST', 'localhost');
define('DB_NAME', 'your_database');
define('DB_USER', 'your_user');
define('DB_PASS', 'your_password');
// 邮件通知配置
define('MAIL_ENABLED', true);
define('MAIL_TO', 'admin@example.com');
define('MAIL_FROM', 'monitor@example.com');
// Webhook通知配置
define('WEBHOOK_ENABLED', true);
define('WEBHOOK_URL', 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL');
// 短信通知配置(示例)
define('SMS_ENABLED', false);
notification.php
<?php
/**
* 通知发送功能
*/
class NotificationCenter {
public static function sendReport($report) {
$messages = [];
if ($report['overall_status'] !== 'OK') {
// 发送邮件
if (defined('MAIL_ENABLED') && MAIL_ENABLED) {
self::sendEmail($report);
}
// 发送Webhook
if (defined('WEBHOOK_ENABLED') && WEBHOOK_ENABLED) {
self::sendWebhook($report);
}
}
return true;
}
private static function sendEmail($report) {
$subject = "[{$report['overall_status']}] 服务器巡检报告 - " . date('Y-m-d H:i:s');
// 生成HTML报告
$htmlReport = self::generateHtmlReport($report);
$headers = "MIME-Version: 1.0\r\n";
$headers .= "Content-type: text/html; charset=utf-8\r\n";
$headers .= "From: " . MAIL_FROM . "\r\n";
// 使用mail函数或PHPMailer
mail(MAIL_TO, $subject, $htmlReport, $headers);
}
private static function sendWebhook($report) {
$payload = [
'text' => "🚨 *服务器巡检提醒*\n" .
"*状态:* {$report['overall_status']}\n" .
"*时间:* {$report['timestamp']}\n" .
"*警告数:* {$report['summary']['warnings']}\n" .
"*错误数:* {$report['summary']['errors']}"
];
$ch = curl_init(WEBHOOK_URL);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
}
private static function generateHtmlReport($report) {
$html = '<h2>服务器巡检报告</h2>';
$html .= "<p>状态: <strong>{$report['overall_status']}</strong></p>";
$html .= "<p>时间: {$report['timestamp']}</p>";
foreach ($report['details'] as $category => $details) {
$html .= "<h3>{$category}</h3>";
if (isset($details['status'])) {
$html .= "<p>状态: {$details['status']}</p>";
}
if (isset($details['issues']) && !empty($details['issues'])) {
$html .= '<ul>';
foreach ($details['issues'] as $issue) {
$html .= "<li>$issue</li>";
}
$html .= '</ul>';
}
}
return $html;
}
}
// 如果报告完成,发送通知
NotificationCenter::sendReport($report);
定时任务配置
crontab 配置示例
# 每天凌晨2点执行服务器巡检 0 2 * * * php /path/to/server_check.php >> /var/log/php_check.log 2>&1 # 每30分钟检查一次Web服务状态 */30 * * * * php /path/to/web_service_check.php # 每天检查数据库状态 30 3 * * * php /path/to/database_check.php # 每周日完整巡检 0 4 * * 0 php /path/to/full_check.php
使用说明
配置文件
- 将上述代码保存为对应文件
- 修改
config.php中的数据库配置和通知配置 - 测试运行:
php server_check.php
主要功能
- 系统检查: CPU、内存、磁盘使用情况
- 性能监控: 响应时间、负载均衡
- 安全扫描: 敏感文件、危险函数、安全配置
- 数据库检查: 连接数、慢查询、表完整性
- Web服务检查: Apache/Nginx、PHP-FPM状态
通知方式
- 邮件通知
- Webhook(如Slack、钉钉)
- 可扩展短信通知
这个巡检脚本可以根据您的具体需求进行调整和扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播