Skip to content

Commit 4c3659a

Browse files
committed
feat(cli-repl): add ability to disable logging
1 parent 24894f3 commit 4c3659a

File tree

6 files changed

+148
-129
lines changed

6 files changed

+148
-129
lines changed

packages/cli-repl/src/cli-repl.spec.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import type { DevtoolsConnectOptions } from '@mongosh/service-provider-node-driv
3333
import type { AddressInfo } from 'net';
3434
import sinon from 'sinon';
3535
import type { CliUserConfig } from '@mongosh/types';
36+
import { MongoLogWriter } from 'mongodb-log-writer';
3637
const { EJSON } = bson;
3738

3839
const delay = promisify(setTimeout);
@@ -1318,17 +1319,18 @@ describe('CliRepl', function () {
13181319
sinon.restore();
13191320
});
13201321

1321-
it('logging occurs when it is not disabled', async function () {
1322+
it('start logging when it is not disabled', async function () {
13221323
const emitSpy = sinon.spy(cliRepl.bus, 'emit');
13231324

13241325
await cliRepl.start(await testServer.connectionString(), {});
13251326

13261327
expect(cliRepl.getConfig('disableLogging')).is.false;
13271328

13281329
expect(emitSpy).calledWith('mongosh:log-initialized');
1330+
expect(cliRepl.logWriter).is.instanceOf(MongoLogWriter);
13291331
});
13301332

1331-
it('uses the disable logging setting', async function () {
1333+
it('does not start logging when it is disabled', async function () {
13321334
const emitSpy = sinon.spy(cliRepl.bus, 'emit');
13331335
cliRepl.config.disableLogging = true;
13341336

@@ -1338,6 +1340,7 @@ describe('CliRepl', function () {
13381340

13391341
expect(emitSpy).called;
13401342
expect(emitSpy).not.calledWith('mongosh:log-initialized');
1343+
expect(cliRepl.logWriter).is.undefined;
13411344
});
13421345
});
13431346

packages/cli-repl/src/cli-repl.ts

Lines changed: 47 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -257,50 +257,30 @@ export class CliRepl implements MongoshIOProvider {
257257
);
258258
}
259259

260-
/** Setup analytics, logging and telemetry. */
261-
private async startLoggingAndTelemetry() {
262-
// Read the global config with log settings, e.g. logLocation, disableLogging
263-
const disableLogging = this.getConfig('disableLogging');
264-
if (!disableLogging) {
265-
await this.logManager.cleanupOldLogFiles();
266-
markTime(TimingCategories.Logging, 'cleaned up log files');
267-
268-
const logger = await this.logManager.createLogWriter();
269-
const { quiet } = CliRepl.getFileAndEvalInfo(this.cliOptions);
270-
if (!quiet) {
271-
this.output.write(`Current Mongosh Log ID:\t${logger.logId}\n`);
272-
}
273-
274-
this.logWriter = logger;
275-
setupMongoLogWriter(logger);
276-
markTime(TimingCategories.Logging, 'instantiated log writer');
277-
this.bus.emit('mongosh:log-initialized');
278-
logger.info('MONGOSH', mongoLogId(1_000_000_000), 'log', 'Starting log', {
279-
execPath: process.execPath,
280-
envInfo: redactSensitiveData(this.getLoggedEnvironmentVariables()),
281-
...(await buildInfo()),
282-
});
283-
284-
markTime(TimingCategories.Logging, 'logged initial message');
285-
}
286-
287-
markTime(TimingCategories.Telemetry, 'completed telemetry setup');
288-
289-
// Create analytics instance
290-
let analyticsSetupError: Error | null = null;
291-
try {
292-
await this.setupAnalytics();
293-
} catch (err: unknown) {
294-
// Need to delay emitting the error on the bus so that logging is in place
295-
// as well
296-
analyticsSetupError = err as Error;
260+
/** Setup log writer and start logging. */
261+
private async startLogging() {
262+
await this.logManager.cleanupOldLogFiles();
263+
markTime(TimingCategories.Logging, 'cleaned up log files');
264+
const logger = await this.logManager.createLogWriter();
265+
const { quiet } = CliRepl.getFileAndEvalInfo(this.cliOptions);
266+
if (!quiet) {
267+
this.output.write(`Current Mongosh Log ID:\t${logger.logId}\n`);
297268
}
298269

299-
markTime(TimingCategories.Telemetry, 'created analytics instance');
300-
301-
if (analyticsSetupError) {
302-
this.bus.emit('mongosh:error', analyticsSetupError, 'analytics');
303-
}
270+
this.logWriter = logger;
271+
this.logWriter = logger;
272+
setupMongoLogWriter(logger);
273+
this.logWriter = logger;
274+
setupMongoLogWriter(logger);
275+
markTime(TimingCategories.Logging, 'instantiated log writer');
276+
setupMongoLogWriter(logger);
277+
this.bus.emit('mongosh:log-initialized');
278+
logger.info('MONGOSH', mongoLogId(1_000_000_000), 'log', 'Starting log', {
279+
execPath: process.execPath,
280+
envInfo: redactSensitiveData(this.getLoggedEnvironmentVariables()),
281+
...(await buildInfo()),
282+
});
283+
markTime(TimingCategories.Logging, 'logged initial message');
304284
}
305285

306286
/**
@@ -355,14 +335,20 @@ export class CliRepl implements MongoshIOProvider {
355335
}
356336
markTime(TimingCategories.REPLInstantiation, 'ensured shell homedir');
357337

358-
// Setup telemetry
338+
let analyticsSetupError: Error | null = null;
339+
try {
340+
await this.setupAnalytics();
341+
} catch (err: unknown) {
342+
// Need to delay emitting the error on the bus so that logging is in place
343+
// as well
344+
analyticsSetupError = err as Error;
345+
}
346+
347+
markTime(TimingCategories.Telemetry, 'created analytics instance');
348+
359349
setupLoggerAndTelemetry(
360350
this.bus,
361351
this.toggleableAnalytics,
362-
{
363-
userId: this.getConfig('userId'),
364-
telemetryAnonymousId: this.getConfig('telemetryAnonymousId'),
365-
},
366352
{
367353
platform: process.platform,
368354
arch: process.arch,
@@ -371,8 +357,13 @@ export class CliRepl implements MongoshIOProvider {
371357
},
372358
version
373359
);
360+
markTime(TimingCategories.Telemetry, 'completed telemetry setup');
361+
362+
if (analyticsSetupError) {
363+
this.bus.emit('mongosh:error', analyticsSetupError, 'analytics');
364+
}
374365

375-
// Get configuration
366+
// Read local and global configuration
376367
try {
377368
this.config = await this.configDirectory.generateOrReadConfig(
378369
this.config
@@ -384,7 +375,10 @@ export class CliRepl implements MongoshIOProvider {
384375
this.globalConfig = await this.loadGlobalConfigFile();
385376
markTime(TimingCategories.UserConfigLoading, 'read global config files');
386377

387-
await this.startLoggingAndTelemetry();
378+
const disableLogging = this.getConfig('disableLogging');
379+
if (disableLogging !== true) {
380+
await this.startLogging();
381+
}
388382

389383
// Needs to happen after loading the mongosh config file(s)
390384
void this.fetchMongoshUpdateUrl();
@@ -543,6 +537,7 @@ export class CliRepl implements MongoshIOProvider {
543537
this.bus.emit('mongosh:start-mongosh-repl', { version });
544538
markTime(TimingCategories.REPLInstantiation, 'starting repl');
545539
await this.mongoshRepl.startRepl(initialized);
540+
546541
this.bus.emit('mongosh:start-session', {
547542
isInteractive: true,
548543
jsContext: this.mongoshRepl.jsContext(),
@@ -647,7 +642,7 @@ export class CliRepl implements MongoshIOProvider {
647642
files: string[],
648643
evalScripts: string[]
649644
): Promise<number> {
650-
let lastEvalResult: any;
645+
let lastEvalResult: unknown;
651646
let exitCode = 0;
652647
try {
653648
markTime(TimingCategories.Eval, 'start eval scripts');
@@ -1305,7 +1300,8 @@ export class CliRepl implements MongoshIOProvider {
13051300
}
13061301

13071302
async getMoreRecentMongoshVersion(): Promise<string | null> {
1308-
const { version } = require('../package.json');
1303+
// eslint-disable-next-line @typescript-eslint/no-var-requires
1304+
const { version }: { version: string } = require('../package.json');
13091305
return await this.updateNotificationManager.getLatestVersionIfMoreRecent(
13101306
process.env
13111307
.MONGOSH_ASSUME_DIFFERENT_VERSION_FOR_UPDATE_NOTIFICATION_TEST ||

packages/logging/src/analytics-helpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export type MongoshAnalyticsIdentity =
1111
anonymousId: string;
1212
};
1313

14-
type AnalyticsIdentifyMessage = MongoshAnalyticsIdentity & {
14+
export type AnalyticsIdentifyMessage = MongoshAnalyticsIdentity & {
1515
traits: { platform: string; session_id: string };
1616
timestamp?: Date;
1717
};

packages/logging/src/multi-set.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,30 @@ export class MultiSet<T extends Record<string, unknown>> {
2020
}
2121
}
2222
}
23+
24+
/**
25+
* It transforms a random string into snake case. Snake case is completely
26+
* lowercase and uses '_' to separate words. For example:
27+
*
28+
* This function defines a "word" as a sequence of characters until the next `.` or capital letter.
29+
*
30+
* 'Random String' => 'random_string'
31+
*
32+
* It will also remove any non alphanumeric characters to ensure the string
33+
* is compatible with Segment. For example:
34+
*
35+
* 'Node.js REPL Instantiation' => 'node_js_repl_instantiation'
36+
*
37+
* @param str Any non snake-case formatted string
38+
* @returns The snake-case formatted string
39+
*/
40+
export function toSnakeCase(str: string): string {
41+
const matches = str.match(
42+
/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g
43+
);
44+
if (!matches) {
45+
return str;
46+
}
47+
48+
return matches.map((x) => x.toLowerCase()).join('_');
49+
}

0 commit comments

Comments
 (0)