Skip to content

Commit

Permalink
feat(NODE-5169): Implement emergency logger (#3610)
Browse files Browse the repository at this point in the history
  • Loading branch information
W-A-James committed Apr 14, 2023
1 parent 2a26de3 commit d502eb0
Show file tree
Hide file tree
Showing 12 changed files with 1,259 additions and 88 deletions.
14 changes: 13 additions & 1 deletion src/cmap/command_monitoring_events.ts
@@ -1,5 +1,11 @@
import type { Document, ObjectId } from '../bson';
import { LEGACY_HELLO_COMMAND, LEGACY_HELLO_COMMAND_CAMEL_CASE } from '../constants';
import {
COMMAND_FAILED,
COMMAND_STARTED,
COMMAND_SUCCEEDED,
LEGACY_HELLO_COMMAND,
LEGACY_HELLO_COMMAND_CAMEL_CASE
} from '../constants';
import { calculateDurationInMs, deepCopy } from '../utils';
import { Msg, WriteProtocolMessageType } from './commands';
import type { Connection } from './connection';
Expand All @@ -18,6 +24,8 @@ export class CommandStartedEvent {
address: string;
connectionId?: string | number;
serviceId?: ObjectId;
/** @internal */
name = COMMAND_STARTED;

/**
* Create a started event
Expand Down Expand Up @@ -65,6 +73,8 @@ export class CommandSucceededEvent {
commandName: string;
reply: unknown;
serviceId?: ObjectId;
/** @internal */
name = COMMAND_SUCCEEDED;

/**
* Create a succeeded event
Expand Down Expand Up @@ -113,6 +123,8 @@ export class CommandFailedEvent {
commandName: string;
failure: Error;
serviceId?: ObjectId;
/** @internal */
name = COMMAND_FAILED;

/**
* Create a failure event
Expand Down
1 change: 1 addition & 0 deletions src/cmap/connect.ts
Expand Up @@ -401,6 +401,7 @@ function makeConnection(options: MakeConnectionOptions, _callback: Callback<Stre

if ('authorizationError' in socket) {
if (socket.authorizationError && rejectUnauthorized) {
// TODO(NODE-5192): wrap this with a MongoError subclass
return callback(socket.authorizationError);
}
}
Expand Down
18 changes: 14 additions & 4 deletions src/cmap/connection_pool.ts
Expand Up @@ -641,7 +641,10 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
}
}

private destroyConnection(connection: Connection, reason: string) {
private destroyConnection(
connection: Connection,
reason: 'error' | 'idle' | 'stale' | 'poolClosed'
) {
this.emit(
ConnectionPool.CONNECTION_CLOSED,
new ConnectionClosedEvent(this, connection, reason)
Expand Down Expand Up @@ -701,7 +704,13 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
this[kPending]--;
this.emit(
ConnectionPool.CONNECTION_CLOSED,
new ConnectionClosedEvent(this, { id: connectOptions.id, serviceId: undefined }, 'error')
new ConnectionClosedEvent(
this,
{ id: connectOptions.id, serviceId: undefined },
'error',
// TODO(NODE-5192): Remove this cast
err as MongoError
)
);
if (err instanceof MongoNetworkError || err instanceof MongoServerError) {
err.connectionGeneration = connectOptions.generation;
Expand Down Expand Up @@ -812,7 +821,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
const error = this.closed ? new PoolClosedError(this) : new PoolClearedError(this);
this.emit(
ConnectionPool.CONNECTION_CHECK_OUT_FAILED,
new ConnectionCheckOutFailedEvent(this, reason)
new ConnectionCheckOutFailedEvent(this, reason, error)
);
if (waitQueueMember.timer) {
clearTimeout(waitQueueMember.timer);
Expand Down Expand Up @@ -865,7 +874,8 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
if (err) {
this.emit(
ConnectionPool.CONNECTION_CHECK_OUT_FAILED,
new ConnectionCheckOutFailedEvent(this, 'connectionError')
// TODO(NODE-5192): Remove this cast
new ConnectionCheckOutFailedEvent(this, 'connectionError', err as MongoError)
);
} else if (connection) {
this[kCheckedOut].add(connection);
Expand Down
74 changes: 68 additions & 6 deletions src/cmap/connection_pool_events.ts
@@ -1,5 +1,18 @@
import type { ObjectId } from '../bson';
import type { AnyError } from '../error';
import {
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
} from '../constants';
import type { MongoError } from '../error';
import type { Connection } from './connection';
import type { ConnectionPool, ConnectionPoolOptions } from './connection_pool';

Expand All @@ -8,11 +21,24 @@ import type { ConnectionPool, ConnectionPoolOptions } from './connection_pool';
* @public
* @category Event
*/
export class ConnectionPoolMonitoringEvent {
export abstract class ConnectionPoolMonitoringEvent {
/** A timestamp when the event was created */
time: Date;
/** The address (host/port pair) of the pool */
address: string;
/** @internal */
abstract name:
| typeof CONNECTION_CHECK_OUT_FAILED
| typeof CONNECTION_CHECK_OUT_STARTED
| typeof CONNECTION_CHECKED_IN
| typeof CONNECTION_CHECKED_OUT
| typeof CONNECTION_CLOSED
| typeof CONNECTION_CREATED
| typeof CONNECTION_POOL_CLEARED
| typeof CONNECTION_POOL_CLOSED
| typeof CONNECTION_POOL_CREATED
| typeof CONNECTION_POOL_READY
| typeof CONNECTION_READY;

/** @internal */
constructor(pool: ConnectionPool) {
Expand All @@ -29,6 +55,8 @@ export class ConnectionPoolMonitoringEvent {
export class ConnectionPoolCreatedEvent extends ConnectionPoolMonitoringEvent {
/** The options used to create this connection pool */
options?: ConnectionPoolOptions;
/** @internal */
name = CONNECTION_POOL_CREATED;

/** @internal */
constructor(pool: ConnectionPool) {
Expand All @@ -43,6 +71,9 @@ export class ConnectionPoolCreatedEvent extends ConnectionPoolMonitoringEvent {
* @category Event
*/
export class ConnectionPoolReadyEvent extends ConnectionPoolMonitoringEvent {
/** @internal */
name = CONNECTION_POOL_READY;

/** @internal */
constructor(pool: ConnectionPool) {
super(pool);
Expand All @@ -55,6 +86,9 @@ export class ConnectionPoolReadyEvent extends ConnectionPoolMonitoringEvent {
* @category Event
*/
export class ConnectionPoolClosedEvent extends ConnectionPoolMonitoringEvent {
/** @internal */
name = CONNECTION_POOL_CLOSED;

/** @internal */
constructor(pool: ConnectionPool) {
super(pool);
Expand All @@ -69,6 +103,8 @@ export class ConnectionPoolClosedEvent extends ConnectionPoolMonitoringEvent {
export class ConnectionCreatedEvent extends ConnectionPoolMonitoringEvent {
/** A monotonically increasing, per-pool id for the newly created connection */
connectionId: number | '<monitor>';
/** @internal */
name = CONNECTION_CREATED;

/** @internal */
constructor(pool: ConnectionPool, connection: { id: number | '<monitor>' }) {
Expand All @@ -85,6 +121,8 @@ export class ConnectionCreatedEvent extends ConnectionPoolMonitoringEvent {
export class ConnectionReadyEvent extends ConnectionPoolMonitoringEvent {
/** The id of the connection */
connectionId: number | '<monitor>';
/** @internal */
name = CONNECTION_READY;

/** @internal */
constructor(pool: ConnectionPool, connection: Connection) {
Expand All @@ -104,17 +142,23 @@ export class ConnectionClosedEvent extends ConnectionPoolMonitoringEvent {
/** The reason the connection was closed */
reason: string;
serviceId?: ObjectId;
/** @internal */
name = CONNECTION_CLOSED;
/** @internal */
error: MongoError | null;

/** @internal */
constructor(
pool: ConnectionPool,
connection: Pick<Connection, 'id' | 'serviceId'>,
reason: string
reason: 'idle' | 'stale' | 'poolClosed' | 'error',
error?: MongoError
) {
super(pool);
this.connectionId = connection.id;
this.reason = reason || 'unknown';
this.reason = reason;
this.serviceId = connection.serviceId;
this.error = error ?? null;
}
}

Expand All @@ -124,6 +168,9 @@ export class ConnectionClosedEvent extends ConnectionPoolMonitoringEvent {
* @category Event
*/
export class ConnectionCheckOutStartedEvent extends ConnectionPoolMonitoringEvent {
/** @internal */
name = CONNECTION_CHECK_OUT_STARTED;

/** @internal */
constructor(pool: ConnectionPool) {
super(pool);
Expand All @@ -137,12 +184,21 @@ export class ConnectionCheckOutStartedEvent extends ConnectionPoolMonitoringEven
*/
export class ConnectionCheckOutFailedEvent extends ConnectionPoolMonitoringEvent {
/** The reason the attempt to check out failed */
reason: AnyError | string;
reason: string;
/** @internal */
error?: MongoError;
/** @internal */
name = CONNECTION_CHECK_OUT_FAILED;

/** @internal */
constructor(pool: ConnectionPool, reason: AnyError | string) {
constructor(
pool: ConnectionPool,
reason: 'poolClosed' | 'timeout' | 'connectionError',
error?: MongoError
) {
super(pool);
this.reason = reason;
this.error = error;
}
}

Expand All @@ -154,6 +210,8 @@ export class ConnectionCheckOutFailedEvent extends ConnectionPoolMonitoringEvent
export class ConnectionCheckedOutEvent extends ConnectionPoolMonitoringEvent {
/** The id of the connection */
connectionId: number | '<monitor>';
/** @internal */
name = CONNECTION_CHECKED_OUT;

/** @internal */
constructor(pool: ConnectionPool, connection: Connection) {
Expand All @@ -170,6 +228,8 @@ export class ConnectionCheckedOutEvent extends ConnectionPoolMonitoringEvent {
export class ConnectionCheckedInEvent extends ConnectionPoolMonitoringEvent {
/** The id of the connection */
connectionId: number | '<monitor>';
/** @internal */
name = CONNECTION_CHECKED_IN;

/** @internal */
constructor(pool: ConnectionPool, connection: Connection) {
Expand All @@ -188,6 +248,8 @@ export class ConnectionPoolClearedEvent extends ConnectionPoolMonitoringEvent {
serviceId?: ObjectId;

interruptInUseConnections?: boolean;
/** @internal */
name = CONNECTION_POOL_CLEARED;

/** @internal */
constructor(
Expand Down
3 changes: 2 additions & 1 deletion src/connection_string.ts
Expand Up @@ -1280,5 +1280,6 @@ export const DEFAULT_OPTIONS = new CaseInsensitiveMap(
*/
export const FEATURE_FLAGS = new Set([
Symbol.for('@@mdb.skipPingOnConnect'),
Symbol.for('@@mdb.enableMongoLogger')
Symbol.for('@@mdb.enableMongoLogger'),
Symbol.for('@@mdb.internalLoggerConfig')
]);
11 changes: 11 additions & 0 deletions src/constants.ts
Expand Up @@ -23,16 +23,27 @@ export const SERVER_DESCRIPTION_CHANGED = 'serverDescriptionChanged' as const;
export const TOPOLOGY_OPENING = 'topologyOpening' as const;
export const TOPOLOGY_CLOSED = 'topologyClosed' as const;
export const TOPOLOGY_DESCRIPTION_CHANGED = 'topologyDescriptionChanged' as const;
/** @internal */
export const CONNECTION_POOL_CREATED = 'connectionPoolCreated' as const;
/** @internal */
export const CONNECTION_POOL_CLOSED = 'connectionPoolClosed' as const;
/** @internal */
export const CONNECTION_POOL_CLEARED = 'connectionPoolCleared' as const;
/** @internal */
export const CONNECTION_POOL_READY = 'connectionPoolReady' as const;
/** @internal */
export const CONNECTION_CREATED = 'connectionCreated' as const;
/** @internal */
export const CONNECTION_READY = 'connectionReady' as const;
/** @internal */
export const CONNECTION_CLOSED = 'connectionClosed' as const;
/** @internal */
export const CONNECTION_CHECK_OUT_STARTED = 'connectionCheckOutStarted' as const;
/** @internal */
export const CONNECTION_CHECK_OUT_FAILED = 'connectionCheckOutFailed' as const;
/** @internal */
export const CONNECTION_CHECKED_OUT = 'connectionCheckedOut' as const;
/** @internal */
export const CONNECTION_CHECKED_IN = 'connectionCheckedIn' as const;
export const CLUSTER_TIME_RECEIVED = 'clusterTimeReceived' as const;
export const COMMAND_STARTED = 'commandStarted' as const;
Expand Down
20 changes: 19 additions & 1 deletion src/index.ts
Expand Up @@ -248,7 +248,20 @@ export type { ConnectionPoolMetrics } from './cmap/metrics';
export type { StreamDescription, StreamDescriptionOptions } from './cmap/stream_description';
export type { CompressorName } from './cmap/wire_protocol/compression';
export type { CollectionOptions, CollectionPrivate, ModifyResult } from './collection';
export type { MONGO_CLIENT_EVENTS } from './constants';
export type {
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,
MONGO_CLIENT_EVENTS
} from './constants';
export type {
AbstractCursorEvents,
AbstractCursorOptions,
Expand Down Expand Up @@ -290,6 +303,11 @@ export type {
WithSessionCallback
} from './mongo_client';
export type {
Log,
LogConvertible,
Loggable,
LoggableEvent,
MongoDBLogWritable,
MongoLoggableComponent,
MongoLogger,
MongoLoggerEnvOptions,
Expand Down

0 comments on commit d502eb0

Please sign in to comment.