Skip to content

Commit 06215e1

Browse files
committed
fix: Track attributes for new PDO subclasses
1 parent 56e4005 commit 06215e1

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

src/Instrumentation/PDO/src/PDOInstrumentation.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,41 @@ public static function register(): void
3131
);
3232
$pdoTracker = new PDOTracker();
3333

34+
// Hook for the new PDO::connect static method
35+
if (method_exists(PDO::class, 'connect')) {
36+
hook(
37+
PDO::class,
38+
'connect',
39+
pre: static function (PDO $pdo, array $params, string $class, string $function, ?string $filename, ?int $lineno) use ($instrumentation) {
40+
/** @psalm-suppress ArgumentTypeCoercion */
41+
$builder = self::makeBuilder($instrumentation, 'PDO::connect', $function, $class, $filename, $lineno)
42+
->setSpanKind(SpanKind::KIND_CLIENT);
43+
if ($class === PDO::class) {
44+
$builder
45+
->setAttribute(TraceAttributes::SERVER_ADDRESS, $params[0] ?? 'unknown')
46+
->setAttribute(TraceAttributes::SERVER_PORT, $params[0] ?? null);
47+
}
48+
$parent = Context::getCurrent();
49+
$span = $builder->startSpan();
50+
Context::storage()->attach($span->storeInContext($parent));
51+
},
52+
post: static function (PDO $pdo, array $params, mixed $statement, ?Throwable $exception) use ($pdoTracker) {
53+
$scope = Context::storage()->scope();
54+
if (!$scope) {
55+
return;
56+
}
57+
$span = Span::fromContext($scope->context());
58+
59+
$dsn = $params[0] ?? '';
60+
61+
$attributes = $pdoTracker->trackPdoAttributes($pdo, $dsn);
62+
$span->setAttributes($attributes);
63+
64+
self::end($exception);
65+
}
66+
);
67+
}
68+
3469
hook(
3570
PDO::class,
3671
'__construct',

src/Instrumentation/PDO/tests/Integration/PDOInstrumentationTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ private function createDB(): PDO
2626
return new PDO('sqlite::memory:');
2727
}
2828

29+
private function createDBWithNewSubclass(): PDO\Sqlite
30+
{
31+
if (!class_exists('Pdo\Sqlite')) {
32+
$this->markTestSkipped('Pdo\Sqlite class is not available in this PHP version');
33+
}
34+
return PDO::connect('sqlite::memory:');
35+
}
36+
2937
private function fillDB():string
3038
{
3139
return <<<SQL
@@ -72,6 +80,34 @@ public function test_pdo_construct(): void
7280
$this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM_NAME));
7381
}
7482

83+
public function test_pdo_sqlite_subclass(): void
84+
{
85+
$this->assertCount(0, $this->storage);
86+
$db = self::createDBWithNewSubclass();
87+
$this->assertCount(1, $this->storage);
88+
$span = $this->storage->offsetGet(0);
89+
$this->assertSame('PDO::connect', $span->getName());
90+
$this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM_NAME));
91+
92+
// Test that the subclass-specific methods work
93+
$db->createFunction('test_function', static fn ($value) => strtoupper($value));
94+
95+
// Test that standard PDO operations still work
96+
$db->exec($this->fillDB());
97+
$span = $this->storage->offsetGet(1);
98+
$this->assertSame('PDO::exec', $span->getName());
99+
$this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM_NAME));
100+
$this->assertCount(2, $this->storage);
101+
102+
// Test that the custom function works
103+
$result = $db->query("SELECT test_function('hello')")->fetchColumn();
104+
$this->assertEquals('HELLO', $result);
105+
$span = $this->storage->offsetGet(2);
106+
$this->assertSame('PDO::query', $span->getName());
107+
$this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM_NAME));
108+
$this->assertCount(3, $this->storage);
109+
}
110+
75111
public function test_constructor_exception(): void
76112
{
77113
$this->expectException(\PDOException::class);

0 commit comments

Comments
 (0)