Skip to content

Commit f495abb

Browse files
feat(NODE-4849): Add Typescript support for log path in client options (#3886)
Co-authored-by: Daria Pardue <[email protected]>
1 parent 4125526 commit f495abb

File tree

6 files changed

+146
-8
lines changed

6 files changed

+146
-8
lines changed

src/connection_string.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1224,7 +1224,10 @@ export const OPTIONS = {
12241224
'useUnifiedTopology has no effect since Node.js Driver version 4.0.0 and will be removed in the next major version'
12251225
} as OptionDescriptor,
12261226
// MongoLogger
1227-
// TODO(NODE-4849): Tighten the type of mongodbLogPath
1227+
/**
1228+
* @internal
1229+
* TODO: NODE-5671 - remove internal flag
1230+
*/
12281231
mongodbLogPath: { type: 'any' }
12291232
} as Record<keyof MongoClientOptions, OptionDescriptor>;
12301233

src/mongo_client.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { MONGO_CLIENT_EVENTS } from './constants';
2121
import { Db, type DbOptions } from './db';
2222
import type { Encrypter } from './encrypter';
2323
import { MongoInvalidArgumentError } from './error';
24-
import { MongoLogger, type MongoLoggerOptions } from './mongo_logger';
24+
import { type MongoDBLogWritable, MongoLogger, type MongoLoggerOptions } from './mongo_logger';
2525
import { TypedEventEmitter } from './mongo_types';
2626
import { executeOperation } from './operations/execute_operation';
2727
import { RunAdminCommandOperation } from './operations/run_command';
@@ -252,6 +252,11 @@ export interface MongoClientOptions extends BSONSerializeOptions, SupportedNodeC
252252
srvPoller?: SrvPoller;
253253
/** @internal */
254254
connectionType?: typeof Connection;
255+
/**
256+
* @internal
257+
* TODO: NODE-5671 - remove internal flag
258+
*/
259+
mongodbLogPath?: 'stderr' | 'stdout' | MongoDBLogWritable;
255260

256261
/** @internal */
257262
[featureFlag: symbol]: any;
@@ -825,6 +830,14 @@ export interface MongoOptions
825830
/** @internal */
826831
[featureFlag: symbol]: any;
827832

828-
/** @internal */
833+
/**
834+
* @internal
835+
* TODO: NODE-5671 - remove internal flag
836+
*/
829837
mongoLoggerOptions: MongoLoggerOptions;
838+
/**
839+
* @internal
840+
* TODO: NODE-5671 - remove internal flag
841+
*/
842+
mongodbLogPath?: 'stderr' | 'stdout' | MongoDBLogWritable;
830843
}

src/mongo_logger.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ export function createStdioLogger(stream: {
191191
*/
192192
function resolveLogPath(
193193
{ MONGODB_LOG_PATH }: MongoLoggerEnvOptions,
194-
{ mongodbLogPath }: { mongodbLogPath?: string | Writable | MongoDBLogWritable }
194+
{ mongodbLogPath }: MongoLoggerMongoClientOptions
195195
): MongoDBLogWritable {
196196
if (typeof mongodbLogPath === 'string' && /^stderr$/i.test(mongodbLogPath)) {
197197
return createStdioLogger(process.stderr);

test/tools/unified-spec-runner/entities.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,9 @@ export class UnifiedMongoClient extends MongoClient {
189189
[Symbol.for('@@mdb.skipPingOnConnect')]: true,
190190
[Symbol.for('@@mdb.enableMongoLogger')]: true,
191191
[Symbol.for('@@mdb.internalLoggerConfig')]: componentSeverities,
192-
// @ts-expect-error TODO(NODE-4849): Remove this once we have support for mongodbLogPath
193-
mongodbLogPath: logCollector,
194192
...getEnvironmentalOptions(),
195-
...(description.serverApi ? { serverApi: description.serverApi } : {})
193+
...(description.serverApi ? { serverApi: description.serverApi } : {}),
194+
mongodbLogPath: logCollector
196195
} as any);
197196
this.logCollector = logCollector;
198197

test/unit/connection_string.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import * as process from 'node:process';
44
import { expect } from 'chai';
55
import * as dns from 'dns';
66
import * as sinon from 'sinon';
7+
import { inspect } from 'util';
78

89
import {
910
AUTH_MECHS_AUTH_SRC_EXTERNAL,
1011
AuthMechanism,
1112
DEFAULT_ALLOWED_HOSTS,
1213
FEATURE_FLAGS,
14+
type Log,
1315
MongoAPIError,
1416
MongoClient,
1517
MongoCredentials,
@@ -832,4 +834,53 @@ describe('Connection String', function () {
832834
.that.matches(/useUnifiedTopology has no effect/);
833835
});
834836
});
837+
838+
describe('when mongodbLogPath is in options', function () {
839+
const loggerFeatureFlag = Symbol.for('@@mdb.enableMongoLogger');
840+
841+
let stderrStub;
842+
let stdoutStub;
843+
844+
beforeEach(() => {
845+
stdoutStub = sinon.stub(process.stdout);
846+
stderrStub = sinon.stub(process.stderr);
847+
});
848+
849+
afterEach(() => {
850+
sinon.restore();
851+
});
852+
853+
context('when option is `stderr`', function () {
854+
it('it is accessible through mongoLogger.logDestination', function () {
855+
const client = new MongoClient('mongodb://a/?mongodbLogPath=stderr', {
856+
[loggerFeatureFlag]: true
857+
});
858+
const log: Log = { t: new Date(), c: 'ConnectionStringStdErr', s: 'error' };
859+
client.options.mongoLoggerOptions.logDestination.write(log);
860+
expect(stderrStub.write).calledWith(inspect(log, { breakLength: Infinity, compact: true }));
861+
});
862+
});
863+
864+
context('when option is `stdout`', function () {
865+
it('it is accessible through mongoLogger.logDestination', function () {
866+
const client = new MongoClient('mongodb://a/?mongodbLogPath=stdout', {
867+
[loggerFeatureFlag]: true
868+
});
869+
const log: Log = { t: new Date(), c: 'ConnectionStringStdOut', s: 'error' };
870+
client.options.mongoLoggerOptions.logDestination.write(log);
871+
expect(stdoutStub.write).calledWith(inspect(log, { breakLength: Infinity, compact: true }));
872+
});
873+
});
874+
875+
context('when option is invalid', function () {
876+
it('it defaults to stderr', function () {
877+
const client = new MongoClient('mongodb://a/?mongodbLogPath=stdnothing', {
878+
[loggerFeatureFlag]: true
879+
});
880+
const log: Log = { t: new Date(), c: 'ConnectionStringInvalidOption', s: 'error' };
881+
client.options.mongoLoggerOptions.logDestination.write(log);
882+
expect(stderrStub.write).calledWith(inspect(log, { breakLength: Infinity, compact: true }));
883+
});
884+
});
885+
});
835886
});

test/unit/mongo_client.test.js

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
'use strict';
1+
('use strict');
2+
3+
import { inspect } from 'util';
4+
25
const os = require('os');
36
const fs = require('fs');
47
const { expect } = require('chai');
@@ -813,4 +816,73 @@ describe('MongoOptions', function () {
813816
expect(client.options).to.have.property('mongoLoggerOptions').to.equal(expectedLoggingObject);
814817
});
815818
});
819+
820+
context('when mongodbLogPath is in options', function () {
821+
const loggerFeatureFlag = Symbol.for('@@mdb.enableMongoLogger');
822+
823+
let stderrStub;
824+
let stdoutStub;
825+
826+
beforeEach(() => {
827+
stdoutStub = sinon.stub(process.stdout);
828+
stderrStub = sinon.stub(process.stderr);
829+
});
830+
831+
afterEach(() => {
832+
sinon.restore();
833+
});
834+
835+
context('when option is `stderr`', function () {
836+
it('it is accessible through mongoLogger.logDestination', function () {
837+
const client = new MongoClient('mongodb://a/', {
838+
[loggerFeatureFlag]: true,
839+
mongodbLogPath: 'stderr'
840+
});
841+
const log = { t: new Date(), c: 'constructorStdErr', s: 'error' };
842+
client.options.mongoLoggerOptions.logDestination.write(log);
843+
expect(stderrStub.write).calledWith(inspect(log, { breakLength: Infinity, compact: true }));
844+
});
845+
});
846+
847+
context('when option is a MongoDBLogWritable stream', function () {
848+
it('it is accessible through mongoLogger.logDestination', function () {
849+
const writable = {
850+
buffer: [],
851+
write(log) {
852+
this.buffer.push(log);
853+
}
854+
};
855+
const client = new MongoClient('mongodb://a/', {
856+
[loggerFeatureFlag]: true,
857+
mongodbLogPath: writable
858+
});
859+
expect(client.options.mongoLoggerOptions.logDestination).to.deep.equal(writable);
860+
});
861+
});
862+
863+
context('when option is `stdout`', function () {
864+
it('it is accessible through mongoLogger.logDestination', function () {
865+
const client = new MongoClient('mongodb://a/', {
866+
[loggerFeatureFlag]: true,
867+
mongodbLogPath: 'stdout'
868+
});
869+
const log = { t: new Date(), c: 'constructorStdOut', s: 'error' };
870+
client.options.mongoLoggerOptions.logDestination.write(log);
871+
expect(stdoutStub.write).calledWith(inspect(log, { breakLength: Infinity, compact: true }));
872+
});
873+
});
874+
875+
context('when option is invalid', function () {
876+
it('it defaults to stderr', function () {
877+
const invalidOption = 'stdnothing';
878+
const client = new MongoClient('mongodb://a/', {
879+
[loggerFeatureFlag]: true,
880+
mongodbLogPath: invalidOption
881+
});
882+
const log = { t: new Date(), c: 'constructorInvalidOption', s: 'error' };
883+
client.options.mongoLoggerOptions.logDestination.write(log);
884+
expect(stderrStub.write).calledWith(inspect(log, { breakLength: Infinity, compact: true }));
885+
});
886+
});
887+
});
816888
});

0 commit comments

Comments
 (0)