Skip to content

Commit f8f5af3

Browse files
committed
mongodb 2.0 support
Being able to retrieve host, port + info from a CommandStartedEvent is deprecated in 1.20.0 and will be removed in 2.0. we have been advised to use SDAM subscription instead. - update tests to allow defining mongo server from env - require ext-mongodb 1.13 (which provides SDAM subscriber for server info) - use SDAM subscriber to get server info attributes. Subscribe to the serverChanged event and store the attributes in a class variable, organised by host/port.
1 parent 4e6037a commit f8f5af3

File tree

5 files changed

+109
-21
lines changed

5 files changed

+109
-21
lines changed

docker-compose.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ services:
1414
PHP_IDE_CONFIG: ${PHP_IDE_CONFIG:-''}
1515
RABBIT_HOST: ${RABBIT_HOST:-rabbitmq}
1616
KAFKA_HOST: ${KAFKA_HOST:-kafka}
17+
MONGODB_HOST: ${MONGODB_HOST:-mongodb}
18+
MONGODB_PORT: ${MONGODB_PORT:-27017}
1719

1820
zipkin:
1921
image: openzipkin/zipkin-slim
@@ -60,5 +62,9 @@ services:
6062
command: "bash -c '/tmp/update_run.sh && /etc/confluent/docker/run'"
6163
volumes:
6264
- ./docker/kafka/update_run.sh:/tmp/update_run.sh
63-
65+
mongodb:
66+
image: mongo:4
67+
hostname: mongodb
68+
ports:
69+
- "27017:27017/tcp"
6470

src/Instrumentation/MongoDB/composer.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@
66
"homepage": "https://opentelemetry.io/docs/php",
77
"readme": "./README.md",
88
"license": "Apache-2.0",
9-
"minimum-stability": "dev",
109
"require": {
1110
"php": ">=7.4",
12-
"ext-mongodb": "*",
11+
"ext-mongodb": "^1.13",
1312
"ext-json": "*",
1413
"mongodb/mongodb": "^1.15",
1514
"open-telemetry/api": "^1.0",
@@ -40,7 +39,8 @@
4039
},
4140
"config": {
4241
"allow-plugins": {
43-
"php-http/discovery": false
42+
"php-http/discovery": false,
43+
"tbachert/spi": false
4444
}
4545
}
4646
}

src/Instrumentation/MongoDB/phpstan.neon.dist

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,8 @@ parameters:
77
paths:
88
- src
99
- tests
10+
ignoreErrors:
11+
-
12+
message: "#Call to an undefined method .*#"
13+
paths:
14+
- src/MongoDBInstrumentationSubscriber.php

src/Instrumentation/MongoDB/src/MongoDBInstrumentationSubscriber.php

Lines changed: 85 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@
99
use MongoDB\Driver\Monitoring\CommandStartedEvent;
1010
use MongoDB\Driver\Monitoring\CommandSubscriber;
1111
use MongoDB\Driver\Monitoring\CommandSucceededEvent;
12+
use MongoDB\Driver\Monitoring\SDAMSubscriber;
13+
use MongoDB\Driver\Monitoring\ServerChangedEvent;
14+
use MongoDB\Driver\Monitoring\ServerClosedEvent;
15+
use MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent;
16+
use MongoDB\Driver\Monitoring\ServerHeartbeatStartedEvent;
17+
use MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent;
18+
use MongoDB\Driver\Monitoring\ServerOpeningEvent;
19+
use MongoDB\Driver\Monitoring\TopologyChangedEvent;
20+
use MongoDB\Driver\Monitoring\TopologyClosedEvent;
21+
use MongoDB\Driver\Monitoring\TopologyOpeningEvent;
1222
use OpenTelemetry\API\Instrumentation\CachedInstrumentation;
1323
use OpenTelemetry\API\Trace\Span;
1424
use OpenTelemetry\API\Trace\SpanBuilderInterface;
@@ -18,13 +28,17 @@
1828
use OpenTelemetry\SemConv\TraceAttributes;
1929
use Throwable;
2030

21-
final class MongoDBInstrumentationSubscriber implements CommandSubscriber
31+
final class MongoDBInstrumentationSubscriber implements CommandSubscriber, SDAMSubscriber
2232
{
2333
private CachedInstrumentation $instrumentation;
2434
/**
2535
* @var Closure(object):?string
2636
*/
2737
private Closure $commandSerializer;
38+
/**
39+
* @var array<string, array<int, array<string, mixed>>>
40+
*/
41+
private array $serverAttributes = [];
2842

2943
/**
3044
* @param (callable(object):?string) $commandSerializer
@@ -41,16 +55,26 @@ public function __construct(CachedInstrumentation $instrumentation, callable $co
4155
};
4256
}
4357

58+
/**
59+
* @psalm-suppress MixedAssignment,MixedArrayTypeCoercion,MixedArrayOffset,MixedArgument
60+
*/
4461
public function commandStarted(CommandStartedEvent $event): void
4562
{
4663
$command = $event->getCommand();
4764
$collectionName = MongoDBCollectionExtractor::extract($command);
4865
$databaseName = $event->getDatabaseName();
4966
$commandName = $event->getCommandName();
50-
$server = $event->getServer();
51-
$info = $server->getInfo();
52-
$port = $server->getPort();
53-
$host = $server->getHost();
67+
/** @phpstan-ignore-next-line */
68+
if (version_compare(phpversion('mongodb'), '1.20.0', '>=')) {
69+
$host = $event->getHost();
70+
$port = $event->getPort();
71+
} else {
72+
$server = $event->getServer();
73+
$host = $server->getHost();
74+
$port = $server->getPort();
75+
}
76+
$attributes = $this->serverAttributes[$host][$port] ?? [];
77+
5478
$isSocket = str_starts_with($host, '/');
5579
/** @psalm-suppress RiskyTruthyFalsyComparison **/
5680
$scopedCommand = ($collectionName ? $collectionName . '.' : '') . $commandName;
@@ -65,17 +89,10 @@ public function commandStarted(CommandStartedEvent $event): void
6589
->setAttribute(TraceAttributes::NETWORK_TRANSPORT, $isSocket ? 'unix' : 'tcp')
6690
->setAttribute(TraceAttributes::DB_STATEMENT, ($this->commandSerializer)($command))
6791
->setAttribute(TraceAttributes::DB_MONGODB_COLLECTION, $collectionName)
68-
->setAttribute(MongoDBTraceAttributes::DB_MONGODB_MASTER, $info['ismaster'] ?? null)
69-
->setAttribute(MongoDBTraceAttributes::DB_MONGODB_READ_ONLY, $info['readOnly'] ?? null)
70-
->setAttribute(MongoDBTraceAttributes::DB_MONGODB_CONNECTION_ID, $info['connectionId'] ?? null)
7192
->setAttribute(MongoDBTraceAttributes::DB_MONGODB_REQUEST_ID, $event->getRequestId())
7293
->setAttribute(MongoDBTraceAttributes::DB_MONGODB_OPERATION_ID, $event->getOperationId())
73-
->setAttribute(MongoDBTraceAttributes::DB_MONGODB_MAX_WIRE_VERSION, $info['maxWireVersion'] ?? null)
74-
->setAttribute(MongoDBTraceAttributes::DB_MONGODB_MIN_WIRE_VERSION, $info['minWireVersion'] ?? null)
75-
->setAttribute(MongoDBTraceAttributes::DB_MONGODB_MAX_BSON_OBJECT_SIZE_BYTES, $info['maxBsonObjectSize'] ?? null)
76-
->setAttribute(MongoDBTraceAttributes::DB_MONGODB_MAX_MESSAGE_SIZE_BYTES, $info['maxMessageSizeBytes'] ?? null)
77-
->setAttribute(MongoDBTraceAttributes::DB_MONGODB_MAX_WRITE_BATCH_SIZE, $info['maxWriteBatchSize'] ?? null);
78-
94+
->setAttributes($attributes)
95+
;
7996
$parent = Context::getCurrent();
8097
$span = $builder->startSpan();
8198
Context::storage()->attach($span->storeInContext($parent));
@@ -118,4 +135,58 @@ private static function endSpan(?Throwable $exception = null): void
118135

119136
$span->end();
120137
}
138+
139+
public function serverChanged(ServerChangedEvent $event): void
140+
{
141+
$host = $event->getHost();
142+
$port = $event->getPort();
143+
$info = $event->getNewDescription()->getHelloResponse();
144+
$attributes = [
145+
MongoDBTraceAttributes::DB_MONGODB_MASTER => $info['ismaster'] ?? null,
146+
MongoDBTraceAttributes::DB_MONGODB_READ_ONLY => $info['readOnly'] ?? null,
147+
MongoDBTraceAttributes::DB_MONGODB_CONNECTION_ID => $info['connectionId'] ?? null,
148+
MongoDBTraceAttributes::DB_MONGODB_MAX_WIRE_VERSION => $info['maxWireVersion'] ?? null,
149+
MongoDBTraceAttributes::DB_MONGODB_MIN_WIRE_VERSION => $info['minWireVersion'] ?? null,
150+
MongoDBTraceAttributes::DB_MONGODB_MAX_BSON_OBJECT_SIZE_BYTES => $info['maxBsonObjectSize'] ?? null,
151+
MongoDBTraceAttributes::DB_MONGODB_MAX_MESSAGE_SIZE_BYTES => $info['maxMessageSizeBytes'] ?? null,
152+
MongoDBTraceAttributes::DB_MONGODB_MAX_WRITE_BATCH_SIZE => $info['maxWriteBatchSize'] ?? null,
153+
];
154+
$this->serverAttributes[$host][$port] = $attributes;
155+
}
156+
157+
public function serverOpened(ServerOpeningEvent $event): void
158+
{
159+
}
160+
161+
public function serverClosed(ServerClosedEvent $event): void
162+
{
163+
}
164+
165+
public function serverOpening(ServerOpeningEvent $event): void
166+
{
167+
}
168+
169+
public function serverHeartbeatFailed(ServerHeartbeatFailedEvent $event): void
170+
{
171+
}
172+
173+
public function serverHeartbeatStarted(ServerHeartbeatStartedEvent $event): void
174+
{
175+
}
176+
177+
public function serverHeartbeatSucceeded(ServerHeartbeatSucceededEvent $event): void
178+
{
179+
}
180+
181+
public function topologyChanged(TopologyChangedEvent $event): void
182+
{
183+
}
184+
185+
public function topologyClosed(TopologyClosedEvent $event): void
186+
{
187+
}
188+
189+
public function topologyOpening(TopologyOpeningEvent $event): void
190+
{
191+
}
121192
}

src/Instrumentation/MongoDB/tests/Integration/MongoDBInstrumentationTest.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,19 @@ class MongoDBInstrumentationTest extends TestCase
2222
{
2323
private const DATABASE_NAME = 'db';
2424
private const COLLECTION_NAME = 'coll';
25+
private string $host;
26+
private int $port;
27+
private string $uri;
2528
private ScopeInterface $scope;
2629
/** @var ArrayObject<int,ImmutableSpan> */
2730
private ArrayObject $storage;
2831
private ?ImmutableSpan $span = null;
2932

3033
public function setUp(): void
3134
{
35+
$this->host = $_SERVER['MONGODB_HOST'] ?? '127.0.0.1';
36+
$this->port = (int) ($_SERVER['MONGODB_PORT'] ?? 27017);
37+
$this->uri = "mongodb://$this->host:$this->port";
3238
/** @psalm-suppress MixedPropertyTypeCoercion */
3339
$this->storage = new ArrayObject();
3440
$tracerProvider = new TracerProvider(
@@ -49,7 +55,7 @@ public function tearDown(): void
4955

5056
public function test_mongodb_find_one(): void
5157
{
52-
$manager = new Manager('mongodb://127.0.0.1:27017');
58+
$manager = new Manager($this->uri);
5359

5460
$find = new FindOne(self::DATABASE_NAME, self::COLLECTION_NAME, ['a' => 'b']);
5561

@@ -67,8 +73,8 @@ public function test_mongodb_find_one(): void
6773
self::assertSame(self::DATABASE_NAME, $attributes->get(TraceAttributes::DB_NAME));
6874
self::assertSame('find', $attributes->get(TraceAttributes::DB_OPERATION));
6975
self::assertSame(self::COLLECTION_NAME, $attributes->get(TraceAttributes::DB_MONGODB_COLLECTION));
70-
self::assertSame('127.0.0.1', $attributes->get(TraceAttributes::SERVER_ADDRESS));
71-
self::assertSame(27017, $attributes->get(TraceAttributes::SERVER_PORT));
76+
self::assertSame($this->host, $attributes->get(TraceAttributes::SERVER_ADDRESS));
77+
self::assertSame($this->port, $attributes->get(TraceAttributes::SERVER_PORT));
7278
self::assertSame('tcp', $attributes->get(TraceAttributes::NETWORK_TRANSPORT));
7379
self::assertTrue($attributes->get(MongoDBTraceAttributes::DB_MONGODB_MASTER));
7480
self::assertFalse($attributes->get(MongoDBTraceAttributes::DB_MONGODB_READ_ONLY));

0 commit comments

Comments
 (0)