PHP项目线上异常如何及时推送告警

wen PHP项目 30

本文目录导读:

PHP项目线上异常如何及时推送告警

  1. 方案一:最轻量级——邮件/短信/钉钉/企业微信机器人(适合小型项目)
  2. 方案二:集成第三方监控平台(推荐,中型以上项目)
  3. 方案三:使用 PHP 日志库进行结构化告警(例如 Monolog)
  4. 方案四:高可靠方案——异步队列 + 熔断
  5. 关键最佳实践
  6. 总结推荐

对于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(如发送钉钉、邮件)如果本身耗时过长或失败,会影响主业务流程。

解决办法:

  1. 将告警信息放入 Redis 队列(如 RPUSH)。
  2. 后台常驻 PHP 进程php daemon.php)或使用消息队列消费者(如 RabbitMQ),异步消费队列中的告警任务。
  3. 重试机制: 如果推送失败(网络超时、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]);
        }
    }
}

关键最佳实践

  1. 区分级别: 不是所有错误都需要告警。

    • INFO:无
    • WARNING:记录日志
    • ERROR:记录日志 + 低优先级通知(白天处理)
    • CRITICAL/ALERT/EMERGENCY:立刻推送(钉钉/电话)
  2. 防止告警风暴:

    • 频率限制: 同一个错误在短时间内(如5分钟)不要重复发送多次,可以在 Redis 中记录 error_md5($msg) -> last_send_time
    • 分级升级: 如果5分钟内有10次报错,升级为更高优先级。
  3. 上下文丰富:

    • 中除了文件、行号、错误信息,一定要包含$_SERVER['REQUEST_URI']$_SERVER['HTTP_HOST']$_GET$_POST(脱敏后)、当前登录用户ID。
    • 这样收到告警后可以直接复制 URI 去模拟请求定位问题。
  4. 敏感信息脱敏: 在日志/告警中过滤掉密码、Token、身份证号等。

总结推荐

项目规模 推荐方案 成本 维护成本
钉钉/企微机器人 + 全局异常捕获 极低(免费)
Sentry 免费版额度够用 极低
大(自建) ELK + 自研告警规则 服务器成本
云原生 云日志服务(SLS/CLS) + 告警配置 按量付费

一句话建议: 如果你不想折腾,直接集成 Sentry,免费版基本满足小型到中型项目的需求,只需要配置一个 Webhook 到钉钉/企业微信即可。

抱歉,评论功能暂时关闭!