Skip to content

Commit ef79cf4

Browse files
committed
refactor(cli-repl): use a object-oriented structure, hook loggers at initialization
I think this refactor provides much better readability and provides an easier interface for us to test and debug the functionality of this. This also moves the hookLoggers call to the point of initialization as
1 parent 5e503f8 commit ef79cf4

File tree

9 files changed

+887
-922
lines changed

9 files changed

+887
-922
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,7 +1326,7 @@ describe('CliRepl', function () {
13261326

13271327
expect(cliRepl.getConfig('disableLogging')).is.false;
13281328

1329-
expect(emitSpy).calledWith('mongosh:log-initialized');
1329+
expect(emitSpy).calledWith('mongosh:logger-initialized');
13301330
expect(cliRepl.logWriter).is.instanceOf(MongoLogWriter);
13311331
});
13321332

@@ -1339,7 +1339,7 @@ describe('CliRepl', function () {
13391339
expect(cliRepl.getConfig('disableLogging')).is.true;
13401340

13411341
expect(emitSpy).called;
1342-
expect(emitSpy).not.calledWith('mongosh:log-initialized');
1342+
expect(emitSpy).not.calledWith('mongosh:logger-initialized');
13431343
expect(cliRepl.logWriter).is.undefined;
13441344
});
13451345
});

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

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ import { MongoLogManager, mongoLogId } from 'mongodb-log-writer';
3131
import type { MongoshNodeReplOptions, MongoshIOProvider } from './mongosh-repl';
3232
import MongoshNodeRepl from './mongosh-repl';
3333
import {
34-
setupLoggerAndTelemetry,
3534
ToggleableAnalytics,
3635
ThrottledAnalytics,
3736
SampledAnalytics,
37+
MongoshLoggingAndTelemetry,
3838
} from '@mongosh/logging';
3939
import type { MongoshBus } from '@mongosh/types';
4040
import {
@@ -53,7 +53,6 @@ import type {
5353
DevtoolsProxyOptions,
5454
} from '@mongodb-js/devtools-proxy-support';
5555
import { useOrCreateAgent } from '@mongodb-js/devtools-proxy-support';
56-
import { setupMongoLogWriter } from '@mongosh/logging/lib/setup-logger-and-telemetry';
5756

5857
/**
5958
* Connecting text key.
@@ -258,7 +257,7 @@ export class CliRepl implements MongoshIOProvider {
258257
}
259258

260259
/** Setup log writer and start logging. */
261-
private async startLogging() {
260+
private async startLogging(loggingAndTelemetry: MongoshLoggingAndTelemetry) {
262261
await this.logManager.cleanupOldLogFiles();
263262
markTime(TimingCategories.Logging, 'cleaned up log files');
264263
const logger = await this.logManager.createLogWriter();
@@ -268,13 +267,10 @@ export class CliRepl implements MongoshIOProvider {
268267
}
269268

270269
this.logWriter = logger;
271-
this.logWriter = logger;
272-
setupMongoLogWriter(logger);
273-
this.logWriter = logger;
274-
setupMongoLogWriter(logger);
270+
loggingAndTelemetry.setupLogger(logger);
271+
275272
markTime(TimingCategories.Logging, 'instantiated log writer');
276-
setupMongoLogWriter(logger);
277-
this.bus.emit('mongosh:log-initialized');
273+
this.bus.emit('mongosh:logger-initialized');
278274
logger.info('MONGOSH', mongoLogId(1_000_000_000), 'log', 'Starting log', {
279275
execPath: process.execPath,
280276
envInfo: redactSensitiveData(this.getLoggedEnvironmentVariables()),
@@ -346,7 +342,7 @@ export class CliRepl implements MongoshIOProvider {
346342

347343
markTime(TimingCategories.Telemetry, 'created analytics instance');
348344

349-
setupLoggerAndTelemetry(
345+
const loggingAndTelemetry = new MongoshLoggingAndTelemetry(
350346
this.bus,
351347
this.toggleableAnalytics,
352348
{
@@ -357,6 +353,8 @@ export class CliRepl implements MongoshIOProvider {
357353
},
358354
version
359355
);
356+
loggingAndTelemetry.setup();
357+
360358
markTime(TimingCategories.Telemetry, 'completed telemetry setup');
361359

362360
if (analyticsSetupError) {
@@ -377,7 +375,7 @@ export class CliRepl implements MongoshIOProvider {
377375

378376
const disableLogging = this.getConfig('disableLogging');
379377
if (disableLogging !== true) {
380-
await this.startLogging();
378+
await this.startLogging(loggingAndTelemetry);
381379
}
382380

383381
// Needs to happen after loading the mongosh config file(s)

packages/logging/src/helpers.spec.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { expect } from 'chai';
2+
import { toSnakeCase } from './helpers';
3+
4+
describe('logging helpers', function () {
5+
describe('toSnakeCase', function () {
6+
const useCases = [
7+
{ input: 'MongoDB REPL', output: 'mongo_db_repl' },
8+
{
9+
input: 'Node.js REPL Instantiation',
10+
output: 'node_js_repl_instantiation',
11+
},
12+
{ input: 'A', output: 'a' },
13+
{
14+
input: 'OneLongThingInPascalCase',
15+
output: 'one_long_thing_in_pascal_case',
16+
},
17+
{ input: 'Removes .Dots in Node.js', output: 'removes_dots_in_node_js' },
18+
];
19+
20+
for (const { input, output } of useCases) {
21+
it(`should convert ${input} to ${output}`, function () {
22+
expect(toSnakeCase(input)).to.equal(output);
23+
});
24+
}
25+
});
26+
});
File renamed without changes.

packages/logging/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export { setupLoggerAndTelemetry } from './setup-logger-and-telemetry';
1+
export { MongoshLoggingAndTelemetry } from './logging-and-telemetry';
22
export {
33
MongoshAnalytics,
44
ToggleableAnalytics,

packages/logging/src/setup-logger-and-telemetry.spec.ts renamed to packages/logging/src/logging-and-telemetry.spec.ts

Lines changed: 63 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,30 @@
11
/* eslint-disable mocha/max-top-level-suites */
22
import { expect } from 'chai';
33
import { MongoLogWriter } from 'mongodb-log-writer';
4-
import { setupLoggerAndTelemetry } from './';
54
import { EventEmitter } from 'events';
65
import { MongoshInvalidInputError } from '@mongosh/errors';
76
import type { MongoshBus } from '@mongosh/types';
8-
import { setupMongoLogWriter, toSnakeCase } from './setup-logger-and-telemetry';
97
import type { Writable } from 'stream';
8+
import { MongoshLoggingAndTelemetry } from './logging-and-telemetry';
109

11-
describe('toSnakeCase', function () {
12-
const useCases = [
13-
{ input: 'MongoDB REPL', output: 'mongo_db_repl' },
14-
{
15-
input: 'Node.js REPL Instantiation',
16-
output: 'node_js_repl_instantiation',
17-
},
18-
{ input: 'A', output: 'a' },
19-
{
20-
input: 'OneLongThingInPascalCase',
21-
output: 'one_long_thing_in_pascal_case',
22-
},
23-
{ input: 'Removes .Dots in Node.js', output: 'removes_dots_in_node_js' },
24-
];
25-
26-
for (const { input, output } of useCases) {
27-
it(`should convert ${input} to ${output}`, function () {
28-
expect(toSnakeCase(input)).to.equal(output);
29-
});
30-
}
31-
});
32-
33-
describe('setupLoggerAndTelemetry', function () {
10+
describe('MongoshLoggingAndTelemetry', function () {
3411
let logOutput: any[];
3512
let analyticsOutput: ['identify' | 'track' | 'log', any][];
3613
let bus: MongoshBus;
3714

3815
const userId = '53defe995fa47e6c13102d9d';
3916
const logId = '5fb3c20ee1507e894e5340f3';
4017

41-
setupMongoLogWriter(
42-
new MongoLogWriter({
43-
logId,
44-
logFilePath: `/tmp/${logId}_log`,
45-
target: {
46-
write(chunk: string, cb: () => void) {
47-
logOutput.push(JSON.parse(chunk));
48-
cb();
49-
},
50-
end(cb: () => void) {
51-
cb();
52-
},
53-
} as Writable,
54-
})
55-
);
18+
const logger = new MongoLogWriter(logId, `/tmp/${logId}_log`, {
19+
write(chunk: string, cb: () => void) {
20+
logOutput.push(JSON.parse(chunk));
21+
cb();
22+
},
23+
end(cb: () => void) {
24+
cb();
25+
},
26+
} as Writable);
27+
5628
const analytics = {
5729
identify(info: any) {
5830
analyticsOutput.push(['identify', info]);
@@ -71,87 +43,41 @@ describe('setupLoggerAndTelemetry', function () {
7143
bus = new EventEmitter();
7244
});
7345

74-
it('accepts user ID at setup', function () {
75-
setupLoggerAndTelemetry(
46+
it('throws when trying to setup writer prematurely', function () {
47+
const loggingAndTelemetry = new MongoshLoggingAndTelemetry(
7648
bus,
7749
analytics,
78-
{ userId },
7950
{
8051
platform: process.platform,
8152
arch: process.arch,
8253
},
8354
'1.0.0'
8455
);
85-
expect(logOutput).to.have.lengthOf(0);
86-
expect(analyticsOutput).to.be.empty;
87-
88-
bus.emit('mongosh:connect', {
89-
uri: 'mongodb://localhost/',
90-
is_localhost: true,
91-
is_atlas: false,
92-
resolved_hostname: 'localhost',
93-
node_version: 'v12.19.0',
94-
});
95-
96-
expect(analyticsOutput).to.deep.equal([
97-
[
98-
'track',
99-
{
100-
anonymousId: userId,
101-
event: 'New Connection',
102-
properties: {
103-
mongosh_version: '1.0.0',
104-
session_id: logId,
105-
is_localhost: true,
106-
is_atlas: false,
107-
atlas_hostname: null,
108-
node_version: 'v12.19.0',
109-
},
110-
},
111-
],
112-
]);
113-
});
11456

115-
it('throws if an event occurs before the user is set', function () {
116-
setupLoggerAndTelemetry(
117-
bus,
118-
analytics,
119-
{},
120-
{
121-
platform: process.platform,
122-
arch: process.arch,
123-
},
124-
'1.0.0'
57+
expect(() => loggingAndTelemetry.setupLogger(logger)).throws(
58+
'Run setup() before setting up the log writer.'
12559
);
126-
expect(logOutput).to.have.lengthOf(0);
127-
expect(analyticsOutput).to.be.empty;
128-
129-
expect(() =>
130-
bus.emit('mongosh:connect', {
131-
uri: 'mongodb://localhost/',
132-
is_localhost: true,
133-
is_atlas: false,
134-
resolved_hostname: 'localhost',
135-
node_version: 'v12.19.0',
136-
})
137-
).throws('No telemetry identity found');
13860
});
13961

14062
it('tracks new local connection events', function () {
141-
setupLoggerAndTelemetry(
63+
const loggingAndTelemetry = new MongoshLoggingAndTelemetry(
14264
bus,
14365
analytics,
144-
{},
14566
{
14667
platform: process.platform,
14768
arch: process.arch,
14869
},
14970
'1.0.0'
15071
);
72+
73+
loggingAndTelemetry.setup();
74+
loggingAndTelemetry.setupLogger(logger);
75+
15176
expect(logOutput).to.have.lengthOf(0);
15277
expect(analyticsOutput).to.be.empty;
15378

15479
bus.emit('mongosh:new-user', { userId, anonymousId: userId });
80+
bus.emit('mongosh:logger-initialized');
15581

15682
bus.emit('mongosh:connect', {
15783
uri: 'mongodb://localhost/',
@@ -199,20 +125,24 @@ describe('setupLoggerAndTelemetry', function () {
199125
});
200126

201127
it('tracks new atlas connection events', function () {
202-
setupLoggerAndTelemetry(
128+
const loggingAndTelemetry = new MongoshLoggingAndTelemetry(
203129
bus,
204130
analytics,
205-
{},
206131
{
207132
platform: process.platform,
208133
arch: process.arch,
209134
},
210135
'1.0.0'
211136
);
137+
138+
loggingAndTelemetry.setup();
139+
loggingAndTelemetry.setupLogger(logger);
140+
212141
expect(logOutput).to.have.lengthOf(0);
213142
expect(analyticsOutput).to.be.empty;
214143

215144
bus.emit('mongosh:new-user', { userId, anonymousId: userId });
145+
bus.emit('mongosh:logger-initialized');
216146

217147
bus.emit('mongosh:connect', {
218148
uri: 'mongodb://test-data-sets-a011bb.mongodb.net/',
@@ -264,20 +194,25 @@ describe('setupLoggerAndTelemetry', function () {
264194
});
265195

266196
it('tracks a sequence of events', function () {
267-
setupLoggerAndTelemetry(
197+
const loggingAndTelemetry = new MongoshLoggingAndTelemetry(
268198
bus,
269199
analytics,
270-
{},
271200
{
272201
platform: process.platform,
273202
arch: process.arch,
274203
},
275204
'1.0.0'
276205
);
206+
207+
loggingAndTelemetry.setup();
208+
loggingAndTelemetry.setupLogger(logger);
209+
277210
expect(logOutput).to.have.lengthOf(0);
278211
expect(analyticsOutput).to.be.empty;
279212

280213
bus.emit('mongosh:new-user', { userId, anonymousId: userId });
214+
bus.emit('mongosh:logger-initialized');
215+
281216
bus.emit('mongosh:update-user', { userId, anonymousId: userId });
282217
bus.emit('mongosh:start-session', {
283218
isInteractive: true,
@@ -728,11 +663,25 @@ describe('setupLoggerAndTelemetry', function () {
728663
});
729664

730665
it('buffers deprecated API calls', function () {
731-
setupLoggerAndTelemetry(bus, analytics, {}, {}, '1.0.0');
666+
const loggingAndTelemetry = new MongoshLoggingAndTelemetry(
667+
bus,
668+
analytics,
669+
{
670+
platform: process.platform,
671+
arch: process.arch,
672+
},
673+
'1.0.0'
674+
);
675+
676+
loggingAndTelemetry.setup();
677+
loggingAndTelemetry.setupLogger(logger);
678+
732679
expect(logOutput).to.have.lengthOf(0);
733680
expect(analyticsOutput).to.be.empty;
734681

735682
bus.emit('mongosh:new-user', { userId, anonymousId: userId });
683+
bus.emit('mongosh:logger-initialized');
684+
736685
bus.emit('mongosh:evaluate-started');
737686

738687
logOutput = [];
@@ -900,7 +849,19 @@ describe('setupLoggerAndTelemetry', function () {
900849
});
901850

902851
it('does not track database calls outside of evaluate-{started,finished}', function () {
903-
setupLoggerAndTelemetry(bus, analytics, {}, {}, '1.0.0');
852+
const loggingAndTelemetry = new MongoshLoggingAndTelemetry(
853+
bus,
854+
analytics,
855+
{
856+
platform: process.platform,
857+
arch: process.arch,
858+
},
859+
'1.0.0'
860+
);
861+
862+
loggingAndTelemetry.setup();
863+
loggingAndTelemetry.setupLogger(logger);
864+
904865
expect(logOutput).to.have.lengthOf(0);
905866
expect(analyticsOutput).to.be.empty;
906867

0 commit comments

Comments
 (0)