Skip to content

Commit

Permalink
feat(NODE-4849): Add Typescript support for log path in client options (
Browse files Browse the repository at this point in the history
#3886)

Co-authored-by: Daria Pardue <[email protected]>
  • Loading branch information
aditi-khare-mongoDB and dariakp authored Oct 23, 2023
1 parent 4125526 commit f495abb
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 8 deletions.
5 changes: 4 additions & 1 deletion src/connection_string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1224,7 +1224,10 @@ export const OPTIONS = {
'useUnifiedTopology has no effect since Node.js Driver version 4.0.0 and will be removed in the next major version'
} as OptionDescriptor,
// MongoLogger
// TODO(NODE-4849): Tighten the type of mongodbLogPath
/**
* @internal
* TODO: NODE-5671 - remove internal flag
*/
mongodbLogPath: { type: 'any' }
} as Record<keyof MongoClientOptions, OptionDescriptor>;

Expand Down
17 changes: 15 additions & 2 deletions src/mongo_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { MONGO_CLIENT_EVENTS } from './constants';
import { Db, type DbOptions } from './db';
import type { Encrypter } from './encrypter';
import { MongoInvalidArgumentError } from './error';
import { MongoLogger, type MongoLoggerOptions } from './mongo_logger';
import { type MongoDBLogWritable, MongoLogger, type MongoLoggerOptions } from './mongo_logger';
import { TypedEventEmitter } from './mongo_types';
import { executeOperation } from './operations/execute_operation';
import { RunAdminCommandOperation } from './operations/run_command';
Expand Down Expand Up @@ -252,6 +252,11 @@ export interface MongoClientOptions extends BSONSerializeOptions, SupportedNodeC
srvPoller?: SrvPoller;
/** @internal */
connectionType?: typeof Connection;
/**
* @internal
* TODO: NODE-5671 - remove internal flag
*/
mongodbLogPath?: 'stderr' | 'stdout' | MongoDBLogWritable;

/** @internal */
[featureFlag: symbol]: any;
Expand Down Expand Up @@ -825,6 +830,14 @@ export interface MongoOptions
/** @internal */
[featureFlag: symbol]: any;

/** @internal */
/**
* @internal
* TODO: NODE-5671 - remove internal flag
*/
mongoLoggerOptions: MongoLoggerOptions;
/**
* @internal
* TODO: NODE-5671 - remove internal flag
*/
mongodbLogPath?: 'stderr' | 'stdout' | MongoDBLogWritable;
}
2 changes: 1 addition & 1 deletion src/mongo_logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ export function createStdioLogger(stream: {
*/
function resolveLogPath(
{ MONGODB_LOG_PATH }: MongoLoggerEnvOptions,
{ mongodbLogPath }: { mongodbLogPath?: string | Writable | MongoDBLogWritable }
{ mongodbLogPath }: MongoLoggerMongoClientOptions
): MongoDBLogWritable {
if (typeof mongodbLogPath === 'string' && /^stderr$/i.test(mongodbLogPath)) {
return createStdioLogger(process.stderr);
Expand Down
5 changes: 2 additions & 3 deletions test/tools/unified-spec-runner/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,9 @@ export class UnifiedMongoClient extends MongoClient {
[Symbol.for('@@mdb.skipPingOnConnect')]: true,
[Symbol.for('@@mdb.enableMongoLogger')]: true,
[Symbol.for('@@mdb.internalLoggerConfig')]: componentSeverities,
// @ts-expect-error TODO(NODE-4849): Remove this once we have support for mongodbLogPath
mongodbLogPath: logCollector,
...getEnvironmentalOptions(),
...(description.serverApi ? { serverApi: description.serverApi } : {})
...(description.serverApi ? { serverApi: description.serverApi } : {}),
mongodbLogPath: logCollector
} as any);
this.logCollector = logCollector;

Expand Down
51 changes: 51 additions & 0 deletions test/unit/connection_string.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import * as process from 'node:process';
import { expect } from 'chai';
import * as dns from 'dns';
import * as sinon from 'sinon';
import { inspect } from 'util';

import {
AUTH_MECHS_AUTH_SRC_EXTERNAL,
AuthMechanism,
DEFAULT_ALLOWED_HOSTS,
FEATURE_FLAGS,
type Log,
MongoAPIError,
MongoClient,
MongoCredentials,
Expand Down Expand Up @@ -832,4 +834,53 @@ describe('Connection String', function () {
.that.matches(/useUnifiedTopology has no effect/);
});
});

describe('when mongodbLogPath is in options', function () {
const loggerFeatureFlag = Symbol.for('@@mdb.enableMongoLogger');

let stderrStub;
let stdoutStub;

beforeEach(() => {
stdoutStub = sinon.stub(process.stdout);
stderrStub = sinon.stub(process.stderr);
});

afterEach(() => {
sinon.restore();
});

context('when option is `stderr`', function () {
it('it is accessible through mongoLogger.logDestination', function () {
const client = new MongoClient('mongodb://a/?mongodbLogPath=stderr', {
[loggerFeatureFlag]: true
});
const log: Log = { t: new Date(), c: 'ConnectionStringStdErr', s: 'error' };
client.options.mongoLoggerOptions.logDestination.write(log);
expect(stderrStub.write).calledWith(inspect(log, { breakLength: Infinity, compact: true }));
});
});

context('when option is `stdout`', function () {
it('it is accessible through mongoLogger.logDestination', function () {
const client = new MongoClient('mongodb://a/?mongodbLogPath=stdout', {
[loggerFeatureFlag]: true
});
const log: Log = { t: new Date(), c: 'ConnectionStringStdOut', s: 'error' };
client.options.mongoLoggerOptions.logDestination.write(log);
expect(stdoutStub.write).calledWith(inspect(log, { breakLength: Infinity, compact: true }));
});
});

context('when option is invalid', function () {
it('it defaults to stderr', function () {
const client = new MongoClient('mongodb://a/?mongodbLogPath=stdnothing', {
[loggerFeatureFlag]: true
});
const log: Log = { t: new Date(), c: 'ConnectionStringInvalidOption', s: 'error' };
client.options.mongoLoggerOptions.logDestination.write(log);
expect(stderrStub.write).calledWith(inspect(log, { breakLength: Infinity, compact: true }));
});
});
});
});
74 changes: 73 additions & 1 deletion test/unit/mongo_client.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
'use strict';
('use strict');

import { inspect } from 'util';

const os = require('os');
const fs = require('fs');
const { expect } = require('chai');
Expand Down Expand Up @@ -813,4 +816,73 @@ describe('MongoOptions', function () {
expect(client.options).to.have.property('mongoLoggerOptions').to.equal(expectedLoggingObject);
});
});

context('when mongodbLogPath is in options', function () {
const loggerFeatureFlag = Symbol.for('@@mdb.enableMongoLogger');

let stderrStub;
let stdoutStub;

beforeEach(() => {
stdoutStub = sinon.stub(process.stdout);
stderrStub = sinon.stub(process.stderr);
});

afterEach(() => {
sinon.restore();
});

context('when option is `stderr`', function () {
it('it is accessible through mongoLogger.logDestination', function () {
const client = new MongoClient('mongodb://a/', {
[loggerFeatureFlag]: true,
mongodbLogPath: 'stderr'
});
const log = { t: new Date(), c: 'constructorStdErr', s: 'error' };
client.options.mongoLoggerOptions.logDestination.write(log);
expect(stderrStub.write).calledWith(inspect(log, { breakLength: Infinity, compact: true }));
});
});

context('when option is a MongoDBLogWritable stream', function () {
it('it is accessible through mongoLogger.logDestination', function () {
const writable = {
buffer: [],
write(log) {
this.buffer.push(log);
}
};
const client = new MongoClient('mongodb://a/', {
[loggerFeatureFlag]: true,
mongodbLogPath: writable
});
expect(client.options.mongoLoggerOptions.logDestination).to.deep.equal(writable);
});
});

context('when option is `stdout`', function () {
it('it is accessible through mongoLogger.logDestination', function () {
const client = new MongoClient('mongodb://a/', {
[loggerFeatureFlag]: true,
mongodbLogPath: 'stdout'
});
const log = { t: new Date(), c: 'constructorStdOut', s: 'error' };
client.options.mongoLoggerOptions.logDestination.write(log);
expect(stdoutStub.write).calledWith(inspect(log, { breakLength: Infinity, compact: true }));
});
});

context('when option is invalid', function () {
it('it defaults to stderr', function () {
const invalidOption = 'stdnothing';
const client = new MongoClient('mongodb://a/', {
[loggerFeatureFlag]: true,
mongodbLogPath: invalidOption
});
const log = { t: new Date(), c: 'constructorInvalidOption', s: 'error' };
client.options.mongoLoggerOptions.logDestination.write(log);
expect(stderrStub.write).calledWith(inspect(log, { breakLength: Infinity, compact: true }));
});
});
});
});

0 comments on commit f495abb

Please sign in to comment.