diff --git a/src/Aws/src/AwsSdkInstrumentation.php b/src/Aws/src/AwsSdkInstrumentation.php index c1d797ea7..0044b086d 100644 --- a/src/Aws/src/AwsSdkInstrumentation.php +++ b/src/Aws/src/AwsSdkInstrumentation.php @@ -8,7 +8,6 @@ use Aws\Middleware; use Aws\ResultInterface; use Closure; -use Error; use GuzzleHttp\Promise; use OpenTelemetry\API\Instrumentation\InstrumentationInterface; use OpenTelemetry\API\Instrumentation\InstrumentationTrait; @@ -18,6 +17,7 @@ use OpenTelemetry\API\Trace\TracerProviderInterface; use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; use Psr\Http\Message\RequestInterface; +use Stringable; use Throwable; /** @@ -197,10 +197,10 @@ private function normalizeReason(mixed $reason): ?string return $reason->getMessage(); } - try { - return strval($reason); - } catch (Error) { + if (is_object($reason) && ! $reason instanceof Stringable) { return null; } + + return (string) $reason; } } diff --git a/src/Aws/tests/Integration/AwsSdkInstrumentationTest.php b/src/Aws/tests/Integration/AwsSdkInstrumentationTest.php index f31280b08..a8deca822 100644 --- a/src/Aws/tests/Integration/AwsSdkInstrumentationTest.php +++ b/src/Aws/tests/Integration/AwsSdkInstrumentationTest.php @@ -6,13 +6,18 @@ use Aws\AwsClientInterface; use Aws\EventBridge\EventBridgeClient; +use Aws\Kms\Exception\KmsException; +use Aws\Kms\KmsClient; use Aws\S3\S3Client; use Aws\Sqs\SqsClient; +use GuzzleHttp\Promise; +use OpenTelemetry\API\Trace\StatusCode; use OpenTelemetry\Aws\AwsSdkInstrumentation; use OpenTelemetry\Aws\Xray\Propagator; use OpenTelemetry\SDK\Trace\ReadWriteSpanInterface; use OpenTelemetry\SDK\Trace\TracerProvider; use PHPUnit\Framework\TestCase; +use stdClass; class AwsSdkInstrumentationTest extends TestCase { @@ -213,4 +218,97 @@ public function testPreventsRepeatedInstrumentationOfSameClient() ); } } + + public function testFailedOperationRecordsSpan() + { + /** @var KmsClient $kmsClient */ + $kmsClient = $this->getTestClient('KMS', ['region' => 'eu-west-1']); + + $spanProcessor = new CollectingSpanProcessor(); + $this->awsSdkInstrumentation->setTracerProvider(new TracerProvider([$spanProcessor])); + $this->awsSdkInstrumentation->setPropagator(new Propagator()); + $this->awsSdkInstrumentation->instrumentClients([$kmsClient]); + $this->awsSdkInstrumentation->init(); + $this->awsSdkInstrumentation->activate(); + + try { + $kmsClient->decrypt(['CiphertextBlob' => random_bytes(16)]); + } catch (KmsException) { + } + + $collectedSpans = $spanProcessor->getCollectedSpans(); + $this->assertCount(1, $collectedSpans); + + $span = array_shift($collectedSpans); + + /** @var ReadWriteSpanInterface $span */ + $this->assertTrue($span->hasEnded()); + $this->assertSame(StatusCode::STATUS_ERROR, $span->toSpanData()->getStatus()->getCode()); + } + + public function testRejectsSafelyWithNonStringableObject() + { + /** @var KmsClient $kmsClient */ + $kmsClient = $this->getTestClient('KMS', ['region' => 'eu-west-1']); + + $spanProcessor = new CollectingSpanProcessor(); + $this->awsSdkInstrumentation->setTracerProvider(new TracerProvider([$spanProcessor])); + $this->awsSdkInstrumentation->setPropagator(new Propagator()); + $this->awsSdkInstrumentation->instrumentClients([$kmsClient]); + $this->awsSdkInstrumentation->init(); + $this->awsSdkInstrumentation->activate(); + + $kmsClient->getHandlerList()->appendSign(function () { + return function () { + return Promise\Create::rejectionFor(new stdClass()); + }; + }); + + try { + $kmsClient->decrypt(['CiphertextBlob' => random_bytes(16)]); + } catch (Promise\RejectionException) { + } + + $collectedSpans = $spanProcessor->getCollectedSpans(); + $this->assertCount(1, $collectedSpans); + + $span = array_shift($collectedSpans); + + /** @var ReadWriteSpanInterface $span */ + $this->assertTrue($span->hasEnded()); + $this->assertSame(StatusCode::STATUS_ERROR, $span->toSpanData()->getStatus()->getCode()); + } + + public function testRejectsSafelyWithString() + { + /** @var KmsClient $kmsClient */ + $kmsClient = $this->getTestClient('KMS', ['region' => 'eu-west-1']); + + $spanProcessor = new CollectingSpanProcessor(); + $this->awsSdkInstrumentation->setTracerProvider(new TracerProvider([$spanProcessor])); + $this->awsSdkInstrumentation->setPropagator(new Propagator()); + $this->awsSdkInstrumentation->instrumentClients([$kmsClient]); + $this->awsSdkInstrumentation->init(); + $this->awsSdkInstrumentation->activate(); + + $kmsClient->getHandlerList()->appendSign(function () { + return function () { + return Promise\Create::rejectionFor('failed'); + }; + }); + + try { + $kmsClient->decrypt(['CiphertextBlob' => random_bytes(16)]); + } catch (Promise\RejectionException) { + } + + $collectedSpans = $spanProcessor->getCollectedSpans(); + $this->assertCount(1, $collectedSpans); + + $span = array_shift($collectedSpans); + + /** @var ReadWriteSpanInterface $span */ + $this->assertTrue($span->hasEnded()); + $this->assertSame(StatusCode::STATUS_ERROR, $span->toSpanData()->getStatus()->getCode()); + } }