diff --git a/src/sentry/publish/sentry.php b/src/sentry/publish/sentry.php index a6069a138..e97ece50b 100644 --- a/src/sentry/publish/sentry.php +++ b/src/sentry/publish/sentry.php @@ -63,6 +63,7 @@ 'cache' => env('SENTRY_BREADCRUMBS_CACHE', true), 'command' => env('SENTRY_BREADCRUMBS_COMMAND', true), 'command_input' => env('SENTRY_BREADCRUMBS_COMMAND_INPUT', true), + 'filesystem' => env('SENTRY_BREADCRUMBS_FILESYSTEM', true), 'sql_queries' => env('SENTRY_BREADCRUMBS_SQL_QUERIES', true), 'sql_bindings' => env('SENTRY_BREADCRUMBS_SQL_BINDINGS', true), 'sql_transaction' => env('SENTRY_BREADCRUMBS_SQL_TRANSACTION', true), @@ -106,6 +107,7 @@ 'coroutine' => env('SENTRY_TRACING_SPANS_COROUTINE', true), 'db' => env('SENTRY_TRACING_SPANS_DB', true), 'elasticsearch' => env('SENTRY_TRACING_SPANS_ELASTICSEARCH', true), + 'filesystem' => env('SENTRY_TRACING_SPANS_FILESYSTEM', true), 'guzzle' => env('SENTRY_TRACING_SPANS_GUZZLE', true), 'rpc' => env('SENTRY_TRACING_SPANS_RPC', true), 'grpc' => env('SENTRY_TRACING_SPANS_GRPC', true), diff --git a/src/sentry/src/Aspect/FilesystemAspect.php b/src/sentry/src/Aspect/FilesystemAspect.php new file mode 100644 index 000000000..63a4737c9 --- /dev/null +++ b/src/sentry/src/Aspect/FilesystemAspect.php @@ -0,0 +1,133 @@ +switcher->isBreadcrumbEnabled('filesystem')) { + return $proceedingJoinPoint->process(); + } + + [$op, $description, $data] = $this->getSentryMetadata($proceedingJoinPoint); + + Integration::addBreadcrumb(new Breadcrumb( + Breadcrumb::LEVEL_INFO, + Breadcrumb::TYPE_DEFAULT, + $op, + $description, + $data + )); + + return $proceedingJoinPoint->process(); + } + + /** + * @return array{0: string, 1: string, 2: array} [op, description, data] + */ + protected function getSentryMetadata(ProceedingJoinPoint $proceedingJoinPoint): array + { + $method = $proceedingJoinPoint->methodName; + $arguments = $proceedingJoinPoint->arguments['keys'] ?? []; + // See https://develop.sentry.dev/sdk/performance/span-operations/#web-server + $op = "file.{$method}"; + $description = match ($method) { + 'move', 'copy' => sprintf( + 'from "%s" to "%s"', + $arguments['source'] ?? '', + $arguments['destination'] ?? '' + ), + 'write', 'writeStream', + 'read', 'readStream', + 'setVisibility', 'visibility', + 'delete', 'deleteDirectory', 'createDirectory', + 'fileExists', 'directoryExists', + 'listContents', + 'lastModified', + 'fileSize', + 'mimeType', => $arguments['path'] ?? '', + default => '', + }; + + $config = null; + + if (isset($arguments['config'])) { + if (is_object($arguments['config']) && method_exists($arguments['config'], 'toArray')) { + $config = $arguments['config']->toArray(); + } else { + $config = $arguments['config']; + } + } + + $data = match ($method) { + 'move', 'copy' => [ + 'from' => $arguments['source'] ?? '', + 'to' => $arguments['destination'] ?? '', + 'config' => $config, + ], + 'write', 'writeStream', 'createDirectory' => [ + 'path' => $arguments['path'] ?? '', + 'config' => $config, + ], + 'setVisibility' => [ + 'path' => $arguments['path'] ?? '', + 'visibility' => $arguments['visibility'] ?? '', + ], + 'listContents' => [ + 'path' => $arguments['path'] ?? '', + 'deep' => $arguments['deep'] ?? false, + ], + 'read', 'readStream', + 'visibility', 'delete', 'deleteDirectory', + 'fileExists', 'directoryExists', + 'lastModified', 'fileSize', 'mimeType' => [ + 'path' => $arguments['path'] ?? '', + ], + default => [], + }; + + return [$op, $description, $data]; + } +} diff --git a/src/sentry/src/ConfigProvider.php b/src/sentry/src/ConfigProvider.php index 6ca66ca3b..0f9cbd1cd 100644 --- a/src/sentry/src/ConfigProvider.php +++ b/src/sentry/src/ConfigProvider.php @@ -22,6 +22,7 @@ public function __invoke(): array Aspect\BreadcrumbAspect::class, Aspect\CacheAspect::class, Aspect\CoroutineAspect::class, + Aspect\FilesystemAspect::class, Aspect\GuzzleHttpClientAspect::class, Aspect\LoggerAspect::class, Aspect\RedisAspect::class, @@ -33,6 +34,7 @@ public function __invoke(): array Tracing\Aspect\CoroutineAspect::class, Tracing\Aspect\DbAspect::class, Tracing\Aspect\ElasticsearchAspect::class, + Tracing\Aspect\FilesystemAspect::class, Tracing\Aspect\GrpcAspect::class, Tracing\Aspect\GuzzleHttpClientAspect::class, Tracing\Aspect\KafkaProducerAspect::class, diff --git a/src/sentry/src/Tracing/Aspect/FilesystemAspect.php b/src/sentry/src/Tracing/Aspect/FilesystemAspect.php new file mode 100644 index 000000000..319c8c943 --- /dev/null +++ b/src/sentry/src/Tracing/Aspect/FilesystemAspect.php @@ -0,0 +1,41 @@ +switcher->isTracingEnabled('filesystem')) { + return $proceedingJoinPoint->process(); + } + + [$op, $description, $data] = $this->getSentryMetadata($proceedingJoinPoint); + + return trace( + fn () => $proceedingJoinPoint->process(), + SpanContext::make() + ->setOp($op) + ->setData($data) + ->setOrigin('auto.filesystem') + ->setDescription($description) + ); + } +}