Skip to content

Commit eb7d6fe

Browse files
authored
Merge pull request #542 from forcedotcom/ew/rotating-log-file-v3
Rotating file logs V3
2 parents e2d689b + ef5df25 commit eb7d6fe

File tree

4 files changed

+80
-11
lines changed

4 files changed

+80
-11
lines changed

messages/envVars.md

+16
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,14 @@ Set to true to send messages resulting from failed Salesforce CLI commands to st
9494

9595
Level of messages that the CLI writes to the log file. Valid values are trace, debug, info, warn, error, fatal. Default value is warn.
9696

97+
# sfdxLogRotationCount
98+
99+
The default rotation period for logs. Example '1d' will rotate logs daily (at midnight).
100+
101+
# sfdxLogRotationPeriod
102+
103+
The number of backup rotated log files to keep. Example: '3' will have the base sf.log file, and the past 3 (period) log files.
104+
97105
# sfdxMaxQueryLimit
98106

99107
Maximum number of Salesforce records returned by a CLI command. Default value is 10,000. Overrides the maxQueryLimit configuration value.
@@ -222,6 +230,14 @@ Set to true to send messages resulting from failed Salesforce CLI commands to st
222230

223231
Level of messages that the CLI writes to the log file. Valid values are trace, debug, info, warn, error, fatal. Default value is warn.
224232

233+
# sfLogRotationCount
234+
235+
The default rotation period for logs. Example '1d' will rotate logs daily (at midnight).
236+
237+
# sfLogRotationPeriod
238+
239+
The number of backup rotated log files to keep. Example: '3' will have the base sf.log file, and the past 3 (period) log files.
240+
225241
# sfMaxQueryLimit
226242

227243
Maximum number of Salesforce records returned by a CLI command. Default value is 10,000. Overrides the maxQueryLimit configuration variable.

src/config/envVars.ts

+20
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ export enum EnvironmentVariable {
3838
'SFDX_INSTANCE_URL' = 'SFDX_INSTANCE_URL',
3939
'SFDX_JSON_TO_STDOUT' = 'SFDX_JSON_TO_STDOUT',
4040
'SFDX_LOG_LEVEL' = 'SFDX_LOG_LEVEL',
41+
'SFDX_LOG_ROTATION_COUNT' = 'SFDX_LOG_ROTATION_COUNT',
42+
'SFDX_LOG_ROTATION_PERIOD' = 'SFDX_LOG_ROTATION_PERIOD',
4143
'SFDX_MAX_QUERY_LIMIT' = 'SFDX_MAX_QUERY_LIMIT',
4244
'SFDX_MDAPI_TEMP_DIR' = 'SFDX_MDAPI_TEMP_DIR',
4345
'SFDX_NPM_REGISTRY' = 'SFDX_NPM_REGISTRY',
@@ -70,6 +72,8 @@ export enum EnvironmentVariable {
7072
'SF_INSTANCE_URL' = 'SF_INSTANCE_URL',
7173
'SF_JSON_TO_STDOUT' = 'SF_JSON_TO_STDOUT',
7274
'SF_LOG_LEVEL' = 'SF_LOG_LEVEL',
75+
'SF_LOG_ROTATION_COUNT' = 'SF_LOG_ROTATION_COUNT',
76+
'SF_LOG_ROTATION_PERIOD' = 'SF_LOG_ROTATION_PERIOD',
7377
'SF_MAX_QUERY_LIMIT' = 'SF_MAX_QUERY_LIMIT',
7478
'SF_MDAPI_TEMP_DIR' = 'SF_MDAPI_TEMP_DIR',
7579
'SF_NPM_REGISTRY' = 'SF_NPM_REGISTRY',
@@ -195,6 +199,14 @@ export const SUPPORTED_ENV_VARS: EnvType = {
195199
description: getMessage(EnvironmentVariable.SFDX_LOG_LEVEL),
196200
synonymOf: EnvironmentVariable.SF_LOG_LEVEL,
197201
},
202+
[EnvironmentVariable.SFDX_LOG_ROTATION_COUNT]: {
203+
description: getMessage(EnvironmentVariable.SFDX_LOG_ROTATION_COUNT),
204+
synonymOf: EnvironmentVariable.SF_LOG_ROTATION_COUNT,
205+
},
206+
[EnvironmentVariable.SFDX_LOG_ROTATION_PERIOD]: {
207+
description: getMessage(EnvironmentVariable.SFDX_LOG_ROTATION_PERIOD),
208+
synonymOf: EnvironmentVariable.SF_LOG_ROTATION_PERIOD,
209+
},
198210
[EnvironmentVariable.SFDX_MAX_QUERY_LIMIT]: {
199211
description: getMessage(EnvironmentVariable.SFDX_MAX_QUERY_LIMIT),
200212
synonymOf: EnvironmentVariable.SF_MAX_QUERY_LIMIT,
@@ -326,6 +338,14 @@ export const SUPPORTED_ENV_VARS: EnvType = {
326338
description: getMessage(EnvironmentVariable.SF_LOG_LEVEL),
327339
synonymOf: null,
328340
},
341+
[EnvironmentVariable.SF_LOG_ROTATION_COUNT]: {
342+
description: getMessage(EnvironmentVariable.SF_LOG_ROTATION_COUNT),
343+
synonymOf: null,
344+
},
345+
[EnvironmentVariable.SF_LOG_ROTATION_PERIOD]: {
346+
description: getMessage(EnvironmentVariable.SF_LOG_ROTATION_PERIOD),
347+
synonymOf: null,
348+
},
329349
[EnvironmentVariable.SF_MAX_QUERY_LIMIT]: {
330350
description: getMessage(EnvironmentVariable.SF_MAX_QUERY_LIMIT),
331351
synonymOf: null,

src/logger.ts

+24-9
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import * as fs from 'fs';
1212
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
1313
// @ts-ignore
1414
import * as Bunyan from '@salesforce/bunyan';
15-
import { parseJson, parseJsonMap } from '@salesforce/kit';
15+
import { Env, parseJson, parseJsonMap } from '@salesforce/kit';
1616
import {
1717
Dictionary,
1818
ensure,
@@ -221,6 +221,21 @@ export class Logger {
221221
// The sfdx root logger singleton
222222
private static rootLogger?: Logger;
223223

224+
/**
225+
* The default rotation period for logs. Example '1d' will rotate logs daily (at midnight).
226+
* See 'period' docs here: https://github.com/forcedotcom/node-bunyan#stream-type-rotating-file
227+
*/
228+
229+
public readonly logRotationPeriod = new Env().getString('SF_LOG_ROTATION_PERIOD') || '1d';
230+
231+
/**
232+
* The number of backup rotated log files to keep.
233+
* Example: '3' will have the base sf.log file, and the past 3 (period) log files.
234+
* See 'count' docs here: https://github.com/forcedotcom/node-bunyan#stream-type-rotating-file
235+
*/
236+
237+
public readonly logRotationCount = new Env().getNumber('SF_LOG_ROTATION_COUNT') || 2;
238+
224239
/**
225240
* Whether debug is enabled for this Logger.
226241
*/
@@ -418,14 +433,14 @@ export class Logger {
418433
!this.bunyan.streams.find(
419434
// No bunyan typings
420435
// eslint-disable-next-line @typescript-eslint/no-explicit-any
421-
(stream: any) => stream.type === 'file' && stream.path === logFile
436+
(stream: any) => stream.type === 'rotating-file' && stream.path === logFile
422437
)
423438
) {
424-
// TODO: rotating-file
425-
// https://github.com/trentm/node-bunyan#stream-type-rotating-file
426439
this.addStream({
427-
type: 'file',
440+
type: 'rotating-file',
428441
path: logFile,
442+
period: this.logRotationPeriod,
443+
count: this.logRotationCount,
429444
level: this.bunyan.level() as number,
430445
});
431446
}
@@ -460,14 +475,14 @@ export class Logger {
460475
!this.bunyan.streams.find(
461476
// No bunyan typings
462477
// eslint-disable-next-line @typescript-eslint/no-explicit-any
463-
(stream: any) => stream.type === 'file' && stream.path === logFile
478+
(stream: any) => stream.type === 'rotating-file' && stream.path === logFile
464479
)
465480
) {
466-
// TODO: rotating-file
467-
// https://github.com/trentm/node-bunyan#stream-type-rotating-file
468481
this.addStream({
469-
type: 'file',
482+
type: 'rotating-file',
470483
path: logFile,
484+
period: this.logRotationPeriod,
485+
count: this.logRotationCount,
471486
level: this.bunyan.level() as number,
472487
});
473488
}

test/unit/loggerTest.ts

+20-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ const $$ = testSetup();
2020

2121
describe('Logger', () => {
2222
const sfdxEnv = process.env.SFDX_ENV;
23+
const logRotationPeriodBackup = process.env.SF_LOG_ROTATION_PERIOD;
24+
const logRotationCountBackup = process.env.SF_LOG_ROTATION_COUNT;
2325

2426
beforeEach(async () => {
2527
process.env.SFDX_ENV = 'test';
@@ -32,7 +34,9 @@ describe('Logger', () => {
3234

3335
afterEach(() => {
3436
Logger.destroyRoot();
35-
process.env.SFDX_ENV = sfdxEnv;
37+
if (sfdxEnv) process.env.SFDX_ENV = sfdxEnv;
38+
if (logRotationPeriodBackup) process.env.SF_LOG_ROTATION_PERIOD = logRotationPeriodBackup;
39+
if (logRotationCountBackup) process.env.SF_LOG_ROTATION_COUNT = logRotationCountBackup;
3640
});
3741

3842
describe('constructor', () => {
@@ -110,11 +114,25 @@ describe('Logger', () => {
110114
expect(utilAccessStub.firstCall.args[0]).to.equal(testLogFile);
111115
expect(utilWriteFileStub.called).to.be.false;
112116
const addStreamArgs = addStreamStub.firstCall.args[0];
113-
expect(addStreamArgs).to.have.property('type', 'file');
117+
expect(addStreamArgs).to.have.property('type', 'rotating-file');
114118
expect(addStreamArgs).to.have.property('path', testLogFile);
115119
expect(addStreamArgs).to.have.property('level', logger.getLevel());
116120
});
117121

122+
it('should allow log rotation count and period overrides', async () => {
123+
process.env.SF_LOG_ROTATION_PERIOD = '1w';
124+
process.env.SF_LOG_ROTATION_COUNT = '3';
125+
126+
utilAccessStub.returns(Promise.resolve({}));
127+
const logger = new Logger('testing-env-vars');
128+
const addStreamStub = $$.SANDBOX.stub(logger, 'addStream');
129+
await logger.addLogFileStream(testLogFile);
130+
131+
const addStreamArgs = addStreamStub.firstCall.args[0];
132+
expect(addStreamArgs).to.have.property('period', '1w');
133+
expect(addStreamArgs).to.have.property('count', 3);
134+
});
135+
118136
it('should create a new log file and all directories if nonexistent', async () => {
119137
utilAccessStub.throws();
120138
const logger = new Logger('testLogger');

0 commit comments

Comments
 (0)