好的,我想我已经想通了。看来this is related to a bug in which the PDO MySQL driver emits warnings even when they are supposed to be disabled(另见:this answer)。我相信 Sentry 会将这些视为错误。
我终于能够通过修改 Bill Karwin 的测试脚本来复制并解决这个问题:
// Initialize the Sentry reporting client
$ravenClient = new \Raven_Client(SENTRY_KEY);
$ravenClient->install();
echo 'Connecting...' . PHP_EOL;
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo 'Connected. Waiting...' . PHP_EOL;
sleep(20); // during this sleep, I stop my MySQL Server instance.
echo 'Querying...' . PHP_EOL;
try {
$result = $pdo->query("SELECT 1");
}
catch(\PDOException $e) {
echo 'Caught PDOException ' . $e->getMessage() . PHP_EOL;
}
这将打印以下内容:
Connecting...
Connected. Waiting...
Querying...
PHP Warning: PDO::query(): MySQL server has gone away in /home/xxx/src/test.php on line 37
PHP Stack trace:
PHP 1. {main}() /home/xxx/src/test.php:0
PHP 2. PDO->query() /home/xxx/src/test.php:37
Caught PDOException SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
Done.
Sentry 将在query() 行上记录一个ErrorException。
我能够通过实施 jferrer 在the PHP bug report 上发布的“解决方案”来解决这个问题。
// Convert NOTICE, WARNING, ... in Exceptions
$convertErrorToException = function ($level, $message, $file, $line){
throw new ErrorException($message, 0, $level, $file, $line);
};
// The $previousErrorHandler will contain Sentry's handler
$previousErrorHandler = set_error_handler($convertErrorToException);
try {
$result = $pdo->query("SELECT 1");
}
catch(\PDOException $e) {
echo 'Caught PDOException ' . $e->getMessage() . PHP_EOL;
}
catch(\ErrorException $e) {
echo 'Caught ErrorException ' . $e->getMessage() . PHP_EOL;
}
// Restore Sentry as the default handler
set_error_handler($previousErrorHandler);
这只会引发并捕获 ErrorException:
Connecting...
Connected. Waiting...
Querying...
Caught ErrorException PDO::query(): MySQL server has gone away
Done.