本文目录导读:

- 方案一:最轻量级——邮件/短信/钉钉/企业微信机器人(适合小型项目)
- 方案二:集成第三方监控平台(推荐,中型以上项目)
- 方案三:使用 PHP 日志库进行结构化告警(例如 Monolog)
- 方案四:高可靠方案——异步队列 + 熔断
- 关键最佳实践
- 总结推荐
对于PHP项目线上异常,及时推送告警的核心思路是:捕获异常 → 结构化数据 → 通过渠道通知负责人。
以下是几种从简单到复杂的实战方案,你可以根据项目规模选择合适的方式。
最轻量级——邮件/短信/钉钉/企业微信机器人(适合小型项目)
在项目入口文件(如 index.php 或框架的异常处理器)中,设置全局异常捕获。
核心代码示例(使用 PHP 原生或框架全局异常捕获):
<?php
// 1. 设置错误和异常处理函数
set_error_handler([ErrorHandler::class, 'handleError']);
set_exception_handler([ErrorHandler::class, 'handleException']);
class ErrorHandler {
public static function handleException(\Throwable $e) {
// 构建告警信息
$message = sprintf(
"【PHP异常告警】\n项目:%s\n环境:%s\n时间:%s\n文件:%s\n行号:%d\n错误信息:%s\n请求URI:%s\n堆栈:%s",
'你的项目名',
getenv('APP_ENV') ?: 'production', // 生产环境
date('Y-m-d H:i:s'),
$e->getFile(),
$e->getLine(),
$e->getMessage(),
$_SERVER['REQUEST_URI'] ?? 'cli',
$e->getTraceAsString()
);
// 2. 选择推送渠道(以下任选其一)
// self::sendMail($message);
// self::sendDingTalk($message);
// self::sendWechatBot($message);
// 3. 记录日志(方便回溯)
error_log($message, 3, '/tmp/php_alert.log');
}
}
推送渠道实现:
-
钉钉/企业微信机器人(推荐): 在群聊中添加机器人,获取 Webhook URL。
public static function sendDingTalk($text) { $webhook = "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN"; $data = [ 'msgtype' => 'text', 'text' => ['content' => $text] ]; self::curlPost($webhook, json_encode($data)); } public static function sendWechatBot($text) { $webhook = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"; $data = [ 'msgtype' => 'text', 'text' => ['content' => $text] ]; self::curlPost($webhook, json_encode($data)); } -
邮件:
public static function sendMail($text) { $to = "admin@example.com, dev@example.com"; $subject = "PHP生产环境异常告警"; $headers = "From: no-reply@yourdomain.com\r\nContent-Type: text/plain; charset=utf-8"; mail($to, $subject, $text, $headers); }
集成第三方监控平台(推荐,中型以上项目)
这些工具专门处理日志和告警,功能强大,支持聚合、去重、分级和多渠道推送。
Sentry (最流行)
-
特点: 自动捕获未处理的异常、性能问题,提供详细的上下文(用户、请求、Session、数据库查询等)。
-
接入方式:
composer require sentry/sdk
// config.php \Sentry\init([ 'dsn' => 'https://examplePublicKey@o0.ingest.sentry.io/0', 'environment' => 'production', 'release' => '1.0.0', ]); // 手动上报 try { // ... 业务代码 } catch (\Throwable $e) { \Sentry\captureException($e); } -
告警: 在 Sentry 后台设置 Alert Rules,可以关联 Slack、钉钉、企业微信、PagerDuty、邮件等。
阿里云日志服务/腾讯云日志服务(CLS/CTS)
- 特点: 如果你使用阿里云/腾讯云部署,可以直接将 PHP 错误日志推送到云日志服务。
- 告警: 在日志服务控制台设置告警监控,5分钟内错误日志数 > 10”则触发通知。
自建 ELK(Elasticsearch, Logstash, Kibana)
- 特点: 适合大规模微服务架构,PHP 将结构化日志(JSON格式)写入文件,Filebeat/Logstash 采集,存入 ES,通过 ES Watcher 或 ElastAlert 进行规则告警。
使用 PHP 日志库进行结构化告警(Monolog)
Monolog 是 PHP 最流行的日志库,大多数框架(Laravel、Symfony、ThinkPHP)都内置它。
配置技巧:使用不同的 Handler 实现告警分级
<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\NativeMailerHandler;
use Monolog\Handler\SlackWebhookHandler;
$logger = new Logger('app');
// 1. 普通错误写文件
$logger->pushHandler(new StreamHandler('/var/log/php/error.log', Logger::ERROR));
// 2. 严重错误(ERROR 以上)发送钉钉/邮件/企微
$logger->pushHandler(new SlackWebhookHandler(
'https://hooks.slack.com/services/T.../B.../xxx',
'#devops',
'PHP Bot',
true, // 是否使用附件格式
null, // 图标
true, // 是否只发送告警级别
Logger::CRITICAL // 只有 CRITICAL 和 ALERT 级别才推送
));
// 3. 业务代码中
$logger->critical('数据库连接失败', [
'db_host' => '...',
'error_code' => 1001,
'user_id' => $userId
]);
高可靠方案——异步队列 + 熔断
问题: 告警通知 API(如发送钉钉、邮件)如果本身耗时过长或失败,会影响主业务流程。
解决办法:
- 将告警信息放入 Redis 队列(如
RPUSH)。 - 后台常驻 PHP 进程(
php daemon.php)或使用消息队列消费者(如 RabbitMQ),异步消费队列中的告警任务。 - 重试机制: 如果推送失败(网络超时、API限流),重新入队或延迟重试。
// 异常处理器中
$data = json_encode(['type' => 'exception', 'msg' => $e->getMessage(), 'trace' => ...]);
Redis::rpush('alert_queue', $data); // 瞬间完成,不阻塞用户
// 后台 worker 进程(另一个PHP脚本)
while (true) {
$data = Redis::blpop('alert_queue', 5); // 阻塞获取
if ($data) {
// 尝试推送钉钉,失败则重新入队
$result = sendDingTalk($data[1]);
if (!$result) {
Redis::rpush('alert_queue', $data[1]);
}
}
}
关键最佳实践
-
区分级别: 不是所有错误都需要告警。
INFO:无WARNING:记录日志ERROR:记录日志 + 低优先级通知(白天处理)CRITICAL/ALERT/EMERGENCY:立刻推送(钉钉/电话)
-
防止告警风暴:
- 频率限制: 同一个错误在短时间内(如5分钟)不要重复发送多次,可以在 Redis 中记录
error_md5($msg) -> last_send_time。 - 分级升级: 如果5分钟内有10次报错,升级为更高优先级。
- 频率限制: 同一个错误在短时间内(如5分钟)不要重复发送多次,可以在 Redis 中记录
-
上下文丰富:
- 中除了文件、行号、错误信息,一定要包含:
$_SERVER['REQUEST_URI']、$_SERVER['HTTP_HOST']、$_GET、$_POST(脱敏后)、当前登录用户ID。 - 这样收到告警后可以直接复制 URI 去模拟请求定位问题。
- 中除了文件、行号、错误信息,一定要包含:
-
敏感信息脱敏: 在日志/告警中过滤掉密码、Token、身份证号等。
总结推荐
| 项目规模 | 推荐方案 | 成本 | 维护成本 |
|---|---|---|---|
| 小 | 钉钉/企微机器人 + 全局异常捕获 | 极低(免费) | 低 |
| 中 | Sentry | 免费版额度够用 | 极低 |
| 大(自建) | ELK + 自研告警规则 | 服务器成本 | 高 |
| 云原生 | 云日志服务(SLS/CLS) + 告警配置 | 按量付费 | 低 |
一句话建议: 如果你不想折腾,直接集成 Sentry,免费版基本满足小型到中型项目的需求,只需要配置一个 Webhook 到钉钉/企业微信即可。