Server IP : 162.213.251.212 / Your IP : 18.188.22.126 [ Web Server : LiteSpeed System : Linux business55.web-hosting.com 4.18.0-553.lve.el8.x86_64 #1 SMP Mon May 27 15:27:34 UTC 2024 x86_64 User : allssztx ( 535) PHP Version : 8.1.31 Disable Function : NONE Domains : 1 Domains MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/allssztx/nodevenv/needapair.com/20/lib/node_modules/mongodb/src/ |
Upload File : |
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; log.durationMS = logObject.durationMS; 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}`; } log.durationMS = logObject.durationMS; return log; case CONNECTION_CHECKED_OUT: log = attachConnectionFields(log, logObject); log.message = 'Connection checked out'; log.driverConnectionId = logObject.connectionId; log.durationMS = logObject.durationMS; 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 .then(() => this.logDestination.write(logMessage)) .then(this.clearPendingLog.bind(this), this.logWriteFailureHandler.bind(this)); return; } try { const logResult = this.logDestination.write(logMessage); if (isPromiseLike(logResult)) { 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 }; } }