1
- import { EJSON } from 'bson' ;
1
+ import { type Document , EJSON , type EJSONOptions } from 'bson' ;
2
2
import type { Writable } from 'stream' ;
3
3
import { inspect } from 'util' ;
4
4
@@ -38,7 +38,15 @@ import {
38
38
SERVER_SELECTION_FAILED ,
39
39
SERVER_SELECTION_STARTED ,
40
40
SERVER_SELECTION_SUCCEEDED ,
41
- WAITING_FOR_SUITABLE_SERVER
41
+ WAITING_FOR_SUITABLE_SERVER ,
42
+ SERVER_CLOSED ,
43
+ SERVER_HEARTBEAT_FAILED ,
44
+ SERVER_HEARTBEAT_STARTED ,
45
+ SERVER_HEARTBEAT_SUCCEEDED ,
46
+ SERVER_OPENING ,
47
+ TOPOLOGY_CLOSED ,
48
+ TOPOLOGY_DESCRIPTION_CHANGED ,
49
+ TOPOLOGY_OPENING
42
50
} from './constants' ;
43
51
import type {
44
52
ServerSelectionEvent ,
@@ -47,6 +55,13 @@ import type {
47
55
ServerSelectionSucceededEvent ,
48
56
WaitingForSuitableServerEvent
49
57
} from './sdam/server_selection_events' ;
58
+ import type {
59
+ ServerClosedEvent ,
60
+ ServerOpeningEvent ,
61
+ TopologyClosedEvent ,
62
+ TopologyDescriptionChangedEvent ,
63
+ TopologyOpeningEvent
64
+ } from './sdam/events' ;
50
65
import { HostAddress , parseUnsignedInteger } from './utils' ;
51
66
52
67
/** @internal */
@@ -280,6 +295,54 @@ function compareSeverity(s0: SeverityLevel, s1: SeverityLevel): 1 | 0 | -1 {
280
295
return s0Num < s1Num ? - 1 : s0Num > s1Num ? 1 : 0 ;
281
296
}
282
297
298
+ /**
299
+ * @internal
300
+ * Must be separate from Events API due to differences in spec requirements for logging server heartbeat beginning
301
+ */
302
+ export type LoggableServerHeartbeatStartedEvent = {
303
+ topologyId : number ;
304
+ awaited : boolean ;
305
+ connectionId : string ;
306
+ name : typeof SERVER_HEARTBEAT_STARTED ;
307
+ } ;
308
+
309
+ /**
310
+ * @internal
311
+ * Must be separate from Events API due to differences in spec requirements for logging server heartbeat success
312
+ */
313
+ export type LoggableServerHeartbeatSucceededEvent = {
314
+ topologyId : number ;
315
+ awaited : boolean ;
316
+ connectionId : string ;
317
+ reply : Document ;
318
+ serverConnectionId : number | '<monitor>' ;
319
+ duration : number ;
320
+ name : typeof SERVER_HEARTBEAT_SUCCEEDED ;
321
+ } ;
322
+
323
+ /**
324
+ * @internal
325
+ * Must be separate from Events API due to differences in spec requirements for logging server heartbeat failure
326
+ */
327
+ export type LoggableServerHeartbeatFailedEvent = {
328
+ topologyId : number ;
329
+ awaited : boolean ;
330
+ connectionId : string ;
331
+ failure : Error ;
332
+ duration : number ;
333
+ name : typeof SERVER_HEARTBEAT_FAILED ;
334
+ } ;
335
+
336
+ type SDAMLoggableEvent =
337
+ | ServerClosedEvent
338
+ | LoggableServerHeartbeatFailedEvent
339
+ | LoggableServerHeartbeatStartedEvent
340
+ | LoggableServerHeartbeatSucceededEvent
341
+ | ServerOpeningEvent
342
+ | TopologyClosedEvent
343
+ | TopologyDescriptionChangedEvent
344
+ | TopologyOpeningEvent ;
345
+
283
346
/** @internal */
284
347
export type LoggableEvent =
285
348
| ServerSelectionStartedEvent
@@ -299,16 +362,28 @@ export type LoggableEvent =
299
362
| ConnectionCheckedInEvent
300
363
| ConnectionCheckedOutEvent
301
364
| ConnectionCheckOutStartedEvent
302
- | ConnectionCheckOutFailedEvent ;
365
+ | ConnectionCheckOutFailedEvent
366
+ | ServerClosedEvent
367
+ | LoggableServerHeartbeatFailedEvent
368
+ | LoggableServerHeartbeatStartedEvent
369
+ | LoggableServerHeartbeatSucceededEvent
370
+ | ServerOpeningEvent
371
+ | TopologyClosedEvent
372
+ | TopologyDescriptionChangedEvent
373
+ | TopologyOpeningEvent ;
303
374
304
375
/** @internal */
305
376
export interface LogConvertible extends Record < string , any > {
306
377
toLog ( ) : Record < string , any > ;
307
378
}
308
379
309
380
/** @internal */
310
- export function stringifyWithMaxLen ( value : any , maxDocumentLength : number ) : string {
311
- const ejson = EJSON . stringify ( value ) ?? 'custom function' ;
381
+ export function stringifyWithMaxLen (
382
+ value : any ,
383
+ maxDocumentLength : number ,
384
+ options : EJSONOptions = { }
385
+ ) : string {
386
+ const ejson = EJSON . stringify ( value , options ) ;
312
387
313
388
return maxDocumentLength !== 0 && ejson . length > maxDocumentLength
314
389
? `${ ejson . slice ( 0 , maxDocumentLength ) } ...`
@@ -363,6 +438,27 @@ function attachConnectionFields(log: Record<string, any>, event: any) {
363
438
return log ;
364
439
}
365
440
441
+ function attachSDAMFields ( log : Record < string , any > , sdamEvent : SDAMLoggableEvent ) {
442
+ log . topologyId = sdamEvent . topologyId ;
443
+ return log ;
444
+ }
445
+
446
+ function attachServerHeartbeatFields (
447
+ log : Record < string , any > ,
448
+ serverHeartbeatEvent :
449
+ | LoggableServerHeartbeatFailedEvent
450
+ | LoggableServerHeartbeatStartedEvent
451
+ | LoggableServerHeartbeatSucceededEvent
452
+ ) {
453
+ const { awaited, connectionId } = serverHeartbeatEvent ;
454
+ log . awaited = awaited ;
455
+ log . driverConnectionId = serverHeartbeatEvent . connectionId ;
456
+ const { host, port } = HostAddress . fromString ( connectionId ) . toHostPort ( ) ;
457
+ log . serverHost = host ;
458
+ log . serverPort = port ;
459
+ return log ;
460
+ }
461
+
366
462
function defaultLogTransform (
367
463
logObject : LoggableEvent | Record < string , any > ,
368
464
maxDocumentLength : number = DEFAULT_MAX_DOCUMENT_LENGTH
@@ -497,14 +593,63 @@ function defaultLogTransform(
497
593
case CONNECTION_CHECKED_OUT :
498
594
log = attachConnectionFields ( log , logObject ) ;
499
595
log . message = 'Connection checked out' ;
500
-
501
596
log . driverConnectionId = logObject . connectionId ;
502
597
return log ;
503
598
case CONNECTION_CHECKED_IN :
504
599
log = attachConnectionFields ( log , logObject ) ;
505
600
log . message = 'Connection checked in' ;
506
601
log . driverConnectionId = logObject . connectionId ;
507
602
return log ;
603
+ case SERVER_OPENING :
604
+ log = attachSDAMFields ( log , logObject ) ;
605
+ log = attachConnectionFields ( log , logObject ) ;
606
+ log . message = 'Starting server monitoring' ;
607
+ return log ;
608
+ case SERVER_CLOSED :
609
+ log = attachSDAMFields ( log , logObject ) ;
610
+ log = attachConnectionFields ( log , logObject ) ;
611
+ log . message = 'Stopped server monitoring' ;
612
+ return log ;
613
+ case SERVER_HEARTBEAT_STARTED :
614
+ log = attachSDAMFields ( log , logObject ) ;
615
+ log = attachServerHeartbeatFields ( log , logObject ) ;
616
+ log . message = 'Server heartbeat started' ;
617
+ return log ;
618
+ case SERVER_HEARTBEAT_SUCCEEDED :
619
+ log = attachSDAMFields ( log , logObject ) ;
620
+ log = attachServerHeartbeatFields ( log , logObject ) ;
621
+ log . message = 'Server heartbeat succeeded' ;
622
+ log . durationMS = logObject . duration ;
623
+ log . serverConnectionId = logObject . serverConnectionId ;
624
+ log . reply = stringifyWithMaxLen ( logObject . reply , maxDocumentLength , { relaxed : true } ) ;
625
+ return log ;
626
+ case SERVER_HEARTBEAT_FAILED :
627
+ log = attachSDAMFields ( log , logObject ) ;
628
+ log = attachServerHeartbeatFields ( log , logObject ) ;
629
+ log . message = 'Server heartbeat failed' ;
630
+ log . durationMS = logObject . duration ;
631
+ log . failure = logObject . failure . message ;
632
+ return log ;
633
+ case TOPOLOGY_OPENING :
634
+ log = attachSDAMFields ( log , logObject ) ;
635
+ log . message = 'Starting topology monitoring' ;
636
+ return log ;
637
+ case TOPOLOGY_CLOSED :
638
+ log = attachSDAMFields ( log , logObject ) ;
639
+ log . message = 'Stopped topology monitoring' ;
640
+ return log ;
641
+ case TOPOLOGY_DESCRIPTION_CHANGED :
642
+ log = attachSDAMFields ( log , logObject ) ;
643
+ log . message = 'Topology description changed' ;
644
+ log . previousDescription = log . reply = stringifyWithMaxLen (
645
+ logObject . previousDescription ,
646
+ maxDocumentLength
647
+ ) ;
648
+ log . newDescription = log . reply = stringifyWithMaxLen (
649
+ logObject . newDescription ,
650
+ maxDocumentLength
651
+ ) ;
652
+ return log ;
508
653
default :
509
654
for ( const [ key , value ] of Object . entries ( logObject ) ) {
510
655
if ( value != null ) log [ key ] = value ;
0 commit comments