如何为PHP项目设置错误监控?

wen PHP项目 1

本文目录导读:

如何为PHP项目设置错误监控?

  1. PHP 基础错误配置
  2. 自定义错误处理函数
  3. 日志分类与管理
  4. 集成专业监控工具
  5. 环境配置策略
  6. 框架集成示例
  7. 最佳实践总结

为PHP项目设置错误监控是保障应用稳定性的关键步骤,以下是完整的实施指南,涵盖从基础配置到集成专业监控工具的全流程。

PHP 基础错误配置

php.ini 配置

; 开发环境
display_errors = On
error_reporting = E_ALL
; 生产环境
display_errors = Off
log_errors = On
error_log = /var/log/php_errors.log
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT

通过代码动态设置

// 生产环境安全配置
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', '/path/to/error.log');
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);

自定义错误处理函数

基本实现

// 设置自定义错误处理器
set_error_handler(function($severity, $message, $file, $line) {
    // 记录错误
    error_log("Error [$severity]: $message in $file on line $line");
    // 根据错误级别决定是否抛出异常
    if (error_reporting() & $severity) {
        throw new ErrorException($message, 0, $severity, $file, $line);
    }
});
// 设置未捕获异常处理器
set_exception_handler(function($exception) {
    $message = "Uncaught Exception: " . $exception->getMessage() . 
               " in " . $exception->getFile() . " on line " . $exception->getLine();
    error_log($message);
    // 生产环境显示友好错误页面
    if (php_sapi_name() !== 'cli') {
        http_response_code(500);
        include('error_pages/500.php');
    }
    exit(1);
});
// 确保脚本结束前错误被记录
register_shutdown_function(function() {
    $error = error_get_last();
    if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
        error_log("Fatal Error: {$error['message']} in {$error['file']} on line {$error['line']}");
    }
});

日志分类与管理

按级别分类记录

class AppLogger {
    private $logDir;
    public function __construct($logDir = '/var/log/app') {
        $this->logDir = $logDir;
        if (!is_dir($logDir)) {
            mkdir($logDir, 0755, true);
        }
    }
    public function error($message, array $context = []) {
        $this->log('error', $message, $context);
    }
    public function warning($message, array $context = []) {
        $this->log('warning', $message, $context);
    }
    public function info($message, array $context = []) {
        $this->log('info', $message, $context);
    }
    public function critical($message, array $context = []) {
        $this->log('critical', $message, $context);
        // 发送紧急通知
        $this->sendAlert($message, $context);
    }
    private function log($level, $message, array $context = []) {
        $logFile = $this->logDir . '/' . $level . '_' . date('Y-m-d') . '.log';
        $timestamp = date('Y-m-d H:i:s');
        $contextStr = !empty($context) ? ' | ' . json_encode($context) : '';
        $logEntry = "[$timestamp] [$level] $message $contextStr\n";
        file_put_contents($logFile, $logEntry, FILE_APPEND | LOCK_EX);
    }
    private function sendAlert($message, $context) {
        // 集成邮件、Slack、短信等通知
        // ...
    }
}

集成专业监控工具

使用 Sentry

安装:

composer require sentry/sentry

配置初始化:

<?php
// config/sentry.php
use Sentry\SentrySdk;
use Sentry\State\Hub;
use Sentry\ClientBuilder;
// 初始化 Sentry
SentrySdk::getCurrentHub()->bindClient(
    ClientBuilder::create([
        'dsn' => 'https://your-public-key@your-org.ingest.sentry.io/project-id',
        'environment' => $_ENV['APP_ENV'] ?? 'production',
        'release' => '1.0.0',
        'error_types' => E_ALL & ~E_DEPRECATED & ~E_STRICT,
        'before_send' => function (\Sentry\Event $event): ?\Sentry\Event {
            // 过滤敏感信息
            $event->setExtra('ip', $_SERVER['REMOTE_ADDR'] ?? 'unknown');
            return $event;
        },
    ])->getClient()
);

捕获错误:

// 捕获所有错误
\Sentry\configureScope(function (\Sentry\State\Scope $scope): void {
    $scope->setUser([
        'id' => $userId,
        'email' => $userEmail,
    ]);
});
// 手动捕获异常
try {
    // risky operation
} catch (\Exception $e) {
    \Sentry\captureException($e);
}
// 捕获致命错误
register_shutdown_function(function () {
    $error = error_get_last();
    if ($error !== null) {
        \Sentry\captureLastError();
    }
});

使用 Airbrake

// 安装: composer require airbrake/phpbrake
$notifier = new \Airbrake\Notifier([
    'projectId' => 12345,
    'projectKey' => 'your-api-key',
    'environment' => 'production'
]);
// 设置错误和异常处理器
$handler = new \Airbrake\ErrorHandler($notifier);
$handler->register();

使用日志聚合服务(ELK Stack)

// 发送日志到 Logstash
$context = [
    'environment' => $_ENV['APP_ENV'],
    'server' => gethostname(),
    'request_id' => uniqid(),
];
openlog('myapp', LOG_PID | LOG_PERROR, LOG_LOCAL0);
syslog(LOG_ERR, "Database connection failed: " . $e->getMessage() . " " . json_encode($context));
closelog();

环境配置策略

配置文件分离

// config/error.php
class ErrorConfig {
    public static function getConfig() {
        $env = $_ENV['APP_ENV'] ?? 'production';
        $configs = [
            'development' => [
                'display_errors' => true,
                'error_reporting' => E_ALL,
                'log_errors' => true,
                'log_level' => 'debug'
            ],
            'staging' => [
                'display_errors' => false,
                'error_reporting' => E_ALL & ~E_DEPRECATED,
                'log_errors' => true,
                'log_level' => 'info'
            ],
            'production' => [
                'display_errors' => false,
                'error_reporting' => E_ALL & ~E_DEPRECATED & ~E_STRICT,
                'log_errors' => true,
                'log_level' => 'warning'
            ]
        ];
        return $configs[$env] ?? $configs['production'];
    }
}
// 应用配置
$config = ErrorConfig::getConfig();
ini_set('display_errors', $config['display_errors']);
error_reporting($config['error_reporting']);

框架集成示例

Laravel

// config/app.php 中的配置
'debug' => env('APP_DEBUG', false),
// app/Exceptions/Handler.php
public function register()
{
    $this->reportable(function (Throwable $e) {
        if (app()->bound('sentry')) {
            app('sentry')->captureException($e);
        }
    });
    $this->renderable(function (NotFoundHttpException $e, $request) {
        if ($request->expectsJson()) {
            return response()->json(['error' => 'Resource not found'], 404);
        }
        return response()->view('errors.404', [], 404);
    });
}

Symfony

# config/packages/monolog.yaml
monolog:
    handlers:
        main:
            type: fingers_crossed
            action_level: error
            handler: grouped
        grouped:
            type: group
            members: [streamed, sentry]
        streamed:
            type: stream
            path: '%kernel.logs_dir%/%kernel.environment%.log'
            level: debug
        sentry:
            type: service
            id: Sentry\Monolog\Handler

最佳实践总结

层次 措施 优先级
1️⃣ 合理配置 php.ini 和错误报告级别 必须
2️⃣ 实现自定义错误与异常处理器 强烈建议
3️⃣ 使用结构化日志(JSON格式) 推荐
4️⃣ 集成专业监控工具(Sentry/ELK) 按需
5️⃣ 设置实时告警(邮件/Slack) 生产环境必须
6️⃣ 定期审查日志并优化 持续维护

关键注意事项:

  • 生产环境绝不可开启 display_errors
  • 日志文件必须做日志轮转(logrotate
  • 敏感信息过滤(密码、token、信用卡号等)
  • 错误信息要包含上下文(请求ID、用户ID、会话信息)
  • 定期测试错误监控系统是否正常工作

通过实施上述方案,你可以有效监控PHP项目的错误,及时发现问题并快速响应。

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