Repository: getsentry/sentry-php (php)

Issue:
Sentry trace Serializer issue
sentry/sentry  sdk 2.4.1

Hi guys,

We create a magento sentry integration. It works well, except in this scenario. 

It requires Magento 2 knowledge

In sentry I see issue with such a name
```Cannot declare class Vendor\Customer\Plugin\Api\CustomerRepositoryPlugin, because the name is already in use```

Inside issue in the message there is a actual exception message. No real Exception trace, just trace about class redeclare.

```
 in include called at /var/www/magento/releases/20201001162424/vendor/composer/ClassLoader.php (444)
 in Composer\Autoload\includeFile called at /var/www/magento/releases/20201001162424/vendor/composer/ClassLoader.php (322)
 in Composer\Autoload\ClassLoader::loadClass called at ? (?)
 in spl_autoload_call called at ? (?)
 in is_callable called at /var/www/magento/releases/20201001162424/vendor/sentry/sentry/src/Serializer/AbstractSerializer.php (102)
 in Sentry\Serializer\AbstractSerializer::serializeRecursively called at /var/www/magento/releases/20201001162424/vendor/sentry/sentry/src/Serializer/AbstractSerializer.php (110)
 in Sentry\Serializer\AbstractSerializer::serializeRecursively called at /var/www/magento/releases/20201001162424/vendor/sentry/sentry/src/Serializer/RepresentationSerializer.php (21)
 in Sentry\Serializer\RepresentationSerializer::representationSerialize called at /var/www/magento/releases/20201001162424/vendor/sentry/sentry/src/Stacktrace.php (177)
 in Sentry\Stacktrace::addFrame called at /var/www/magento/releases/20201001162424/vendor/sentry/sentry/src/Stacktrace.php (102)
 in Sentry\Stacktrace::createFromBacktrace called at /var/www/magento/releases/20201001162424/vendor/sentry/sentry/src/EventFactory.php (149)
 in Sentry\EventFactory::addThrowableToEvent called at /var/www/magento/releases/20201001162424/vendor/sentry/sentry/src/EventFactory.php (110)
 in Sentry\EventFactory::create called at /var/www/magento/releases/20201001162424/vendor/sentry/sentry/src/Client.php (183)
 in Sentry\Client::prepareEvent called at /var/www/magento/releases/20201001162424/vendor/sentry/sentry/src/Client.php (118)
 in Sentry\Client::captureEvent called at /var/www/magento/releases/20201001162424/vendor/sentry/sentry/src/Client.php (110)
 in Sentry\Client::captureException called at /var/www/magento/releases/20201001162424/vendor/sentry/sentry/src/State/Hub.php (132)
 in Sentry\State\Hub::captureException called at /var/www/magento/releases/20201001162424/vendor/mygento/module-sentry/Model/SentryHandler.php (285)
 in Mygento\Sentry\Model\SentryHandler::Mygento\Sentry\Model\{closure} called at /var/www/magento/releases/20201001162424/vendor/sentry/sentry/src/State/Hub.php (87)
 in Sentry\State\Hub::withScope called at /var/www/magento/releases/20201001162424/vendor/mygento/module-sentry/Model/SentryHandler.php (289)
 in Mygento\Sentry\Model\SentryHandler::write called at /var/www/magento/releases/20201001162424/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php (39)
 in Monolog\Handler\AbstractProcessingHandler::handle called at /var/www/magento/releases/20201001162424/vendor/monolog/monolog/src/Monolog/Logger.php (344)

```

AbstractSerializer.php somehow recreates plugin class

Pull request description:
Handle autoloaders that throws while serializing a possible callable
Fixes #1112

While trying to fix that ticket, I got an improvement in the serialization of a broken class, a PHPT test already present in our test suite.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8148b82..d0df850 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
 ## Unreleased
 
 - Optimize `Span` constructor and add benchmarks (#1274)
+- Handle autoloader that throws an exception while trying to serialize a possible callable (#1276)
 
 ## 3.3.5 (2021-12-27)
 
diff --git a/src/Serializer/AbstractSerializer.php b/src/Serializer/AbstractSerializer.php
index d744bdb..2e7ffae 100644
--- a/src/Serializer/AbstractSerializer.php
+++ b/src/Serializer/AbstractSerializer.php
@@ -99,8 +99,12 @@ protected function serializeRecursively($value, int $_depth = 0)
                 return $this->serializeValue($value);
             }
 
-            if (\is_callable($value)) {
-                return $this->serializeCallable($value);
+            try {
+                if (\is_callable($value)) {
+                    return $this->serializeCallable($value);
+                }
+            } catch (\Throwable $exception) {
+                // Do nothing on purpose
             }
 
             if (\is_array($value)) {


Test patch:
diff --git a/tests/phpt/serialize_broken_class.phpt b/tests/phpt/serialize_broken_class.phpt
index 775aa72..5511595 100644
--- a/tests/phpt/serialize_broken_class.phpt
+++ b/tests/phpt/serialize_broken_class.phpt
@@ -25,7 +25,7 @@ require $vendor . '/vendor/autoload.php';
 function testSerialization($value) {
     $serializer = new Serializer(new Options());
 
-    echo $serializer->serialize($value);
+    echo json_encode($serializer->serialize($value));
 }
 
 testSerialization(BrokenClass::class . '::brokenMethod');
@@ -34,5 +34,5 @@ testSerialization([BrokenClass::class, 'brokenMethod']);
 
 ?>
 --EXPECT--
-Sentry\Tests\Fixtures\code\BrokenClass::brokenMethod {serialization error}
-{serialization error}
+"Sentry\\Tests\\Fixtures\\code\\BrokenClass::brokenMethod {serialization error}"
+["Sentry\\Tests\\Fixtures\\code\\BrokenClass","brokenMethod"]
diff --git a/tests/phpt/serialize_callable_that_makes_autoloader_throw.phpt b/tests/phpt/serialize_callable_that_makes_autoloader_throw.phpt
new file mode 100644
index 0000000..dc1bd62
--- /dev/null
+++ b/tests/phpt/serialize_callable_that_makes_autoloader_throw.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Test that serializing a pseudo-callable that doesn't exist (like an array of 2 strings) doesn't brake
+when inside an application with an autoloader that throws, like Yii or Magento (see #1112)
+--FILE--
+<?php
+
+declare(strict_types=1);
+
+namespace Sentry\Tests;
+
+use Sentry\Options;
+use Sentry\Serializer\Serializer;
+use Sentry\Tests\Fixtures\code\BrokenClass;
+
+$vendor = __DIR__;
+
+while (!file_exists($vendor . '/vendor')) {
+    $vendor = dirname($vendor);
+}
+
+require $vendor . '/vendor/autoload.php';
+
+function testSerialization() {
+    $serializer = new Serializer(new Options());
+
+    echo json_encode($serializer->serialize(['FakeClass', 'fakeMethod']));
+}
+
+testSerialization();
+echo PHP_EOL;
+$brokenAutoloader = function (string $classname): void {
+    throw new \RuntimeException('Autoloader throws while loading ' . $classname);
+};
+
+spl_autoload_register($brokenAutoloader, true, true);
+
+try {
+    testSerialization();
+} finally {
+    spl_autoload_unregister($brokenAutoloader);
+}
+?>
+--EXPECT--
+["FakeClass","fakeMethod"]
+["FakeClass","fakeMethod"]