diff --git a/src/Hooks/Illuminate/Database/Eloquent/Model.php b/src/Hooks/Illuminate/Database/Eloquent/Model.php index 610cdb8..64151b4 100644 --- a/src/Hooks/Illuminate/Database/Eloquent/Model.php +++ b/src/Hooks/Illuminate/Database/Eloquent/Model.php @@ -189,7 +189,11 @@ private function hookDestroy(): void hook( EloquentModel::class, 'destroy', - pre: function ($model, array $params, string $class, string $function, ?string $filename, ?int $lineno) { + pre: function (string $modelClassName, array $params, string $class, string $function, ?string $filename, ?int $lineno) { + // The class-string is passed to the $model argument, because \Illuminate\Database\Eloquent\Model::destroy is static method. + // Therefore, create a class instance from a class-string, and then get the table name from the getTable function. + $model = new $modelClassName(); + $builder = $this->instrumentation ->tracer() ->spanBuilder($model::class . '::destroy') diff --git a/tests/Integration/LaravelInstrumentationTest.php b/tests/Integration/LaravelInstrumentationTest.php index f3928c1..0b1b59f 100644 --- a/tests/Integration/LaravelInstrumentationTest.php +++ b/tests/Integration/LaravelInstrumentationTest.php @@ -102,16 +102,16 @@ public function test_eloquent_operations(): void try { // Test create $created = TestModel::create(['name' => 'test']); - + // Test find $found = TestModel::find($created->id); - + // Test update $found->update(['name' => 'updated']); - + // Test delete $found->delete(); - + return response()->json(['status' => 'ok']); } catch (\Exception $e) { return response()->json([ @@ -127,18 +127,7 @@ public function test_eloquent_operations(): void } $this->assertEquals(200, $response->status()); - // Verify spans for each Eloquent operation - /** @var array $spans */ - $spans = array_values(array_filter( - iterator_to_array($this->storage), - fn ($item) => $item instanceof \OpenTelemetry\SDK\Trace\ImmutableSpan - )); - - // Filter out SQL spans and keep only Eloquent spans - $eloquentSpans = array_values(array_filter( - $spans, - fn ($span) => str_contains($span->getName(), '::') - )); + $eloquentSpans = $this->resolveEloquentOperationSpans(); // Sort spans by operation type to ensure consistent order usort($eloquentSpans, function ($a, $b) { @@ -186,6 +175,58 @@ public function test_eloquent_operations(): void $this->assertSame('delete', $deleteSpan->getAttributes()->get('laravel.eloquent.operation')); } + public function test_eloquent_static_operations(): void + { + // Assert storage is empty before interacting with the database + $this->assertCount(0, $this->storage); + + // Create the test_models table + DB::statement('CREATE TABLE IF NOT EXISTS test_models ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT, + created_at DATETIME, + updated_at DATETIME + )'); + + $this->router()->get('/eloquent', function () { + try { + // create record for Test destroy + $created = TestModel::create(['name' => 'test']); + + // Test destroy + TestModel::destroy([$created->id]); + + return response()->json(['status' => 'ok']); + } catch (\Exception $e) { + return response()->json([ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + ], 500); + } + }); + + $response = $this->call('GET', '/eloquent'); + if ($response->status() !== 200) { + $this->fail('Request failed: ' . $response->content()); + } + $this->assertEquals(200, $response->status()); + + $eloquentSpans = $this->resolveEloquentOperationSpans(); + + // Destroy span + $destroySpans = array_values(array_filter($eloquentSpans, function ($span) { + return $span->getAttributes()->get('laravel.eloquent.operation') === 'destroy'; + })); + + $this->assertCount(1, $destroySpans); + + $destroySpan = $destroySpans[0]; + $this->assertSame('OpenTelemetry\Tests\Contrib\Instrumentation\Laravel\Fixtures\Models\TestModel::destroy', $destroySpan->getName()); + $this->assertSame('OpenTelemetry\Tests\Contrib\Instrumentation\Laravel\Fixtures\Models\TestModel', $destroySpan->getAttributes()->get('laravel.eloquent.model')); + $this->assertSame('test_models', $destroySpan->getAttributes()->get('laravel.eloquent.table')); + $this->assertSame('destroy', $destroySpan->getAttributes()->get('laravel.eloquent.operation')); + } + public function test_low_cardinality_route_span_name(): void { $this->router()->get('/hello/{name}', fn () => null)->name('hello-name'); @@ -213,4 +254,25 @@ private function router(): Router /** @psalm-suppress PossiblyNullReference */ return $this->app->make(Router::class); } + + /** + * @return array + */ + private function resolveEloquentOperationSpans(): array + { + // Verify spans for each Eloquent operation + /** @var array $spans */ + $spans = array_values(array_filter( + iterator_to_array($this->storage), + fn ($item) => $item instanceof \OpenTelemetry\SDK\Trace\ImmutableSpan + )); + + // Filter out SQL spans and keep only Eloquent spans + $eloquentSpans = array_values(array_filter( + $spans, + fn ($span) => str_contains($span->getName(), '::') + )); + + return $eloquentSpans; + } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy