本文目录导读:

- 最基础的:错误报告级别控制(Error Reporting Rules)
- 自定义错误处理函数(实现“告警规则引擎”)
- 异常处理规则(Try-Catch + 自定义异常类)
- 生产环境常用告警规则实现方案
- 完整的小型规则引擎示例
- 总结:选择哪种方案?
在 PHP 中处理“告警规则”(通常指错误报告、异常处理、日志监控和报警触发),没有一个内置的“告警规则引擎”,但可以通过以下层次化的机制来实现类似效果。
我会从开发调试到生产监控,按层级说明最常用的做法。
最基础的:错误报告级别控制(Error Reporting Rules)
这是 PHP 自带的“告警开关”,控制哪些错误应该显示/记录。
常见规则配置(php.ini 或运行时):
// 开发环境:显示所有错误 error_reporting(E_ALL); // 生产环境:除了通知和弃用警告,其他都记录但不显示 error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT);
更严格的规则:
// 只记录致命错误和语法错误 error_reporting(E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR);
控制是否显示到屏幕:
ini_set('display_errors', 0); // 生产关闭
ini_set('display_errors', 1); // 开发开启
规则本质:用位运算组合不同的错误级别常量。
自定义错误处理函数(实现“告警规则引擎”)
你可以定义自己的函数,根据错误类型、文件、行号、消息内容等条件,决定是否触发告警。
function customErrorHandler($severity, $message, $file, $line) {
// 定义规则:只有 E_WARNING 以上才记录
if ($severity >= E_WARNING) {
$log = sprintf("[%s] %s in %s:%d\n",
date('Y-m-d H:i:s'), $message, $file, $line);
// 规则1:如果错误包含 "database" 关键字,立即发邮件
if (stripos($message, 'database') !== false) {
mail('[email protected]', 'Database Error', $log);
}
// 规则2:如果是 E_ERROR 级别,写入告警表
if ($severity === E_ERROR) {
file_put_contents('/var/log/php_critical.log', $log, FILE_APPEND);
// 可调用 webhook
}
// 规则3:同一个文件错误超过 5 次,静默忽略
// (需要配合计数器和缓存实现)
}
// 返回 true 表示已处理,阻止 PHP 默认处理
return true;
}
set_error_handler('customErrorHandler');
规则类型举例:
- 按严重级别(Fatal / Warning / Notice)
- 按错误消息关键词(SQL、Timeout、Permission denied)
- 按文件路径(只监控
/app/controllers/目录) - 按频率(同一错误 N 次/分钟 才告警)
- 按用户(仅管理员可见的错误提升告警)
异常处理规则(Try-Catch + 自定义异常类)
现代 PHP 更推荐使用异常(Exception)来处理可预见的“告警”。
class BusinessRuleException extends Exception {}
function processOrder($amount) {
if ($amount < 0) {
throw new BusinessRuleException("订单金额不能为负");
}
if ($amount > 10000) {
// 触发告警规则:大额订单需人工审核
triggerAlert('large_order', ['amount' => $amount]);
}
}
// 全局异常处理规则
set_exception_handler(function($exception) {
$ruleMap = [
BusinessRuleException::class => 'notify_team',
PDOException::class => 'notify_admin_and_retry',
];
$handler = $ruleMap[get_class($exception)] ?? 'default_handler';
call_user_func($handler, $exception);
});
生产环境常用告警规则实现方案
日志 + 外部监控(最常用)
PHP 只负责写结构化日志,规则解析交给外部系统。
日志规则示例(Monolog + 自定义处理器):
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\NativeMailerHandler;
$log = new Logger('app');
$log->pushHandler(new StreamHandler('/var/log/app.log', Logger::WARNING));
// 规则:WARNING 级别且包含 "timeout" 就发邮件
$mailHandler = new NativeMailerHandler(
'[email protected]',
'Alert',
'[email protected]',
Logger::WARNING
);
// 使用处理器装饰器过滤
$mailHandler->pushProcessor(function ($record) {
if (strpos($record['message'], 'timeout') === false) {
return false; // 不处理
}
return $record;
});
$log->pushHandler($mailHandler);
健康检查端点 + 第三方告警服务
编写一个 /health 接口,返回系统状态码和指标:
// health.php
$checks = [
'database' => checkDatabaseConnection(),
'cache' => pingRedis(),
'disk' => disk_free_space('/') > 500*1024*1024,
];
$status = 200;
foreach ($checks as $key => $ok) {
if (!$ok) {
$status = 500;
// 规则:连续 3 次失败才告警(存储在 APCu 中)
$failures = apcu_inc("health_$key");
if ($failures >= 3) {
trigger_external_alert("$key 不可用");
}
} else {
apcu_store("health_$key", 0);
}
}
http_response_code($status);
echo json_encode($checks);
配合 Prometheus + Alertmanager 或 Uptime Robot 等外部系统,根据 HTTP 状态码触发告警。
完整的小型规则引擎示例
如果你需要灵活的自定义规则,可以这样设计:
class AlertRule {
public string $name;
public int $minSeverity; // 最低错误级别
public ?string $pattern; // 消息匹配正则
public ?int $rateLimitSeconds; // 限流秒数
public callable $action; // 触发动作
}
class AlertManager {
private array $rules = [];
private array $rateLimitCache = [];
public function addRule(AlertRule $rule): void {
$this->rules[] = $rule;
}
public function evaluate(\Throwable $e): void {
$message = $e->getMessage();
$severity = ($e instanceof \Error) ? E_ERROR : E_WARNING;
foreach ($this->rules as $rule) {
if ($severity < $rule->minSeverity) continue;
if ($rule->pattern && !preg_match($rule->pattern, $message)) continue;
// 频率限制
if ($rule->rateLimitSeconds) {
$key = $rule->name . '_' . md5($message);
$last = $this->rateLimitCache[$key] ?? 0;
if (time() - $last < $rule->rateLimitSeconds) continue;
$this->rateLimitCache[$key] = time();
}
call_user_func($rule->action, $e);
}
}
}
// 使用
$manager = new AlertManager();
$manager->addRule(new AlertRule(
name: 'database_alert',
minSeverity: E_WARNING,
pattern: '/database.*timeout/i',
rateLimitSeconds: 300, // 5分钟一次
action: fn($e) => mail(...),
));
选择哪种方案?
| 场景 | 推荐方式 |
|---|---|
| 开发阶段调试 | error_reporting + display_errors |
| 简单项目告警 | 自定义错误处理器 + 邮件 |
| 大型项目 | Monolog 结构化日志 + 外部监控系统 |
| 高灵活规则需求 | 你自己写一个 AlertRule 引擎 |
| 无代码侵入 | PHP 写 /health 端点 + 外部看门狗 |
提示:真正的“告警规则”建议交给外部系统(如 Prometheus、Datadog、Sentry),PHP 只负责记录错误信息和暴露健康指标,因为规则管理、去重、升级、通知渠道这些功能在专用系统中实现更成熟。