Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
54 changes: 54 additions & 0 deletions packages/mongodb-log-writer/src/mongo-log-manager.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { MongoLogManager, mongoLogId } from '.';
import { ObjectId } from 'bson';
import { once } from 'events';
import type { Stats } from 'fs';
import { promises as fs } from 'fs';
import path from 'path';
import os from 'os';
Expand All @@ -27,6 +28,7 @@ describe('MongoLogManager', function () {
});
afterEach(async function () {
await fs.rmdir(directory, { recursive: true });
sinon.restore();
});

it('allows creating and writing to log files', async function () {
Expand Down Expand Up @@ -124,6 +126,58 @@ describe('MongoLogManager', function () {
expect(await getFilesState(paths)).to.equal('0000011111');
});

it('if fs.stat fails, it errors and is not considered towards the logs limit', async function () {
const manager = new MongoLogManager({
directory,
retentionDays,
retentionGB: 3,
onwarn,
onerror,
});

const offset = Math.floor(Date.now() / 1000);

const faultyFile = path.join(
directory,
ObjectId.createFromTime(offset - 10).toHexString() + '_log'
);
await fs.writeFile(faultyFile, '');

const faultyFileError = new Error('test error');

const validFiles: string[] = [];
// Create 5 valid files.
for (let i = 5; i >= 0; i--) {
const filename = path.join(
directory,
ObjectId.createFromTime(offset - i).toHexString() + '_log'
);
await fs.writeFile(filename, '');
validFiles.push(filename);
}

expect(onerror).not.called;

const fsStatStub = sinon.stub(fs, 'stat');

fsStatStub.resolves({
size: 1024 * 1024 * 1024,
} as Stats);
fsStatStub.withArgs(faultyFile).rejects(faultyFileError);

await manager.cleanupOldLogFiles();

expect(onerror).calledOnceWithExactly(faultyFileError, faultyFile);

// fs.stat is stubbed so getFilesState will not be accurate.
const leftoverFiles = (await fs.readdir(directory))
.sort()
.map((file) => path.join(directory, file));

expect(leftoverFiles).to.have.lengthOf(4);
expect(leftoverFiles).deep.equals([faultyFile, ...validFiles.slice(3)]);
});

it('cleans up least recent log files when requested with a storage limit', async function () {
const manager = new MongoLogManager({
directory,
Expand Down
16 changes: 12 additions & 4 deletions packages/mongodb-log-writer/src/mongo-log-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ interface MongoLogOptions {
maxLogFileCount?: number;
/** The maximal GB of log files which are kept. */
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/** The maximal GB of log files which are kept. */
/** The maximal size of log files which are kept. */

retentionGB?: number;
/** A handler for warnings related to a specific filesystem path. */
onerror: (err: Error, path: string) => unknown | Promise<void>;
/** A handler for errors related to a specific filesystem path. */
onerror: (err: Error, path: string) => unknown | Promise<void>;
/** A handler for warnings related to a specific filesystem path. */
onwarn: (err: Error, path: string) => unknown | Promise<void>;
}

Expand Down Expand Up @@ -94,9 +94,17 @@ export class MongoLogManager {
fullPath,
};
} else if (this._options.retentionGB || this._options.maxLogFileCount) {
const fileSize = (await fs.stat(fullPath)).size;
let fileSize: number | undefined;

if (this._options.retentionGB) {
usedStorageSize += fileSize;
try {
fileSize = (await fs.stat(fullPath)).size;
if (this._options.retentionGB) {
usedStorageSize += fileSize;
}
} catch (err) {
this._options.onerror(err as Error, fullPath);
}
}

leastRecentFileHeap.push({
Expand Down
Loading