99use MongoDB \Driver \Monitoring \CommandStartedEvent ;
1010use MongoDB \Driver \Monitoring \CommandSubscriber ;
1111use 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 ;
1222use OpenTelemetry \API \Instrumentation \CachedInstrumentation ;
1323use OpenTelemetry \API \Trace \Span ;
1424use OpenTelemetry \API \Trace \SpanBuilderInterface ;
1828use OpenTelemetry \SemConv \TraceAttributes ;
1929use 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,61 @@ private static function endSpan(?Throwable $exception = null): void
118135
119136 $ span ->end ();
120137 }
138+
139+ /**
140+ * @todo In a load-balanced scenario, the hello response may be empty.
141+ */
142+ public function serverChanged (ServerChangedEvent $ event ): void
143+ {
144+ $ host = $ event ->getHost ();
145+ $ port = $ event ->getPort ();
146+ $ info = $ event ->getNewDescription ()->getHelloResponse ();
147+ $ attributes = [
148+ MongoDBTraceAttributes::DB_MONGODB_MASTER => $ info ['ismaster ' ] ?? null ,
149+ MongoDBTraceAttributes::DB_MONGODB_READ_ONLY => $ info ['readOnly ' ] ?? null ,
150+ MongoDBTraceAttributes::DB_MONGODB_CONNECTION_ID => $ info ['connectionId ' ] ?? null ,
151+ MongoDBTraceAttributes::DB_MONGODB_MAX_WIRE_VERSION => $ info ['maxWireVersion ' ] ?? null ,
152+ MongoDBTraceAttributes::DB_MONGODB_MIN_WIRE_VERSION => $ info ['minWireVersion ' ] ?? null ,
153+ MongoDBTraceAttributes::DB_MONGODB_MAX_BSON_OBJECT_SIZE_BYTES => $ info ['maxBsonObjectSize ' ] ?? null ,
154+ MongoDBTraceAttributes::DB_MONGODB_MAX_MESSAGE_SIZE_BYTES => $ info ['maxMessageSizeBytes ' ] ?? null ,
155+ MongoDBTraceAttributes::DB_MONGODB_MAX_WRITE_BATCH_SIZE => $ info ['maxWriteBatchSize ' ] ?? null ,
156+ ];
157+ $ this ->serverAttributes [$ host ][$ port ] = $ attributes ;
158+ }
159+
160+ public function serverOpened (ServerOpeningEvent $ event ): void
161+ {
162+ }
163+
164+ public function serverClosed (ServerClosedEvent $ event ): void
165+ {
166+ }
167+
168+ public function serverOpening (ServerOpeningEvent $ event ): void
169+ {
170+ }
171+
172+ public function serverHeartbeatFailed (ServerHeartbeatFailedEvent $ event ): void
173+ {
174+ }
175+
176+ public function serverHeartbeatStarted (ServerHeartbeatStartedEvent $ event ): void
177+ {
178+ }
179+
180+ public function serverHeartbeatSucceeded (ServerHeartbeatSucceededEvent $ event ): void
181+ {
182+ }
183+
184+ public function topologyChanged (TopologyChangedEvent $ event ): void
185+ {
186+ }
187+
188+ public function topologyClosed (TopologyClosedEvent $ event ): void
189+ {
190+ }
191+
192+ public function topologyOpening (TopologyOpeningEvent $ event ): void
193+ {
194+ }
121195}
0 commit comments