Spaces:
Runtime error
Runtime error
Download static/node_modules/mongodb/src/mongo_logger.ts from kaab4321/NarrativeFlow: direct link, hf CLI and curl.
- Browser
- Download file 31 kB
-
https://huggingface.co/spaces/kaab4321/NarrativeFlow/resolve/main/static/node_modules/mongodb/src/mongo_logger.ts
- Command line
-
hf download hf://spaces/kaab4321/NarrativeFlow/static/node_modules/mongodb/src/mongo_logger.ts
-
curl -L -o mongo_logger.ts https://huggingface.co/spaces/kaab4321/NarrativeFlow/resolve/main/static/node_modules/mongodb/src/mongo_logger.ts
31 kB
| import { inspect, promisify } from 'util'; | |
| import { type Document, EJSON, type EJSONOptions, type ObjectId } from './bson'; | |
| import type { CommandStartedEvent } from './cmap/command_monitoring_events'; | |
| import type { | |
| ConnectionCheckedInEvent, | |
| ConnectionCheckedOutEvent, | |
| ConnectionCheckOutFailedEvent, | |
| ConnectionCheckOutStartedEvent, | |
| ConnectionClosedEvent, | |
| ConnectionCreatedEvent, | |
| ConnectionPoolClearedEvent, | |
| ConnectionPoolClosedEvent, | |
| ConnectionPoolCreatedEvent, | |
| ConnectionPoolReadyEvent, | |
| ConnectionReadyEvent | |
| } from './cmap/connection_pool_events'; | |
| import { | |
| COMMAND_FAILED, | |
| COMMAND_STARTED, | |
| COMMAND_SUCCEEDED, | |
| CONNECTION_CHECK_OUT_FAILED, | |
| CONNECTION_CHECK_OUT_STARTED, | |
| CONNECTION_CHECKED_IN, | |
| CONNECTION_CHECKED_OUT, | |
| CONNECTION_CLOSED, | |
| CONNECTION_CREATED, | |
| CONNECTION_POOL_CLEARED, | |
| CONNECTION_POOL_CLOSED, | |
| CONNECTION_POOL_CREATED, | |
| CONNECTION_POOL_READY, | |
| CONNECTION_READY, | |
| SERVER_CLOSED, | |
| SERVER_HEARTBEAT_FAILED, | |
| SERVER_HEARTBEAT_STARTED, | |
| SERVER_HEARTBEAT_SUCCEEDED, | |
| SERVER_OPENING, | |
| SERVER_SELECTION_FAILED, | |
| SERVER_SELECTION_STARTED, | |
| SERVER_SELECTION_SUCCEEDED, | |
| TOPOLOGY_CLOSED, | |
| TOPOLOGY_DESCRIPTION_CHANGED, | |
| TOPOLOGY_OPENING, | |
| WAITING_FOR_SUITABLE_SERVER | |
| } from './constants'; | |
| import type { | |
| ServerClosedEvent, | |
| ServerOpeningEvent, | |
| TopologyClosedEvent, | |
| TopologyDescriptionChangedEvent, | |
| TopologyOpeningEvent | |
| } from './sdam/events'; | |
| import type { | |
| ServerSelectionEvent, | |
| ServerSelectionFailedEvent, | |
| ServerSelectionStartedEvent, | |
| ServerSelectionSucceededEvent, | |
| WaitingForSuitableServerEvent | |
| } from './sdam/server_selection_events'; | |
| import { HostAddress, isPromiseLike, parseUnsignedInteger } from './utils'; | |
| /** @internal */ | |
| export const SeverityLevel = Object.freeze({ | |
| EMERGENCY: 'emergency', | |
| ALERT: 'alert', | |
| CRITICAL: 'critical', | |
| ERROR: 'error', | |
| WARNING: 'warn', | |
| NOTICE: 'notice', | |
| INFORMATIONAL: 'info', | |
| DEBUG: 'debug', | |
| TRACE: 'trace', | |
| OFF: 'off' | |
| } as const); | |
| /** @internal */ | |
| export const DEFAULT_MAX_DOCUMENT_LENGTH = 1000; | |
| /** @internal */ | |
| export type SeverityLevel = (typeof SeverityLevel)[keyof typeof SeverityLevel]; | |
| /** @internal */ | |
| class SeverityLevelMap extends Map<SeverityLevel | number, SeverityLevel | number> { | |
| constructor(entries: [SeverityLevel | number, SeverityLevel | number][]) { | |
| const newEntries: [number | SeverityLevel, SeverityLevel | number][] = []; | |
| for (const [level, value] of entries) { | |
| newEntries.push([value, level]); | |
| } | |
| newEntries.push(...entries); | |
| super(newEntries); | |
| } | |
| getNumericSeverityLevel(severity: SeverityLevel): number { | |
| return this.get(severity) as number; | |
| } | |
| getSeverityLevelName(level: number): SeverityLevel | undefined { | |
| return this.get(level) as SeverityLevel | undefined; | |
| } | |
| } | |
| /** @internal */ | |
| export const SEVERITY_LEVEL_MAP = new SeverityLevelMap([ | |
| [SeverityLevel.OFF, -Infinity], | |
| [SeverityLevel.EMERGENCY, 0], | |
| [SeverityLevel.ALERT, 1], | |
| [SeverityLevel.CRITICAL, 2], | |
| [SeverityLevel.ERROR, 3], | |
| [SeverityLevel.WARNING, 4], | |
| [SeverityLevel.NOTICE, 5], | |
| [SeverityLevel.INFORMATIONAL, 6], | |
| [SeverityLevel.DEBUG, 7], | |
| [SeverityLevel.TRACE, 8] | |
| ]); | |
| /** @internal */ | |
| export const MongoLoggableComponent = Object.freeze({ | |
| COMMAND: 'command', | |
| TOPOLOGY: 'topology', | |
| SERVER_SELECTION: 'serverSelection', | |
| CONNECTION: 'connection', | |
| CLIENT: 'client' | |
| } as const); | |
| /** @internal */ | |
| export type MongoLoggableComponent = | |
| (typeof MongoLoggableComponent)[keyof typeof MongoLoggableComponent]; | |
| /** @internal */ | |
| export interface MongoLoggerEnvOptions { | |
| /** Severity level for command component */ | |
| MONGODB_LOG_COMMAND?: string; | |
| /** Severity level for topology component */ | |
| MONGODB_LOG_TOPOLOGY?: string; | |
| /** Severity level for server selection component */ | |
| MONGODB_LOG_SERVER_SELECTION?: string; | |
| /** Severity level for CMAP */ | |
| MONGODB_LOG_CONNECTION?: string; | |
| /** Severity level for client */ | |
| MONGODB_LOG_CLIENT?: string; | |
| /** Default severity level to be if any of the above are unset */ | |
| MONGODB_LOG_ALL?: string; | |
| /** Max length of embedded EJSON docs. Setting to 0 disables truncation. Defaults to 1000. */ | |
| MONGODB_LOG_MAX_DOCUMENT_LENGTH?: string; | |
| /** Destination for log messages. Must be 'stderr', 'stdout'. Defaults to 'stderr'. */ | |
| MONGODB_LOG_PATH?: string; | |
| } | |
| /** @internal */ | |
| export interface LogComponentSeveritiesClientOptions { | |
| /** Optional severity level for command component */ | |
| command?: SeverityLevel; | |
| /** Optional severity level for topology component */ | |
| topology?: SeverityLevel; | |
| /** Optionsl severity level for server selection component */ | |
| serverSelection?: SeverityLevel; | |
| /** Optional severity level for connection component */ | |
| connection?: SeverityLevel; | |
| /** Optional severity level for client component */ | |
| client?: SeverityLevel; | |
| /** Optional default severity level to be used if any of the above are unset */ | |
| default?: SeverityLevel; | |
| } | |
| /** @internal */ | |
| export interface MongoLoggerMongoClientOptions { | |
| /** Destination for log messages */ | |
| mongodbLogPath?: 'stdout' | 'stderr' | MongoDBLogWritable; | |
| /** Severity levels for logger components */ | |
| mongodbLogComponentSeverities?: LogComponentSeveritiesClientOptions; | |
| /** Max length of embedded EJSON docs. Setting to 0 disables truncation. Defaults to 1000. */ | |
| mongodbLogMaxDocumentLength?: number; | |
| } | |
| /** @internal */ | |
| export interface MongoLoggerOptions { | |
| componentSeverities: { | |
| /** Severity level for command component */ | |
| command: SeverityLevel; | |
| /** Severity level for topology component */ | |
| topology: SeverityLevel; | |
| /** Severity level for server selection component */ | |
| serverSelection: SeverityLevel; | |
| /** Severity level for connection component */ | |
| connection: SeverityLevel; | |
| /** Severity level for client component */ | |
| client: SeverityLevel; | |
| /** Default severity level to be used if any of the above are unset */ | |
| default: SeverityLevel; | |
| }; | |
| /** Max length of embedded EJSON docs. Setting to 0 disables truncation. Defaults to 1000. */ | |
| maxDocumentLength: number; | |
| /** Destination for log messages. */ | |
| logDestination: MongoDBLogWritable; | |
| /** For internal check to see if error should stop logging. */ | |
| logDestinationIsStdErr: boolean; | |
| } | |
| /** | |
| * Parses a string as one of SeverityLevel | |
| * @internal | |
| * | |
| * @param s - the value to be parsed | |
| * @returns one of SeverityLevel if value can be parsed as such, otherwise null | |
| */ | |
| export function parseSeverityFromString(s?: string): SeverityLevel | null { | |
| const validSeverities: string[] = Object.values(SeverityLevel); | |
| const lowerSeverity = s?.toLowerCase(); | |
| if (lowerSeverity != null && validSeverities.includes(lowerSeverity)) { | |
| return lowerSeverity as SeverityLevel; | |
| } | |
| return null; | |
| } | |
| /** @internal */ | |
| export function createStdioLogger(stream: { | |
| write: NodeJS.WriteStream['write']; | |
| }): MongoDBLogWritable { | |
| return { | |
| write: promisify((log: Log, cb: (error?: Error) => void): unknown => { | |
| const logLine = inspect(log, { compact: true, breakLength: Infinity }); | |
| stream.write(`${logLine}\n`, 'utf-8', cb); | |
| return; | |
| }) | |
| }; | |
| } | |
| /** | |
| * resolves the MONGODB_LOG_PATH and mongodbLogPath options from the environment and the | |
| * mongo client options respectively. The mongodbLogPath can be either 'stdout', 'stderr', a NodeJS | |
| * Writable or an object which has a `write` method with the signature: | |
| * ```ts | |
| * write(log: Log): void | |
| * ``` | |
| * | |
| * @returns the MongoDBLogWritable object to write logs to | |
| */ | |
| function resolveLogPath( | |
| { MONGODB_LOG_PATH }: MongoLoggerEnvOptions, | |
| { mongodbLogPath }: MongoLoggerMongoClientOptions | |
| ): { mongodbLogPath: MongoDBLogWritable; mongodbLogPathIsStdErr: boolean } { | |
| if (typeof mongodbLogPath === 'string' && /^stderr$/i.test(mongodbLogPath)) { | |
| return { mongodbLogPath: createStdioLogger(process.stderr), mongodbLogPathIsStdErr: true }; | |
| } | |
| if (typeof mongodbLogPath === 'string' && /^stdout$/i.test(mongodbLogPath)) { | |
| return { mongodbLogPath: createStdioLogger(process.stdout), mongodbLogPathIsStdErr: false }; | |
| } | |
| if (typeof mongodbLogPath === 'object' && typeof mongodbLogPath?.write === 'function') { | |
| return { mongodbLogPath: mongodbLogPath, mongodbLogPathIsStdErr: false }; | |
| } | |
| if (MONGODB_LOG_PATH && /^stderr$/i.test(MONGODB_LOG_PATH)) { | |
| return { mongodbLogPath: createStdioLogger(process.stderr), mongodbLogPathIsStdErr: true }; | |
| } | |
| if (MONGODB_LOG_PATH && /^stdout$/i.test(MONGODB_LOG_PATH)) { | |
| return { mongodbLogPath: createStdioLogger(process.stdout), mongodbLogPathIsStdErr: false }; | |
| } | |
| return { mongodbLogPath: createStdioLogger(process.stderr), mongodbLogPathIsStdErr: true }; | |
| } | |
| function resolveSeverityConfiguration( | |
| clientOption: string | undefined, | |
| environmentOption: string | undefined, | |
| defaultSeverity: SeverityLevel | |
| ): SeverityLevel { | |
| return ( | |
| parseSeverityFromString(clientOption) ?? | |
| parseSeverityFromString(environmentOption) ?? | |
| defaultSeverity | |
| ); | |
| } | |
| /** @internal */ | |
| export interface Log extends Record<string, any> { | |
| t: Date; | |
| c: MongoLoggableComponent; | |
| s: SeverityLevel; | |
| message?: string; | |
| } | |
| /** | |
| * @internal | |
| * TODO: NODE-5671 - remove internal flag and add API comments | |
| */ | |
| export interface MongoDBLogWritable { | |
| write(log: Log): PromiseLike<unknown> | unknown; | |
| } | |
| function compareSeverity(s0: SeverityLevel, s1: SeverityLevel): 1 | 0 | -1 { | |
| const s0Num = SEVERITY_LEVEL_MAP.getNumericSeverityLevel(s0); | |
| const s1Num = SEVERITY_LEVEL_MAP.getNumericSeverityLevel(s1); | |
| return s0Num < s1Num ? -1 : s0Num > s1Num ? 1 : 0; | |
| } | |
| /** | |
| * @internal | |
| * Must be separate from Events API due to differences in spec requirements for logging a command success | |
| */ | |
| export type LoggableCommandSucceededEvent = { | |
| address: string; | |
| connectionId?: string | number; | |
| requestId: number; | |
| duration: number; | |
| commandName: string; | |
| reply: Document | undefined; | |
| serviceId?: ObjectId; | |
| name: typeof COMMAND_SUCCEEDED; | |
| serverConnectionId: bigint | null; | |
| databaseName: string; | |
| }; | |
| /** | |
| * @internal | |
| * Must be separate from Events API due to differences in spec requirements for logging a command failure | |
| */ | |
| export type LoggableCommandFailedEvent = { | |
| address: string; | |
| connectionId?: string | number; | |
| requestId: number; | |
| duration: number; | |
| commandName: string; | |
| failure: Error; | |
| serviceId?: ObjectId; | |
| name: typeof COMMAND_FAILED; | |
| serverConnectionId: bigint | null; | |
| databaseName: string; | |
| }; | |
| /** | |
| * @internal | |
| * Must be separate from Events API due to differences in spec requirements for logging server heartbeat beginning | |
| */ | |
| export type LoggableServerHeartbeatStartedEvent = { | |
| topologyId: number; | |
| awaited: boolean; | |
| connectionId: string; | |
| name: typeof SERVER_HEARTBEAT_STARTED; | |
| }; | |
| /** | |
| * @internal | |
| * Must be separate from Events API due to differences in spec requirements for logging server heartbeat success | |
| */ | |
| export type LoggableServerHeartbeatSucceededEvent = { | |
| topologyId: number; | |
| awaited: boolean; | |
| connectionId: string; | |
| reply: Document; | |
| serverConnectionId: number | '<monitor>'; | |
| duration: number; | |
| name: typeof SERVER_HEARTBEAT_SUCCEEDED; | |
| }; | |
| /** | |
| * @internal | |
| * Must be separate from Events API due to differences in spec requirements for logging server heartbeat failure | |
| */ | |
| export type LoggableServerHeartbeatFailedEvent = { | |
| topologyId: number; | |
| awaited: boolean; | |
| connectionId: string; | |
| failure: Error; | |
| duration: number; | |
| name: typeof SERVER_HEARTBEAT_FAILED; | |
| }; | |
| type SDAMLoggableEvent = | |
| | ServerClosedEvent | |
| | LoggableServerHeartbeatFailedEvent | |
| | LoggableServerHeartbeatStartedEvent | |
| | LoggableServerHeartbeatSucceededEvent | |
| | ServerOpeningEvent | |
| | TopologyClosedEvent | |
| | TopologyDescriptionChangedEvent | |
| | TopologyOpeningEvent; | |
| /** @internal */ | |
| export type LoggableEvent = | |
| | ServerSelectionStartedEvent | |
| | ServerSelectionFailedEvent | |
| | ServerSelectionSucceededEvent | |
| | WaitingForSuitableServerEvent | |
| | CommandStartedEvent | |
| | LoggableCommandSucceededEvent | |
| | LoggableCommandFailedEvent | |
| | ConnectionPoolCreatedEvent | |
| | ConnectionPoolReadyEvent | |
| | ConnectionPoolClosedEvent | |
| | ConnectionPoolClearedEvent | |
| | ConnectionCreatedEvent | |
| | ConnectionReadyEvent | |
| | ConnectionClosedEvent | |
| | ConnectionCheckedInEvent | |
| | ConnectionCheckedOutEvent | |
| | ConnectionCheckOutStartedEvent | |
| | ConnectionCheckOutFailedEvent | |
| | ServerClosedEvent | |
| | LoggableServerHeartbeatFailedEvent | |
| | LoggableServerHeartbeatStartedEvent | |
| | LoggableServerHeartbeatSucceededEvent | |
| | ServerOpeningEvent | |
| | TopologyClosedEvent | |
| | TopologyDescriptionChangedEvent | |
| | TopologyOpeningEvent; | |
| /** @internal */ | |
| export interface LogConvertible extends Record<string, any> { | |
| toLog(): Record<string, any>; | |
| } | |
| /** @internal */ | |
| export function stringifyWithMaxLen( | |
| value: any, | |
| maxDocumentLength: number, | |
| options: EJSONOptions = {} | |
| ): string { | |
| let strToTruncate = ''; | |
| if (typeof value === 'string') { | |
| strToTruncate = value; | |
| } else if (typeof value === 'function') { | |
| strToTruncate = value.name; | |
| } else { | |
| try { | |
| strToTruncate = EJSON.stringify(value, options); | |
| } catch (e) { | |
| strToTruncate = `Extended JSON serialization failed with: ${e.message}`; | |
| } | |
| } | |
| // handle truncation that occurs in the middle of multi-byte codepoints | |
| if ( | |
| maxDocumentLength !== 0 && | |
| strToTruncate.length > maxDocumentLength && | |
| strToTruncate.charCodeAt(maxDocumentLength - 1) !== | |
| strToTruncate.codePointAt(maxDocumentLength - 1) | |
| ) { | |
| maxDocumentLength--; | |
| if (maxDocumentLength === 0) { | |
| return ''; | |
| } | |
| } | |
| return maxDocumentLength !== 0 && strToTruncate.length > maxDocumentLength | |
| ? `${strToTruncate.slice(0, maxDocumentLength)}...` | |
| : strToTruncate; | |
| } | |
| /** @internal */ | |
| export type Loggable = LoggableEvent | LogConvertible; | |
| function isLogConvertible(obj: Loggable): obj is LogConvertible { | |
| const objAsLogConvertible = obj as LogConvertible; | |
| // eslint-disable-next-line no-restricted-syntax | |
| return objAsLogConvertible.toLog !== undefined && typeof objAsLogConvertible.toLog === 'function'; | |
| } | |
| function attachServerSelectionFields( | |
| log: Record<string, any>, | |
| serverSelectionEvent: ServerSelectionEvent, | |
| maxDocumentLength: number = DEFAULT_MAX_DOCUMENT_LENGTH | |
| ) { | |
| const { selector, operation, topologyDescription, message } = serverSelectionEvent; | |
| log.selector = stringifyWithMaxLen(selector, maxDocumentLength); | |
| log.operation = operation; | |
| log.topologyDescription = stringifyWithMaxLen(topologyDescription, maxDocumentLength); | |
| log.message = message; | |
| return log; | |
| } | |
| function attachCommandFields( | |
| log: Record<string, any>, | |
| commandEvent: CommandStartedEvent | LoggableCommandSucceededEvent | LoggableCommandFailedEvent | |
| ) { | |
| log.commandName = commandEvent.commandName; | |
| log.requestId = commandEvent.requestId; | |
| log.driverConnectionId = commandEvent.connectionId; | |
| const { host, port } = HostAddress.fromString(commandEvent.address).toHostPort(); | |
| log.serverHost = host; | |
| log.serverPort = port; | |
| if (commandEvent?.serviceId) { | |
| log.serviceId = commandEvent.serviceId.toHexString(); | |
| } | |
| log.databaseName = commandEvent.databaseName; | |
| log.serverConnectionId = commandEvent.serverConnectionId; | |
| return log; | |
| } | |
| function attachConnectionFields(log: Record<string, any>, event: any) { | |
| const { host, port } = HostAddress.fromString(event.address).toHostPort(); | |
| log.serverHost = host; | |
| log.serverPort = port; | |
| return log; | |
| } | |
| function attachSDAMFields(log: Record<string, any>, sdamEvent: SDAMLoggableEvent) { | |
| log.topologyId = sdamEvent.topologyId; | |
| return log; | |
| } | |
| function attachServerHeartbeatFields( | |
| log: Record<string, any>, | |
| serverHeartbeatEvent: | |
| | LoggableServerHeartbeatFailedEvent | |
| | LoggableServerHeartbeatStartedEvent | |
| | LoggableServerHeartbeatSucceededEvent | |
| ) { | |
| const { awaited, connectionId } = serverHeartbeatEvent; | |
| log.awaited = awaited; | |
| log.driverConnectionId = serverHeartbeatEvent.connectionId; | |
| const { host, port } = HostAddress.fromString(connectionId).toHostPort(); | |
| log.serverHost = host; | |
| log.serverPort = port; | |
| return log; | |
| } | |
| /** @internal */ | |
| export function defaultLogTransform( | |
| logObject: LoggableEvent | Record<string, any>, | |
| maxDocumentLength: number = DEFAULT_MAX_DOCUMENT_LENGTH | |
| ): Omit<Log, 's' | 't' | 'c'> { | |
| let log: Omit<Log, 's' | 't' | 'c'> = Object.create(null); | |
| switch (logObject.name) { | |
| case SERVER_SELECTION_STARTED: | |
| log = attachServerSelectionFields(log, logObject, maxDocumentLength); | |
| return log; | |
| case SERVER_SELECTION_FAILED: | |
| log = attachServerSelectionFields(log, logObject, maxDocumentLength); | |
| log.failure = logObject.failure?.message; | |
| return log; | |
| case SERVER_SELECTION_SUCCEEDED: | |
| log = attachServerSelectionFields(log, logObject, maxDocumentLength); | |
| log.serverHost = logObject.serverHost; | |
| log.serverPort = logObject.serverPort; | |
| return log; | |
| case WAITING_FOR_SUITABLE_SERVER: | |
| log = attachServerSelectionFields(log, logObject, maxDocumentLength); | |
| log.remainingTimeMS = logObject.remainingTimeMS; | |
| return log; | |
| case COMMAND_STARTED: | |
| log = attachCommandFields(log, logObject); | |
| log.message = 'Command started'; | |
| log.command = stringifyWithMaxLen(logObject.command, maxDocumentLength, { relaxed: true }); | |
| log.databaseName = logObject.databaseName; | |
| return log; | |
| case COMMAND_SUCCEEDED: | |
| log = attachCommandFields(log, logObject); | |
| log.message = 'Command succeeded'; | |
| log.durationMS = logObject.duration; | |
| log.reply = stringifyWithMaxLen(logObject.reply, maxDocumentLength, { relaxed: true }); | |
| return log; | |
| case COMMAND_FAILED: | |
| log = attachCommandFields(log, logObject); | |
| log.message = 'Command failed'; | |
| log.durationMS = logObject.duration; | |
| log.failure = logObject.failure?.message ?? '(redacted)'; | |
| return log; | |
| case CONNECTION_POOL_CREATED: | |
| log = attachConnectionFields(log, logObject); | |
| log.message = 'Connection pool created'; | |
| if (logObject.options) { | |
| const { maxIdleTimeMS, minPoolSize, maxPoolSize, maxConnecting, waitQueueTimeoutMS } = | |
| logObject.options; | |
| log = { | |
| ...log, | |
| maxIdleTimeMS, | |
| minPoolSize, | |
| maxPoolSize, | |
| maxConnecting, | |
| waitQueueTimeoutMS | |
| }; | |
| } | |
| return log; | |
| case CONNECTION_POOL_READY: | |
| log = attachConnectionFields(log, logObject); | |
| log.message = 'Connection pool ready'; | |
| return log; | |
| case CONNECTION_POOL_CLEARED: | |
| log = attachConnectionFields(log, logObject); | |
| log.message = 'Connection pool cleared'; | |
| if (logObject.serviceId?._bsontype === 'ObjectId') { | |
| log.serviceId = logObject.serviceId?.toHexString(); | |
| } | |
| return log; | |
| case CONNECTION_POOL_CLOSED: | |
| log = attachConnectionFields(log, logObject); | |
| log.message = 'Connection pool closed'; | |
| return log; | |
| case CONNECTION_CREATED: | |
| log = attachConnectionFields(log, logObject); | |
| log.message = 'Connection created'; | |
| log.driverConnectionId = logObject.connectionId; | |
| return log; | |
| case CONNECTION_READY: | |
| log = attachConnectionFields(log, logObject); | |
| log.message = 'Connection ready'; | |
| log.driverConnectionId = logObject.connectionId; | |
| return log; | |
| case CONNECTION_CLOSED: | |
| log = attachConnectionFields(log, logObject); | |
| log.message = 'Connection closed'; | |
| log.driverConnectionId = logObject.connectionId; | |
| switch (logObject.reason) { | |
| case 'stale': | |
| log.reason = 'Connection became stale because the pool was cleared'; | |
| break; | |
| case 'idle': | |
| log.reason = | |
| 'Connection has been available but unused for longer than the configured max idle time'; | |
| break; | |
| case 'error': | |
| log.reason = 'An error occurred while using the connection'; | |
| if (logObject.error) { | |
| log.error = logObject.error; | |
| } | |
| break; | |
| case 'poolClosed': | |
| log.reason = 'Connection pool was closed'; | |
| break; | |
| default: | |
| log.reason = `Unknown close reason: ${logObject.reason}`; | |
| } | |
| return log; | |
| case CONNECTION_CHECK_OUT_STARTED: | |
| log = attachConnectionFields(log, logObject); | |
| log.message = 'Connection checkout started'; | |
| return log; | |
| case CONNECTION_CHECK_OUT_FAILED: | |
| log = attachConnectionFields(log, logObject); | |
| log.message = 'Connection checkout failed'; | |
| switch (logObject.reason) { | |
| case 'poolClosed': | |
| log.reason = 'Connection pool was closed'; | |
| break; | |
| case 'timeout': | |
| log.reason = 'Wait queue timeout elapsed without a connection becoming available'; | |
| break; | |
| case 'connectionError': | |
| log.reason = 'An error occurred while trying to establish a new connection'; | |
| if (logObject.error) { | |
| log.error = logObject.error; | |
| } | |
| break; | |
| default: | |
| log.reason = `Unknown close reason: ${logObject.reason}`; | |
| } | |
| return log; | |
| case CONNECTION_CHECKED_OUT: | |
| log = attachConnectionFields(log, logObject); | |
| log.message = 'Connection checked out'; | |
| log.driverConnectionId = logObject.connectionId; | |
| return log; | |
| case CONNECTION_CHECKED_IN: | |
| log = attachConnectionFields(log, logObject); | |
| log.message = 'Connection checked in'; | |
| log.driverConnectionId = logObject.connectionId; | |
| return log; | |
| case SERVER_OPENING: | |
| log = attachSDAMFields(log, logObject); | |
| log = attachConnectionFields(log, logObject); | |
| log.message = 'Starting server monitoring'; | |
| return log; | |
| case SERVER_CLOSED: | |
| log = attachSDAMFields(log, logObject); | |
| log = attachConnectionFields(log, logObject); | |
| log.message = 'Stopped server monitoring'; | |
| return log; | |
| case SERVER_HEARTBEAT_STARTED: | |
| log = attachSDAMFields(log, logObject); | |
| log = attachServerHeartbeatFields(log, logObject); | |
| log.message = 'Server heartbeat started'; | |
| return log; | |
| case SERVER_HEARTBEAT_SUCCEEDED: | |
| log = attachSDAMFields(log, logObject); | |
| log = attachServerHeartbeatFields(log, logObject); | |
| log.message = 'Server heartbeat succeeded'; | |
| log.durationMS = logObject.duration; | |
| log.serverConnectionId = logObject.serverConnectionId; | |
| log.reply = stringifyWithMaxLen(logObject.reply, maxDocumentLength, { relaxed: true }); | |
| return log; | |
| case SERVER_HEARTBEAT_FAILED: | |
| log = attachSDAMFields(log, logObject); | |
| log = attachServerHeartbeatFields(log, logObject); | |
| log.message = 'Server heartbeat failed'; | |
| log.durationMS = logObject.duration; | |
| log.failure = logObject.failure?.message; | |
| return log; | |
| case TOPOLOGY_OPENING: | |
| log = attachSDAMFields(log, logObject); | |
| log.message = 'Starting topology monitoring'; | |
| return log; | |
| case TOPOLOGY_CLOSED: | |
| log = attachSDAMFields(log, logObject); | |
| log.message = 'Stopped topology monitoring'; | |
| return log; | |
| case TOPOLOGY_DESCRIPTION_CHANGED: | |
| log = attachSDAMFields(log, logObject); | |
| log.message = 'Topology description changed'; | |
| log.previousDescription = log.reply = stringifyWithMaxLen( | |
| logObject.previousDescription, | |
| maxDocumentLength | |
| ); | |
| log.newDescription = log.reply = stringifyWithMaxLen( | |
| logObject.newDescription, | |
| maxDocumentLength | |
| ); | |
| return log; | |
| default: | |
| for (const [key, value] of Object.entries(logObject)) { | |
| if (value != null) log[key] = value; | |
| } | |
| } | |
| return log; | |
| } | |
| /** @internal */ | |
| export class MongoLogger { | |
| componentSeverities: Record<MongoLoggableComponent, SeverityLevel>; | |
| maxDocumentLength: number; | |
| logDestination: MongoDBLogWritable; | |
| logDestinationIsStdErr: boolean; | |
| pendingLog: PromiseLike<unknown> | unknown = null; | |
| private severities: Record<MongoLoggableComponent, Record<SeverityLevel, boolean>>; | |
| /** | |
| * This method should be used when logging errors that do not have a public driver API for | |
| * reporting errors. | |
| */ | |
| error = this.log.bind(this, 'error'); | |
| /** | |
| * This method should be used to log situations where undesirable application behaviour might | |
| * occur. For example, failing to end sessions on `MongoClient.close`. | |
| */ | |
| warn = this.log.bind(this, 'warn'); | |
| /** | |
| * This method should be used to report high-level information about normal driver behaviour. | |
| * For example, the creation of a `MongoClient`. | |
| */ | |
| info = this.log.bind(this, 'info'); | |
| /** | |
| * This method should be used to report information that would be helpful when debugging an | |
| * application. For example, a command starting, succeeding or failing. | |
| */ | |
| debug = this.log.bind(this, 'debug'); | |
| /** | |
| * This method should be used to report fine-grained details related to logic flow. For example, | |
| * entering and exiting a function body. | |
| */ | |
| trace = this.log.bind(this, 'trace'); | |
| constructor(options: MongoLoggerOptions) { | |
| this.componentSeverities = options.componentSeverities; | |
| this.maxDocumentLength = options.maxDocumentLength; | |
| this.logDestination = options.logDestination; | |
| this.logDestinationIsStdErr = options.logDestinationIsStdErr; | |
| this.severities = this.createLoggingSeverities(); | |
| } | |
| createLoggingSeverities(): Record<MongoLoggableComponent, Record<SeverityLevel, boolean>> { | |
| const severities = Object(); | |
| for (const component of Object.values(MongoLoggableComponent)) { | |
| severities[component] = {}; | |
| for (const severityLevel of Object.values(SeverityLevel)) { | |
| severities[component][severityLevel] = | |
| compareSeverity(severityLevel, this.componentSeverities[component]) <= 0; | |
| } | |
| } | |
| return severities; | |
| } | |
| turnOffSeverities() { | |
| for (const component of Object.values(MongoLoggableComponent)) { | |
| this.componentSeverities[component] = SeverityLevel.OFF; | |
| for (const severityLevel of Object.values(SeverityLevel)) { | |
| this.severities[component][severityLevel] = false; | |
| } | |
| } | |
| } | |
| private logWriteFailureHandler(error: Error) { | |
| if (this.logDestinationIsStdErr) { | |
| this.turnOffSeverities(); | |
| this.clearPendingLog(); | |
| return; | |
| } | |
| this.logDestination = createStdioLogger(process.stderr); | |
| this.logDestinationIsStdErr = true; | |
| this.clearPendingLog(); | |
| this.error(MongoLoggableComponent.CLIENT, { | |
| toLog: function () { | |
| return { | |
| message: 'User input for mongodbLogPath is now invalid. Logging is halted.', | |
| error: error.message | |
| }; | |
| } | |
| }); | |
| this.turnOffSeverities(); | |
| this.clearPendingLog(); | |
| } | |
| private clearPendingLog() { | |
| this.pendingLog = null; | |
| } | |
| willLog(component: MongoLoggableComponent, severity: SeverityLevel): boolean { | |
| if (severity === SeverityLevel.OFF) return false; | |
| return this.severities[component][severity]; | |
| } | |
| private log( | |
| severity: SeverityLevel, | |
| component: MongoLoggableComponent, | |
| message: Loggable | string | |
| ): void { | |
| if (!this.willLog(component, severity)) return; | |
| let logMessage: Log = { t: new Date(), c: component, s: severity }; | |
| if (typeof message === 'string') { | |
| logMessage.message = message; | |
| } else if (typeof message === 'object') { | |
| if (isLogConvertible(message)) { | |
| logMessage = { ...logMessage, ...message.toLog() }; | |
| } else { | |
| logMessage = { ...logMessage, ...defaultLogTransform(message, this.maxDocumentLength) }; | |
| } | |
| } | |
| if (isPromiseLike(this.pendingLog)) { | |
| this.pendingLog = this.pendingLog | |
| // eslint-disable-next-line github/no-then | |
| .then(() => this.logDestination.write(logMessage)) | |
| // eslint-disable-next-line github/no-then | |
| .then(this.clearPendingLog.bind(this), this.logWriteFailureHandler.bind(this)); | |
| return; | |
| } | |
| try { | |
| const logResult = this.logDestination.write(logMessage); | |
| if (isPromiseLike(logResult)) { | |
| // eslint-disable-next-line github/no-then | |
| this.pendingLog = logResult.then( | |
| this.clearPendingLog.bind(this), | |
| this.logWriteFailureHandler.bind(this) | |
| ); | |
| } | |
| } catch (error) { | |
| this.logWriteFailureHandler(error); | |
| } | |
| } | |
| /** | |
| * Merges options set through environment variables and the MongoClient, preferring environment | |
| * variables when both are set, and substituting defaults for values not set. Options set in | |
| * constructor take precedence over both environment variables and MongoClient options. | |
| * | |
| * @remarks | |
| * When parsing component severity levels, invalid values are treated as unset and replaced with | |
| * the default severity. | |
| * | |
| * @param envOptions - options set for the logger from the environment | |
| * @param clientOptions - options set for the logger in the MongoClient options | |
| * @returns a MongoLoggerOptions object to be used when instantiating a new MongoLogger | |
| */ | |
| static resolveOptions( | |
| envOptions: MongoLoggerEnvOptions, | |
| clientOptions: MongoLoggerMongoClientOptions | |
| ): MongoLoggerOptions { | |
| // client options take precedence over env options | |
| const resolvedLogPath = resolveLogPath(envOptions, clientOptions); | |
| const combinedOptions = { | |
| ...envOptions, | |
| ...clientOptions, | |
| mongodbLogPath: resolvedLogPath.mongodbLogPath, | |
| mongodbLogPathIsStdErr: resolvedLogPath.mongodbLogPathIsStdErr | |
| }; | |
| const defaultSeverity = resolveSeverityConfiguration( | |
| combinedOptions.mongodbLogComponentSeverities?.default, | |
| combinedOptions.MONGODB_LOG_ALL, | |
| SeverityLevel.OFF | |
| ); | |
| return { | |
| componentSeverities: { | |
| command: resolveSeverityConfiguration( | |
| combinedOptions.mongodbLogComponentSeverities?.command, | |
| combinedOptions.MONGODB_LOG_COMMAND, | |
| defaultSeverity | |
| ), | |
| topology: resolveSeverityConfiguration( | |
| combinedOptions.mongodbLogComponentSeverities?.topology, | |
| combinedOptions.MONGODB_LOG_TOPOLOGY, | |
| defaultSeverity | |
| ), | |
| serverSelection: resolveSeverityConfiguration( | |
| combinedOptions.mongodbLogComponentSeverities?.serverSelection, | |
| combinedOptions.MONGODB_LOG_SERVER_SELECTION, | |
| defaultSeverity | |
| ), | |
| connection: resolveSeverityConfiguration( | |
| combinedOptions.mongodbLogComponentSeverities?.connection, | |
| combinedOptions.MONGODB_LOG_CONNECTION, | |
| defaultSeverity | |
| ), | |
| client: resolveSeverityConfiguration( | |
| combinedOptions.mongodbLogComponentSeverities?.client, | |
| combinedOptions.MONGODB_LOG_CLIENT, | |
| defaultSeverity | |
| ), | |
| default: defaultSeverity | |
| }, | |
| maxDocumentLength: | |
| combinedOptions.mongodbLogMaxDocumentLength ?? | |
| parseUnsignedInteger(combinedOptions.MONGODB_LOG_MAX_DOCUMENT_LENGTH) ?? | |
| 1000, | |
| logDestination: combinedOptions.mongodbLogPath, | |
| logDestinationIsStdErr: combinedOptions.mongodbLogPathIsStdErr | |
| }; | |
| } | |
| } | |