本文目录导读:

我来提供一个完整的 PHP 健康检查失败告警方案,包括监控脚本、告警配置和通知机制。
健康检查脚本方案
基础健康检查脚本
<?php
/**
* PHP健康检查脚本
* 支持命令行和Web访问两种方式
*/
class HealthChecker {
private $config;
public function __construct() {
$this->config = [
'php_version_min' => '7.4',
'memory_limit_min' => '128M',
'disk_space_min' => 1024, // MB
'cache_backend' => 'redis',
'services' => [
'redis' => ['host' => '127.0.0.1', 'port' => 6379],
'mysql' => ['host' => '127.0.0.1', 'port' => 3306],
'rabbitmq' => ['host' => '127.0.0.1', 'port' => 5672],
],
'webhook_url' => getenv('ALERT_WEBHOOK_URL') ?: '',
'notification_services' => [
'slack' => getenv('SLACK_WEBHOOK_URL') ?: '',
'dingtalk' => getenv('DINGTALK_WEBHOOK_URL') ?: '',
'email' => getenv('ADMIN_EMAIL') ?: '',
]
];
}
public function check() {
$results = [];
$healthy = true;
// 基础环境检查
$results['php_version'] = $this->checkPhpVersion();
$results['php_extensions'] = $this->checkPhpExtensions();
$results['memory'] = $this->checkMemory();
$results['disk'] = $this->checkDiskSpace();
$results['permissions'] = $this->checkFilePermissions();
// 服务检查
$results['services'] = $this->checkServices();
// 应用检查
$results['application'] = $this->checkApplication();
// 汇总结果
foreach ($results as $category => $checks) {
foreach ($checks as $check => $result) {
if (!$result['healthy']) {
$healthy = false;
$this->handleFailure($check, $result);
}
}
}
return ['healthy' => $healthy, 'checks' => $results];
}
private function checkPhpVersion() {
$current = PHP_VERSION;
return [
'healthy' => version_compare($current, $this->config['php_version_min'], '>='),
'current' => $current,
'expected' => $this->config['php_version_min']
];
}
private function checkPhpExtensions() {
$required = ['pdo', 'redis', 'json', 'mbstring', 'curl'];
$result = ['healthy' => true, 'missing' => []];
foreach ($required as $ext) {
if (!extension_loaded($ext)) {
$result['healthy'] = false;
$result['missing'][] = $ext;
}
}
return $result;
}
private function checkMemory() {
$limit = ini_get('memory_limit');
return [
'healthy' => $this->parseMemoryLimit($limit) >= $this->config['memory_limit_min'],
'current' => $limit,
'expected' => $this->config['memory_limit_min']
];
}
private function checkDiskSpace() {
$free = disk_free_space("/");
$freeMB = $free != false ? round($free / 1024 / 1024, 2) : 0;
return [
'healthy' => $freeMB >= $this->config['disk_space_min'],
'free_space_mb' => $freeMB,
'expected' => $this->config['disk_space_min']
];
}
private function checkFilePermissions() {
$dirs = ['/var/log', '/tmp', '/var/www/html/storage'];
$result = ['healthy' => true, 'issues' => []];
foreach ($dirs as $dir) {
if (file_exists($dir) && !is_writable($dir)) {
$result['healthy'] = false;
$result['issues'][] = $dir . ' is not writable';
}
}
return $result;
}
private function checkServices() {
$result = ['healthy' => true, 'services' => []];
foreach ($this->config['services'] as $name => $config) {
$connect = @fsockopen($config['host'], $config['port'], $errno, $errstr, 3);
$healthy = $connect !== false;
if ($connect) {
fclose($connect);
}
$result['services'][$name] = [
'healthy' => $healthy,
'error' => $healthy ? null : $errstr
];
if (!$healthy) {
$result['healthy'] = false;
}
}
return $result;
}
private function checkApplication() {
// 应用特定检查,可扩展
$result = ['healthy' => true, 'checks' => []];
// 检查缓存
$result['checks']['cache'] = $this->checkCache();
// 检查队列
$result['checks']['queue'] = $this->checkQueue();
// 检查数据库连接
$result['checks']['database'] = $this->checkDatabase();
return $result;
}
private function parseMemoryLimit($limit) {
$unit = strtolower(substr($limit, -1));
$value = (int)$limit;
switch ($unit) {
case 'g': return $value * 1024;
case 'm': return $value;
case 'k': return $value / 1024;
default: return $value;
}
}
private function handleFailure($check, $result) {
$message = $this->formatAlertMessage($check, $result);
$this->sendAlert($message);
$this->logFailure($message);
}
private function sendAlert($message) {
if ($this->config['notification_services']['slack']) {
$this->sendSlackAlert($message);
}
if ($this->config['notification_services']['dingtalk']) {
$this->sendDingTalkAlert($message);
}
if ($this->config['notification_services']['email']) {
$this->sendEmailAlert($message);
}
}
private function sendSlackAlert($message) {
$data = json_encode([
'text' => ":warning: *PHP Health Check Alert*\n$message"
]);
$this->postToWebhook($this->config['notification_services']['slack'], $data);
}
private function sendDingTalkAlert($message) {
$data = json_encode([
'msgtype' => 'markdown',
'markdown' => [
'title' => 'PHP健康检查告警',
'text' => "### PHP健康检查告警\n\n$message"
]
]);
$this->postToWebhook($this->config['notification_services']['dingtalk'], $data);
}
private function sendEmailAlert($message) {
$subject = '[告警] PHP健康检查失败';
mail($this->config['notification_services']['email'], $subject, $message);
}
private function postToWebhook($url, $data) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_exec($ch);
curl_close($ch);
}
private function formatAlertMessage($check, $result) {
$message = "检查项: $check\n";
$message .= "结果: " . ($result['healthy'] ? '正常' : '异常') . "\n";
if (isset($result['current'])) {
$message .= "当前值: {$result['current']}\n";
}
if (isset($result['expected'])) {
$message .= "期望值: {$result['expected']}\n";
}
if (isset($result['error'])) {
$message .= "错误信息: {$result['error']}\n";
}
return $message;
}
private function logFailure($message) {
$logFile = '/var/log/php-healthcheck.log';
$timestamp = date('Y-m-d H:i:s');
file_put_contents($logFile, "[$timestamp] $message\n", FILE_APPEND);
}
}
// 执行检查
$checker = new HealthChecker();
$result = $checker->check();
// CLI模式下输出结果
if (PHP_SAPI === 'cli') {
echo json_encode($result, JSON_PRETTY_PRINT) . "\n";
exit($result['healthy'] ? 0 : 1);
}
// Web访问模式
header('Content-Type: application/json');
http_response_code($result['healthy'] ? 200 : 503);
echo json_encode($result, JSON_PRETTY_PRINT);
Shell 监控脚本
#!/bin/bash
# healthcheck_wrapper.sh - 包装脚本用于定期监控
#!/bin/bash
# healthcheck_wrapper.sh - 包装脚本用于定期监控
# 配置
PHP_BIN="/usr/bin/php"
SCRIPT_PATH="/var/www/html/healthcheck.php"
LOG_FILE="/var/log/php-healthcheck.log"
ALERT_LOG="/var/log/php-healthcheck-alerts.log"
WEBHOOK_URL_ENV="ALERT_WEBHOOK_URL"
MAX_RETRIES=3
RETRY_INTERVAL=60 # 秒
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
echo -e "$1"
}
# 执行健康检查
run_healthcheck() {
local output
local exit_code
output=$($PHP_BIN "$SCRIPT_PATH" 2>&1)
exit_code=$?
if [ $exit_code -ne 0 ]; then
log_message "${RED}健康检查失败${NC}"
log_message "$output"
return 1
else
log_message "${GREEN}健康检查通过${NC}"
echo "$output" | jq . >> "$LOG_FILE" 2>/dev/null || true
return 0
fi
}
# 重试逻辑
retry_check() {
local attempts=0
local max_retries=$MAX_RETRIES
while [ $attempts -lt $max_retries ]; do
if run_healthcheck; then
return 0
fi
attempts=$((attempts + 1))
log_message "重试 $attempts/$max_retries (等待${RETRY_INTERVAL}秒)"
sleep $RETRY_INTERVAL
done
return 1
}
# 发送告警
send_alert() {
local alert_message="PHP健康检查连续${MAX_RETRIES}次失败"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
# 记录告警
echo "[$timestamp] $alert_message" >> "$ALERT_LOG"
# 发送到webhook
if [ ! -z "$WEBHOOK_URL_ENV" ]; then
curl -X POST -H 'Content-Type: application/json' \
-d "{\"text\": \"🚨 $alert_message\n时间: $timestamp\"}" \
"$WEBHOOK_URL_ENV"
fi
# 发送邮件(如果配置了mail命令)
if command -v mail &> /dev/null; then
echo "$alert_message" | mail -s "PHP健康检查告警" "$ADMIN_EMAIL" 2>/dev/null
fi
}
# 主函数
main() {
log_message "开始执行健康检查..."
if retry_check; then
log_message "健康检查最终结果: 正常"
return 0
else
log_message "健康检查最终结果: 失败"
send_alert
return 1
fi
}
# 运行
main
exit $?
定时任务配置
# crontab 配置示例(每5分钟执行一次) */5 * * * * /usr/bin/php /var/www/html/healthcheck.php --quiet > /dev/null 2>&1 # 或使用Shell脚本(每5分钟检查,失败则立即告警) */5 * * * * /usr/local/bin/healthcheck_wrapper.sh >> /var/log/php-healthcheck-cron.log 2>&1 # 更复杂的监控(每5分钟常规检查,每小时详细检查) */5 * * * * /usr/local/bin/healthcheck_wrapper.sh --quick 0 * * * * /usr/local/bin/healthcheck_wrapper.sh --full # 启动时检查 @reboot /usr/local/bin/healthcheck_wrapper.sh
监控平台集成
Prometheus 导出器
<?php
// prometheus_exporter.php - Prometheus metrics 导出器
class PrometheusExporter {
private $healthChecker;
public function __construct() {
$this->healthChecker = new HealthChecker();
}
public function export() {
$result = $this->healthChecker->check();
$metrics = [];
// 基础指标
$metrics[] = '# HELP php_health_check_total PHP Health Check Status';
$metrics[] = '# TYPE php_health_check_total gauge';
$metrics[] = "php_health_check_total " . ($result['healthy'] ? 1 : 0);
// 服务状态
foreach ($result['checks']['services']['services'] as $name => $status) {
$metrics[] = "# HELP php_service_{$name} Status of {$name} service";
$metrics[] = "# TYPE php_service_{$name} gauge";
$metrics[] = "php_service_{$name} " . ($status['healthy'] ? 1 : 0);
}
// 资源使用
$metrics[] = '# HELP php_memory_usage Current memory usage in MB';
$metrics[] = '# TYPE php_memory_usage gauge';
$metrics[] = "php_memory_usage " . memory_get_usage(true) / 1024 / 1024;
return implode("\n", $metrics);
}
}
header('Content-Type: text/plain; version=0.0.4');
$exporter = new PrometheusExporter();
echo $exporter->export();
Grafana 告警规则
# grafana-alerts.yml
apiVersion: 1
groups:
- name: PHP Health Alerts
rules:
- alert: PHPHealthCheckFailed
expr: php_health_check_total == 0
for: 5m
labels:
severity: critical
annotations:
summary: "PHP Health Check Failed"
description: "PHP application health check has been failing for 5 minutes"
- alert: PHPHighMemoryUsage
expr: php_memory_usage_percent > 85
for: 10m
labels:
severity: warning
annotations:
summary: "High PHP Memory Usage"
description: "PHP memory usage is above 85%"
- alert: PHPRedisDown
expr: php_service_redis == 0
for: 2m
labels:
severity: critical
annotations:
summary: "Redis Service Down"
description: "Redis service is not responding"
告警通知配置
Slack 告警配置
// slack-webhook-config.json
{
"channel": "#php-alerts",
"username": "HealthBot",
"icon_emoji": ":ghost:",
"text": "PHP Monitoring System",
"attachments": [
{
"color": "danger",
"title": "PHP Health Check Failed",
"fields": [
{
"title": "Environment",
"value": "production",
"short": true
},
{
"title": "Timestamp",
"value": "2024-01-01 12:00:00",
"short": true
}
],
"actions": [
{
"type": "button",
"text": "View Dashboard",
"url": "http://monitoring.example.com"
}
]
}
]
}
钉钉/企业微信告警配置
{
"msgtype": "markdown",
"markdown": {: "PHP监控告警",
"text": "## ⚠️ PHP健康检查告警\n\n**检查项:** PHP Version\n**状态:** ❌ 异常\n**详情:** 版本过低\n\n[查看监控面板](http://monitoring.example.com)"
},
"at": {
"isAtAll": false,
"atMobiles": ["13800138000"]
}
}
最佳实践建议
- 分级告警:区分紧急(服务宕机)和警告(资源使用率高)
- 告警聚合:避免重复告警,设置聚合窗口
- 自动恢复:实现简单的自动重启脚本
- 监控可视化:使用 Grafana 展示趋势
- 告警分流:根据服务重要性分配不同通知渠道
- 留档记录:保存历史告警记录用于分析
测试命令
# 手动测试健康检查 curl http://localhost/healthcheck.php # 测试告警 curl -X POST http://localhost/healthcheck.php --test-alert # 查看日志 tail -f /var/log/php-healthcheck.log # 强制触发告警(模拟故障) PHP_ALERT_TEST=true php healthcheck.php
这个方案提供了完整的监控告警体系,可以根据实际需要调整和扩展,记得根据你的部署环境调整路径、端口和通知渠道配置。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播