Skip to content

Commit a9a2a51

Browse files
authored
feat(cli-repl): add configuration to set log retention days MONGOSH-1984 (#2349)
1 parent 51bbd33 commit a9a2a51

File tree

5 files changed

+95
-2
lines changed

5 files changed

+95
-2
lines changed

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ describe('CliRepl', function () {
323323
'updateURL',
324324
'disableLogging',
325325
'logLocation',
326+
'logRetentionDays',
326327
] satisfies (keyof CliUserConfig)[]);
327328
});
328329

@@ -1443,6 +1444,19 @@ describe('CliRepl', function () {
14431444
)
14441445
);
14451446
});
1447+
1448+
it('can set log retention days', async function () {
1449+
const testRetentionDays = 123;
1450+
cliRepl.config.logRetentionDays = testRetentionDays;
1451+
await cliRepl.start(await testServer.connectionString(), {});
1452+
1453+
expect(await cliRepl.getConfig('logRetentionDays')).equals(
1454+
testRetentionDays
1455+
);
1456+
expect(cliRepl.logManager?._options.retentionDays).equals(
1457+
testRetentionDays
1458+
);
1459+
});
14461460
});
14471461

14481462
it('times out fast', async function () {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ export class CliRepl implements MongoshIOProvider {
259259
directory:
260260
(await this.getConfig('logLocation')) ||
261261
this.shellHomeDirectory.localPath('.'),
262-
retentionDays: 30,
262+
retentionDays: await this.getConfig('logRetentionDays'),
263263
maxLogFileCount: +(
264264
process.env.MONGOSH_TEST_ONLY_MAX_LOG_FILE_COUNT || 100
265265
),

packages/e2e-tests/test/e2e.spec.ts

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable no-control-regex */
22
import { expect } from 'chai';
33
import type { Db } from 'mongodb';
4-
import { MongoClient } from 'mongodb';
4+
import { MongoClient, ObjectId } from 'mongodb';
55

66
import { eventually } from '../../../testing/eventually';
77
import { TestShell } from './test-shell';
@@ -1676,6 +1676,77 @@ describe('e2e', function () {
16761676
});
16771677
});
16781678

1679+
/** Helper to visualize and compare the existence of files in a specific order.
1680+
* Returns a string comprised of: 1 if a given file exists, 0 otherwise. */
1681+
const getFilesState = async (paths: string[]) => {
1682+
return (
1683+
await Promise.all(
1684+
paths.map((path) =>
1685+
fs.stat(path).then(
1686+
() => 1,
1687+
() => 0
1688+
)
1689+
)
1690+
)
1691+
).join('');
1692+
};
1693+
1694+
describe('with custom log retention days', function () {
1695+
const customLogDir = useTmpdir();
1696+
1697+
it('should delete older files according to the setting', async function () {
1698+
const paths: string[] = [];
1699+
const today = Math.floor(Date.now() / 1000);
1700+
const tenDaysAgo = today - 10 * 24 * 60 * 60;
1701+
// Create 6 files older than 7 days
1702+
for (let i = 5; i >= 0; i--) {
1703+
const filename = path.join(
1704+
customLogDir.path,
1705+
ObjectId.createFromTime(tenDaysAgo - i).toHexString() + '_log'
1706+
);
1707+
await fs.writeFile(filename, '');
1708+
paths.push(filename);
1709+
}
1710+
// Create 4 files newer than 10 days
1711+
for (let i = 3; i >= 0; i--) {
1712+
const filename = path.join(
1713+
customLogDir.path,
1714+
ObjectId.createFromTime(today - i).toHexString() + '_log'
1715+
);
1716+
await fs.writeFile(filename, '');
1717+
paths.push(filename);
1718+
}
1719+
1720+
const retentionDays = 7;
1721+
1722+
const globalConfig = path.join(homedir, 'globalconfig.conf');
1723+
await fs.writeFile(
1724+
globalConfig,
1725+
`mongosh:\n logLocation: ${JSON.stringify(
1726+
customLogDir.path
1727+
)}\n logRetentionDays: ${retentionDays}`
1728+
);
1729+
1730+
expect(await getFilesState(paths)).equals('1111111111');
1731+
1732+
shell = this.startTestShell({
1733+
args: ['--nodb'],
1734+
env: {
1735+
...env,
1736+
MONGOSH_GLOBAL_CONFIG_FILE_FOR_TESTING: globalConfig,
1737+
},
1738+
forceTerminal: true,
1739+
});
1740+
1741+
await shell.waitForPrompt();
1742+
1743+
// Add the newly created log file
1744+
paths.push(path.join(customLogDir.path, `${shell.logId}_log`));
1745+
// Expect 6 files to be deleted and 5 to remain (including the new log file)
1746+
expect(await getFilesState(paths)).equals('00000011111');
1747+
});
1748+
});
1749+
16791750
it('creates a log file that keeps track of session events', async function () {
16801751
expect(await shell.executeLine('print(123 + 456)')).to.include('579');
16811752
const log = await readLogFile();

packages/types/src/index.spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ describe('config validation', function () {
2525
expect(await validate('historyLength', 0)).to.equal(null);
2626
expect(await validate('historyLength', 1)).to.equal(null);
2727
expect(await validate('historyLength', Infinity)).to.equal(null);
28+
expect(await validate('logRetentionDays', 'foo')).to.equal(
29+
'logRetentionDays must be a positive integer'
30+
);
31+
expect(await validate('logRetentionDays', -1)).to.equal(
32+
'logRetentionDays must be a positive integer'
33+
);
2834
expect(await validate('showStackTraces', 'foo')).to.equal(
2935
'showStackTraces must be a boolean'
3036
);

packages/types/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ export class CliUserConfig extends SnippetShellUserConfig {
509509
updateURL = 'https://downloads.mongodb.com/compass/mongosh.json';
510510
disableLogging = false;
511511
logLocation: string | undefined = undefined;
512+
logRetentionDays = 30;
512513
}
513514

514515
export class CliUserConfigValidator extends SnippetShellUserConfigValidator {
@@ -531,6 +532,7 @@ export class CliUserConfigValidator extends SnippetShellUserConfigValidator {
531532
return null;
532533
case 'inspectDepth':
533534
case 'historyLength':
535+
case 'logRetentionDays':
534536
if (typeof value !== 'number' || value < 0) {
535537
return `${key} must be a positive integer`;
536538
}

0 commit comments

Comments
 (0)