1- import { EJSON } from 'bson' ;
1+ import { type Document , EJSON , type EJSONOptions } from 'bson' ;
22import type { Writable } from 'stream' ;
33import { inspect } from 'util' ;
44
@@ -35,8 +35,23 @@ import {
3535 CONNECTION_POOL_CLOSED ,
3636 CONNECTION_POOL_CREATED ,
3737 CONNECTION_POOL_READY ,
38- CONNECTION_READY
38+ CONNECTION_READY ,
39+ SERVER_CLOSED ,
40+ SERVER_HEARTBEAT_FAILED ,
41+ SERVER_HEARTBEAT_STARTED ,
42+ SERVER_HEARTBEAT_SUCCEEDED ,
43+ SERVER_OPENING ,
44+ TOPOLOGY_CLOSED ,
45+ TOPOLOGY_DESCRIPTION_CHANGED ,
46+ TOPOLOGY_OPENING
3947} from './constants' ;
48+ import type {
49+ ServerClosedEvent ,
50+ ServerOpeningEvent ,
51+ TopologyClosedEvent ,
52+ TopologyDescriptionChangedEvent ,
53+ TopologyOpeningEvent
54+ } from './sdam/events' ;
4055import { HostAddress , parseUnsignedInteger } from './utils' ;
4156
4257/** @internal */
@@ -270,6 +285,54 @@ function compareSeverity(s0: SeverityLevel, s1: SeverityLevel): 1 | 0 | -1 {
270285 return s0Num < s1Num ? - 1 : s0Num > s1Num ? 1 : 0 ;
271286}
272287
288+ /**
289+ * @internal
290+ * Must be separate from Events API due to differences in spec requirements for logging server heartbeat beginning
291+ */
292+ export type LoggableServerHeartbeatStartedEvent = {
293+ topologyId : number ;
294+ awaited : boolean ;
295+ connectionId : string ;
296+ name : typeof SERVER_HEARTBEAT_STARTED ;
297+ } ;
298+
299+ /**
300+ * @internal
301+ * Must be separate from Events API due to differences in spec requirements for logging server heartbeat success
302+ */
303+ export type LoggableServerHeartbeatSucceededEvent = {
304+ topologyId : number ;
305+ awaited : boolean ;
306+ connectionId : string ;
307+ reply : Document ;
308+ serverConnectionId : number | '<monitor>' ;
309+ duration : number ;
310+ name : typeof SERVER_HEARTBEAT_SUCCEEDED ;
311+ } ;
312+
313+ /**
314+ * @internal
315+ * Must be separate from Events API due to differences in spec requirements for logging server heartbeat failure
316+ */
317+ export type LoggableServerHeartbeatFailedEvent = {
318+ topologyId : number ;
319+ awaited : boolean ;
320+ connectionId : string ;
321+ failure : Error ;
322+ duration : number ;
323+ name : typeof SERVER_HEARTBEAT_FAILED ;
324+ } ;
325+
326+ type SDAMLoggableEvent =
327+ | ServerClosedEvent
328+ | LoggableServerHeartbeatFailedEvent
329+ | LoggableServerHeartbeatStartedEvent
330+ | LoggableServerHeartbeatSucceededEvent
331+ | ServerOpeningEvent
332+ | TopologyClosedEvent
333+ | TopologyDescriptionChangedEvent
334+ | TopologyOpeningEvent ;
335+
273336/** @internal */
274337export type LoggableEvent =
275338 | CommandStartedEvent
@@ -285,16 +348,28 @@ export type LoggableEvent =
285348 | ConnectionCheckedInEvent
286349 | ConnectionCheckedOutEvent
287350 | ConnectionCheckOutStartedEvent
288- | ConnectionCheckOutFailedEvent ;
351+ | ConnectionCheckOutFailedEvent
352+ | ServerClosedEvent
353+ | LoggableServerHeartbeatFailedEvent
354+ | LoggableServerHeartbeatStartedEvent
355+ | LoggableServerHeartbeatSucceededEvent
356+ | ServerOpeningEvent
357+ | TopologyClosedEvent
358+ | TopologyDescriptionChangedEvent
359+ | TopologyOpeningEvent ;
289360
290361/** @internal */
291362export interface LogConvertible extends Record < string , any > {
292363 toLog ( ) : Record < string , any > ;
293364}
294365
295366/** @internal */
296- export function stringifyWithMaxLen ( value : any , maxDocumentLength : number ) : string {
297- const ejson = EJSON . stringify ( value ) ;
367+ export function stringifyWithMaxLen (
368+ value : any ,
369+ maxDocumentLength : number ,
370+ options : EJSONOptions = { }
371+ ) : string {
372+ const ejson = EJSON . stringify ( value , options ) ;
298373
299374 return maxDocumentLength !== 0 && ejson . length > maxDocumentLength
300375 ? `${ ejson . slice ( 0 , maxDocumentLength ) } ...`
@@ -329,15 +404,36 @@ function attachCommandFields(
329404
330405function attachConnectionFields (
331406 log : Record < string , any > ,
332- connectionPoolEvent : ConnectionPoolMonitoringEvent
407+ event : ConnectionPoolMonitoringEvent | ServerOpeningEvent | ServerClosedEvent
333408) {
334- const { host, port } = HostAddress . fromString ( connectionPoolEvent . address ) . toHostPort ( ) ;
409+ const { host, port } = HostAddress . fromString ( event . address ) . toHostPort ( ) ;
335410 log . serverHost = host ;
336411 log . serverPort = port ;
337412
338413 return log ;
339414}
340415
416+ function attachSDAMFields ( log : Record < string , any > , sdamEvent : SDAMLoggableEvent ) {
417+ log . topologyId = sdamEvent . topologyId ;
418+ return log ;
419+ }
420+
421+ function attachServerHeartbeatFields (
422+ log : Record < string , any > ,
423+ serverHeartbeatEvent :
424+ | LoggableServerHeartbeatFailedEvent
425+ | LoggableServerHeartbeatStartedEvent
426+ | LoggableServerHeartbeatSucceededEvent
427+ ) {
428+ const { awaited, connectionId } = serverHeartbeatEvent ;
429+ log . awaited = awaited ;
430+ log . driverConnectionId = serverHeartbeatEvent . connectionId ;
431+ const { host, port } = HostAddress . fromString ( connectionId ) . toHostPort ( ) ;
432+ log . serverHost = host ;
433+ log . serverPort = port ;
434+ return log ;
435+ }
436+
341437function defaultLogTransform (
342438 logObject : LoggableEvent | Record < string , any > ,
343439 maxDocumentLength : number = DEFAULT_MAX_DOCUMENT_LENGTH
@@ -456,14 +552,63 @@ function defaultLogTransform(
456552 case CONNECTION_CHECKED_OUT :
457553 log = attachConnectionFields ( log , logObject ) ;
458554 log . message = 'Connection checked out' ;
459-
460555 log . driverConnectionId = logObject . connectionId ;
461556 return log ;
462557 case CONNECTION_CHECKED_IN :
463558 log = attachConnectionFields ( log , logObject ) ;
464559 log . message = 'Connection checked in' ;
465560 log . driverConnectionId = logObject . connectionId ;
466561 return log ;
562+ case SERVER_OPENING :
563+ log = attachSDAMFields ( log , logObject ) ;
564+ log = attachConnectionFields ( log , logObject ) ;
565+ log . message = 'Starting server monitoring' ;
566+ return log ;
567+ case SERVER_CLOSED :
568+ log = attachSDAMFields ( log , logObject ) ;
569+ log = attachConnectionFields ( log , logObject ) ;
570+ log . message = 'Stopped server monitoring' ;
571+ return log ;
572+ case SERVER_HEARTBEAT_STARTED :
573+ log = attachSDAMFields ( log , logObject ) ;
574+ log = attachServerHeartbeatFields ( log , logObject ) ;
575+ log . message = 'Server heartbeat started' ;
576+ return log ;
577+ case SERVER_HEARTBEAT_SUCCEEDED :
578+ log = attachSDAMFields ( log , logObject ) ;
579+ log = attachServerHeartbeatFields ( log , logObject ) ;
580+ log . message = 'Server heartbeat succeeded' ;
581+ log . durationMS = logObject . duration ;
582+ log . serverConnectionId = logObject . serverConnectionId ;
583+ log . reply = stringifyWithMaxLen ( logObject . reply , maxDocumentLength , { relaxed : true } ) ;
584+ return log ;
585+ case SERVER_HEARTBEAT_FAILED :
586+ log = attachSDAMFields ( log , logObject ) ;
587+ log = attachServerHeartbeatFields ( log , logObject ) ;
588+ log . message = 'Server heartbeat failed' ;
589+ log . durationMS = logObject . duration ;
590+ log . failure = logObject . failure . message ;
591+ return log ;
592+ case TOPOLOGY_OPENING :
593+ log = attachSDAMFields ( log , logObject ) ;
594+ log . message = 'Starting topology monitoring' ;
595+ return log ;
596+ case TOPOLOGY_CLOSED :
597+ log = attachSDAMFields ( log , logObject ) ;
598+ log . message = 'Stopped topology monitoring' ;
599+ return log ;
600+ case TOPOLOGY_DESCRIPTION_CHANGED :
601+ log = attachSDAMFields ( log , logObject ) ;
602+ log . message = 'Topology description changed' ;
603+ log . previousDescription = log . reply = stringifyWithMaxLen (
604+ logObject . previousDescription ,
605+ maxDocumentLength
606+ ) ;
607+ log . newDescription = log . reply = stringifyWithMaxLen (
608+ logObject . newDescription ,
609+ maxDocumentLength
610+ ) ;
611+ return log ;
467612 default :
468613 for ( const [ key , value ] of Object . entries ( logObject ) ) {
469614 if ( value != null ) log [ key ] = value ;
0 commit comments