Skip to content

feat(logging): add configuration to disable logging MONGOSH-1988 #2325

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

95 changes: 82 additions & 13 deletions packages/cli-repl/src/cli-repl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
import {
expect,
fakeTTYProps,
readReplLogfile,
readReplLogFile,
tick,
useTmpdir,
waitBus,
Expand All @@ -31,6 +31,9 @@ import { CliRepl } from './cli-repl';
import { CliReplErrors } from './error-codes';
import type { DevtoolsConnectOptions } from '@mongosh/service-provider-node-driver';
import type { AddressInfo } from 'net';
import sinon from 'sinon';
import type { CliUserConfig } from '@mongosh/types';
import { MongoLogWriter, MongoLogManager } from 'mongodb-log-writer';
const { EJSON } = bson;

const delay = promisify(setTimeout);
Expand All @@ -53,7 +56,7 @@ describe('CliRepl', function () {
async function log(): Promise<any[]> {
if (!cliRepl.logWriter?.logFilePath) return [];
await cliRepl.logWriter.flush(); // Ensure any pending data is written first
return readReplLogfile(cliRepl.logWriter.logFilePath);
return readReplLogFile(cliRepl.logWriter.logFilePath);
}

async function startWithExpectedImmediateExit(
Expand Down Expand Up @@ -235,6 +238,27 @@ describe('CliRepl', function () {
});
});

it('does not write to log syntax errors if logging is disabled', async function () {
expect(
(await log()).filter((entry) =>
entry.attr?.stack?.startsWith('SyntaxError:')
)
).to.have.lengthOf(0);
input.write('config.set("disableLogging", true)\n');
await waitEval(cliRepl.bus);
expect(output).includes('Setting "disableLogging" has been changed');

input.write('<cat>\n');
await waitBus(cliRepl.bus, 'mongosh:error');
await eventually(async () => {
expect(
(await log()).filter((entry) =>
entry.attr?.stack?.startsWith('SyntaxError:')
)
).to.have.lengthOf(0);
});
});

it('writes JS errors to the log file', async function () {
input.write('throw new Error("plain js error")\n');
await waitBus(cliRepl.bus, 'mongosh:error');
Expand Down Expand Up @@ -297,7 +321,8 @@ describe('CliRepl', function () {
'oidcTrustedEndpoints',
'browser',
'updateURL',
]);
'disableLogging',
] satisfies (keyof CliUserConfig)[]);
});

it('fails when trying to overwrite mongosh-owned config settings', async function () {
Expand Down Expand Up @@ -453,12 +478,14 @@ describe('CliRepl', function () {
cliRepl = new CliRepl(cliReplOptions);
await cliRepl.start('', {});
await fs.stat(newerlogfile);
try {
await fs.stat(oldlogfile);
expect.fail('missed exception');
} catch (err: any) {
expect(err.code).to.equal('ENOENT');
}
await eventually(async () => {
try {
await fs.stat(oldlogfile);
expect.fail('missed exception');
} catch (err: any) {
expect(err.code).to.equal('ENOENT');
}
});
});

it('verifies the Node.js version', async function () {
Expand Down Expand Up @@ -1309,7 +1336,6 @@ describe('CliRepl', function () {
hasCollectionNames: true,
hasDatabaseNames: true,
});

context('analytics integration', function () {
context('with network connectivity', function () {
let srv: http.Server;
Expand All @@ -1333,6 +1359,7 @@ describe('CliRepl', function () {
.on('data', (chunk) => {
body += chunk;
})
// eslint-disable-next-line @typescript-eslint/no-misused-promises
.on('end', async () => {
requests.push({ req, body });
totalEventsTracked += JSON.parse(body).batch.length;
Expand All @@ -1343,7 +1370,7 @@ describe('CliRepl', function () {
})
.listen(0);
await once(srv, 'listening');
host = `http://localhost:${(srv.address() as any).port}`;
host = `http://localhost:${(srv.address() as AddressInfo).port}`;
cliReplOptions.analyticsOptions = {
host,
apiKey: '🔑',
Expand All @@ -1357,6 +1384,48 @@ describe('CliRepl', function () {
srv.close();
await once(srv, 'close');
setTelemetryDelay(0);
sinon.restore();
});

context('logging configuration', function () {
it('logging is enabled by default and event is called', async function () {
const onLogInitialized = sinon.stub();
cliRepl.bus.on('mongosh:log-initialized', onLogInitialized);

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

expect(await cliRepl.getConfig('disableLogging')).is.false;

expect(onLogInitialized).calledOnce;
expect(cliRepl.logWriter).is.instanceOf(MongoLogWriter);
});

it('does not initialize logging when it is disabled', async function () {
cliRepl.config.disableLogging = true;
const onLogInitialized = sinon.stub();
cliRepl.bus.on('mongosh:log-initialized', onLogInitialized);

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

expect(await cliRepl.getConfig('disableLogging')).is.true;
expect(onLogInitialized).not.called;

expect(cliRepl.logWriter).is.undefined;
});

it('logs cleanup errors', async function () {
sinon
.stub(MongoLogManager.prototype, 'cleanupOldLogFiles')
.rejects(new Error('Method not implemented'));
await cliRepl.start(await testServer.connectionString(), {});
expect(
(await log()).filter(
(entry) =>
entry.ctx === 'log' &&
entry.msg === 'Error: Method not implemented'
)
).to.have.lengthOf(1);
});
});

it('times out fast', async function () {
Expand Down Expand Up @@ -1507,11 +1576,11 @@ describe('CliRepl', function () {

it('includes a statement about flushed telemetry in the log', async function () {
await cliRepl.start(await testServer.connectionString(), {});
const { logFilePath } = cliRepl.logWriter!;
const { logFilePath } = cliRepl.logWriter as MongoLogWriter;
input.write('db.hello()\n');
input.write('exit\n');
await waitBus(cliRepl.bus, 'mongosh:closed');
const flushEntry = (await readReplLogfile(logFilePath)).find(
const flushEntry = (await readReplLogFile(logFilePath)).find(
(entry: any) => entry.id === 1_000_000_045
);
expect(flushEntry.attr.flushError).to.equal(null);
Expand Down
Loading