Skip to content

Commit 6107eea

Browse files
authored
feat(cli-repl): add configuration to set max log files size MONGOSH-1985 (#2361)
1 parent a5e517c commit 6107eea

File tree

9 files changed

+131
-13
lines changed

9 files changed

+131
-13
lines changed

package-lock.json

Lines changed: 41 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/cli-repl/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
"is-recoverable-error": "^1.0.3",
8686
"js-yaml": "^4.1.0",
8787
"mongodb-connection-string-url": "^3.0.1",
88-
"mongodb-log-writer": "^2.1.0",
88+
"mongodb-log-writer": "^2.3.0",
8989
"numeral": "^2.0.6",
9090
"pretty-repl": "^4.0.1",
9191
"semver": "^7.5.4",

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ describe('CliRepl', function () {
326326
'logRetentionDays',
327327
'logMaxFileCount',
328328
'logCompressionEnabled',
329+
'logRetentionGB',
329330
] satisfies (keyof CliUserConfig)[]);
330331
});
331332

@@ -1460,6 +1461,19 @@ describe('CliRepl', function () {
14601461
);
14611462
});
14621463

1464+
it('can set log retention GB', async function () {
1465+
const testLogRetentionGB = 10;
1466+
cliRepl.config.logRetentionGB = testLogRetentionGB;
1467+
await cliRepl.start(await testServer.connectionString(), {});
1468+
1469+
expect(await cliRepl.getConfig('logRetentionGB')).equals(
1470+
testLogRetentionGB
1471+
);
1472+
expect(cliRepl.logManager?._options.retentionGB).equals(
1473+
testLogRetentionGB
1474+
);
1475+
});
1476+
14631477
it('can set log max file count', async function () {
14641478
const testMaxFileCount = 123;
14651479
cliRepl.config.logMaxFileCount = testMaxFileCount;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ export class CliRepl implements MongoshIOProvider {
262262
retentionDays: await this.getConfig('logRetentionDays'),
263263
gzip: await this.getConfig('logCompressionEnabled'),
264264
maxLogFileCount: await this.getConfig('logMaxFileCount'),
265+
retentionGB: await this.getConfig('logRetentionGB'),
265266
onerror: (err: Error) => this.bus.emit('mongosh:error', err, 'log'),
266267
onwarn: (err: Error, path: string) =>
267268
this.warnAboutInaccessibleFile(err, path),

packages/e2e-tests/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"strip-ansi": "^6.0.0"
3434
},
3535
"devDependencies": {
36-
"mongodb-log-writer": "^2.1.0",
36+
"mongodb-log-writer": "^2.3.0",
3737
"@mongodb-js/eslint-config-mongosh": "^1.0.0",
3838
"@mongodb-js/oidc-mock-provider": "^0.10.2",
3939
"@mongodb-js/prettier-config-devtools": "^1.0.1",

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

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,15 +1581,15 @@ describe('e2e', function () {
15811581
await shell.waitForPrompt();
15821582
shell.assertContainsOutput('Ignoring config option "logLocation"');
15831583
shell.assertContainsOutput(
1584-
'must be a valid absolute path or empty'
1584+
'must be a valid absolute path or undefined'
15851585
);
15861586

15871587
expect(
15881588
await shell.executeLine(
15891589
'config.set("logLocation", "[123123123123]")'
15901590
)
15911591
).contains(
1592-
'Cannot set option "logLocation": logLocation must be a valid absolute path or empty'
1592+
'Cannot set option "logLocation": logLocation must be a valid absolute path or undefined'
15931593
);
15941594
});
15951595

@@ -1722,10 +1722,10 @@ describe('e2e', function () {
17221722
});
17231723
});
17241724

1725-
describe('with custom log retention days', function () {
1725+
describe('with logRetentionDays', function () {
17261726
const customLogDir = useTmpdir();
17271727

1728-
it('should delete older files according to the setting', async function () {
1728+
it('should delete older files older than logRetentionDays', async function () {
17291729
const paths: string[] = [];
17301730
const today = Math.floor(Date.now() / 1000);
17311731
const tenDaysAgo = today - 10 * 24 * 60 * 60;
@@ -1776,10 +1776,10 @@ describe('e2e', function () {
17761776
});
17771777
});
17781778

1779-
describe('with custom log retention max file count', function () {
1779+
describe('with logMaxFileCount', function () {
17801780
const customLogDir = useTmpdir();
17811781

1782-
it('should delete files once it is above the max file count limit', async function () {
1782+
it('should delete files once it is above logMaxFileCount', async function () {
17831783
const globalConfig = path.join(homedir, 'globalconfig.conf');
17841784
await fs.writeFile(
17851785
globalConfig,
@@ -1825,6 +1825,57 @@ describe('e2e', function () {
18251825
});
18261826
});
18271827

1828+
describe('with logRetentionGB', function () {
1829+
const customLogDir = useTmpdir();
1830+
1831+
it('should delete files once it is above logRetentionGB', async function () {
1832+
const globalConfig = path.join(homedir, 'globalconfig.conf');
1833+
await fs.writeFile(
1834+
globalConfig,
1835+
// Set logRetentionGB to 4 MB and we will create prior 10 log files, 1 MB each
1836+
`mongosh:\n logLocation: ${JSON.stringify(
1837+
customLogDir.path
1838+
)}\n logRetentionGB: ${4 / 1024}`
1839+
);
1840+
const paths: string[] = [];
1841+
const offset = Math.floor(Date.now() / 1000);
1842+
1843+
// Create 10 log files, around 1 mb each
1844+
for (let i = 9; i >= 0; i--) {
1845+
const filename = path.join(
1846+
customLogDir.path,
1847+
ObjectId.createFromTime(offset - i).toHexString() + '_log'
1848+
);
1849+
await fs.writeFile(filename, '0'.repeat(1024 * 1024));
1850+
paths.push(filename);
1851+
}
1852+
1853+
// All 10 existing log files exist.
1854+
expect(await getFilesState(paths)).to.equal('1111111111');
1855+
shell = this.startTestShell({
1856+
args: ['--nodb'],
1857+
env,
1858+
globalConfigPath: globalConfig,
1859+
forceTerminal: true,
1860+
});
1861+
1862+
await shell.waitForPrompt();
1863+
1864+
// Add the newly created log to the file list.
1865+
paths.push(
1866+
path.join(customLogDir.path, `${shell.logId as string}_log`)
1867+
);
1868+
1869+
expect(
1870+
await shell.executeLine('config.get("logRetentionGB")')
1871+
).contains(`${4 / 1024}`);
1872+
1873+
// Expect 6 files to be deleted and 4 to remain
1874+
// (including the new log file which should be <1 MB)
1875+
expect(await getFilesState(paths)).to.equal('00000001111');
1876+
});
1877+
});
1878+
18281879
it('creates a log file that keeps track of session events', async function () {
18291880
expect(await shell.executeLine('print(123 + 456)')).to.include('579');
18301881
const log = await readLogFile();

packages/logging/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"@mongosh/errors": "2.4.0",
2222
"@mongosh/history": "2.4.2",
2323
"@mongosh/types": "3.2.0",
24-
"mongodb-log-writer": "^2.1.0",
24+
"mongodb-log-writer": "^2.3.0",
2525
"mongodb-redact": "^1.1.5"
2626
},
2727
"devDependencies": {

packages/types/src/index.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ describe('config validation', function () {
3131
expect(await validate('logRetentionDays', -1)).to.equal(
3232
'logRetentionDays must be a positive integer'
3333
);
34+
expect(await validate('logRetentionGB', 'foo')).to.equal(
35+
'logRetentionGB must be a positive number or undefined'
36+
);
37+
expect(await validate('logRetentionGB', -1)).to.equal(
38+
'logRetentionGB must be a positive number or undefined'
39+
);
40+
expect(await validate('logRetentionGB', undefined)).to.equal(null);
41+
expect(await validate('logRetentionGB', 100)).to.equal(null);
3442
expect(await validate('logMaxFileCount', 'foo')).to.equal(
3543
'logMaxFileCount must be a positive integer'
3644
);

packages/types/src/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@ export class CliUserConfig extends SnippetShellUserConfig {
515515
logRetentionDays = 30;
516516
logMaxFileCount = 100;
517517
logCompressionEnabled = false;
518+
logRetentionGB: number | undefined = undefined;
518519
}
519520

520521
export class CliUserConfigValidator extends SnippetShellUserConfigValidator {
@@ -543,6 +544,11 @@ export class CliUserConfigValidator extends SnippetShellUserConfigValidator {
543544
return `${key} must be a positive integer`;
544545
}
545546
return null;
547+
case 'logRetentionGB':
548+
if (value !== undefined && (typeof value !== 'number' || value < 0)) {
549+
return `${key} must be a positive number or undefined`;
550+
}
551+
return null;
546552
case 'disableLogging':
547553
case 'forceDisableTelemetry':
548554
case 'showStackTraces':
@@ -595,7 +601,7 @@ export class CliUserConfigValidator extends SnippetShellUserConfigValidator {
595601
value !== undefined &&
596602
(typeof value !== 'string' || !path.isAbsolute(value))
597603
) {
598-
return `${key} must be a valid absolute path or empty`;
604+
return `${key} must be a valid absolute path or undefined`;
599605
}
600606
return null;
601607
default:

0 commit comments

Comments
 (0)