Skip to content

Commit 5af51d3

Browse files
authored
feat(logger): make loglevel types stricter (#1313)
* feat: make loglevel types stricter * test: added unit test * refactor: logLevel types
1 parent 919853e commit 5af51d3

File tree

5 files changed

+68
-28
lines changed

5 files changed

+68
-28
lines changed

Diff for: packages/logger/src/Logger.ts

+32-21
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ class Logger extends Utility implements ClassThatLogs {
117117

118118
private customConfigService?: ConfigServiceInterface;
119119

120-
private static readonly defaultLogLevel: LogLevel = 'INFO';
120+
private static readonly defaultLogLevel: Uppercase<LogLevel> = 'INFO';
121121

122122
// envVarsService is always initialized in the constructor in setOptions()
123123
private envVarsService!: EnvironmentVariablesService;
@@ -128,7 +128,7 @@ class Logger extends Utility implements ClassThatLogs {
128128

129129
private logIndentation: number = LogJsonIndent.COMPACT;
130130

131-
private logLevel?: LogLevel;
131+
private logLevel?: Uppercase<LogLevel>;
132132

133133
private readonly logLevelThresholds: LogLevelThresholds = {
134134
DEBUG: 8,
@@ -554,12 +554,16 @@ class Logger extends Utility implements ClassThatLogs {
554554

555555
/**
556556
* It returns the log level set for the Logger instance.
557+
*
558+
* Even though logLevel starts as undefined, it will always be set to a value
559+
* during the Logger instance's initialization. So, we can safely use the non-null
560+
* assertion operator here.
557561
*
558562
* @private
559563
* @returns {LogLevel}
560564
*/
561-
private getLogLevel(): LogLevel {
562-
return <LogLevel> this.logLevel;
565+
private getLogLevel(): Uppercase<LogLevel> {
566+
return this.logLevel!;
563567
}
564568

565569
/**
@@ -619,14 +623,14 @@ class Logger extends Utility implements ClassThatLogs {
619623
}
620624

621625
/**
622-
* It returns true if the provided log level is valid.
626+
* It returns true and type guards the log level if a given log level is valid.
623627
*
624628
* @param {LogLevel} logLevel
625629
* @private
626630
* @returns {boolean}
627631
*/
628-
private isValidLogLevel(logLevel?: LogLevel): boolean {
629-
return typeof logLevel === 'string' && logLevel.toUpperCase() in this.logLevelThresholds;
632+
private isValidLogLevel(logLevel?: LogLevel | string): logLevel is Uppercase<LogLevel> {
633+
return typeof logLevel === 'string' && logLevel in this.logLevelThresholds;
630634
}
631635

632636
/**
@@ -647,11 +651,12 @@ class Logger extends Utility implements ClassThatLogs {
647651
/**
648652
* It prints a given log with given log level.
649653
*
650-
* @param {LogLevel} logLevel
651-
* @param {LogItem} log
654+
* @param {Uppercase<LogLevel>} logLevel
655+
* @param {LogItemMessage} input
656+
* @param {LogItemExtraInput} extraInput
652657
* @private
653658
*/
654-
private processLogItem(logLevel: LogLevel, input: LogItemMessage, extraInput: LogItemExtraInput): void {
659+
private processLogItem(logLevel: Uppercase<LogLevel>, input: LogItemMessage, extraInput: LogItemExtraInput): void {
655660
if (!this.shouldPrint(logLevel)) {
656661
return;
657662
}
@@ -743,20 +748,25 @@ class Logger extends Utility implements ClassThatLogs {
743748
* @returns {void}
744749
*/
745750
private setLogLevel(logLevel?: LogLevel): void {
746-
if (this.isValidLogLevel(logLevel)) {
747-
this.logLevel = (<LogLevel>logLevel).toUpperCase();
751+
const constructorLogLevel = logLevel?.toUpperCase();
752+
if (this.isValidLogLevel(constructorLogLevel)) {
753+
this.logLevel = constructorLogLevel;
748754

749755
return;
750756
}
751-
const customConfigValue = this.getCustomConfigService()?.getLogLevel();
757+
const customConfigValue = this.getCustomConfigService()
758+
?.getLogLevel()
759+
?.toUpperCase();
752760
if (this.isValidLogLevel(customConfigValue)) {
753-
this.logLevel = (<LogLevel>customConfigValue).toUpperCase();
761+
this.logLevel = customConfigValue;
754762

755763
return;
756764
}
757-
const envVarsValue = this.getEnvVarsService().getLogLevel();
765+
const envVarsValue = this.getEnvVarsService()
766+
?.getLogLevel()
767+
?.toUpperCase();
758768
if (this.isValidLogLevel(envVarsValue)) {
759-
this.logLevel = (<LogLevel>envVarsValue).toUpperCase();
769+
this.logLevel = envVarsValue;
760770

761771
return;
762772
}
@@ -845,14 +855,15 @@ class Logger extends Utility implements ClassThatLogs {
845855
/**
846856
* It checks whether the current log item should/can be printed.
847857
*
848-
* @param {string} serviceName
849-
* @param {Environment} environment
850-
* @param {LogAttributes} persistentLogAttributes
858+
* @param {Uppercase<LogLevel>} logLevel
851859
* @private
852860
* @returns {boolean}
853861
*/
854-
private shouldPrint(logLevel: LogLevel): boolean {
855-
if (this.logLevelThresholds[logLevel] >= this.logLevelThresholds[this.getLogLevel()]) {
862+
private shouldPrint(logLevel: Uppercase<LogLevel>): boolean {
863+
if (
864+
this.logLevelThresholds[logLevel] >=
865+
this.logLevelThresholds[this.getLogLevel()]
866+
) {
856867
return true;
857868
}
858869

Diff for: packages/logger/src/types/Log.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ type LogLevelInfo = 'INFO';
33
type LogLevelWarn = 'WARN';
44
type LogLevelError = 'ERROR';
55

6-
type LogLevel = LogLevelDebug | LogLevelInfo | LogLevelWarn | LogLevelError | string;
6+
type LogLevel = LogLevelDebug | Lowercase<LogLevelDebug> | LogLevelInfo | Lowercase<LogLevelInfo> | LogLevelWarn | Lowercase<LogLevelWarn> | LogLevelError | Lowercase<LogLevelError>;
77

88
type LogLevelThresholds = {
9-
[key in LogLevel]: number;
9+
[key in Uppercase<LogLevel>]: number;
1010
};
1111

1212
type LogAttributeValue = unknown;

Diff for: packages/logger/tests/unit/Logger.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1486,7 +1486,7 @@ describe('Class: Logger', () => {
14861486
};
14871487
const childLoggerWithSampleRateEnabled = parentLogger.createChild(optionsWithSampleRateEnabled);
14881488

1489-
const optionsWithErrorLogLevel = {
1489+
const optionsWithErrorLogLevel: ConstructorOptions = {
14901490
logLevel: 'ERROR',
14911491
};
14921492
const childLoggerWithErrorLogLevel = parentLogger.createChild(optionsWithErrorLogLevel);

Diff for: packages/logger/tests/unit/formatter/PowertoolLogFormatter.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ describe('Class: PowertoolLogFormatter', () => {
2222

2323
// Prepare
2424
const formatter = new PowertoolLogFormatter();
25-
const unformattedAttributes = {
25+
const unformattedAttributes: UnformattedAttributes = {
2626
sampleRateValue: undefined,
2727
awsRegion: 'eu-west-1',
2828
environment: '',

Diff for: packages/logger/tests/unit/helpers.test.ts

+32-3
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ describe('Helper: createLogger function', () => {
5555
test('when no parameters are set, returns a Logger instance with the correct properties', () => {
5656

5757
// Prepare
58-
const loggerOptions = {
58+
const loggerOptions: ConstructorOptions = {
5959
logLevel: 'WARN',
6060
serviceName: 'my-lambda-service',
6161
sampleRateValue: 1,
@@ -199,10 +199,10 @@ describe('Helper: createLogger function', () => {
199199

200200
});
201201

202-
test('when a custom logLevel is passed, returns a Logger instance with the correct properties', () => {
202+
test('when a custom uppercase logLevel is passed, returns a Logger instance with the correct properties', () => {
203203

204204
// Prepare
205-
const loggerOptions:ConstructorOptions = {
205+
const loggerOptions: ConstructorOptions = {
206206
logLevel: 'ERROR',
207207
};
208208

@@ -227,6 +227,35 @@ describe('Helper: createLogger function', () => {
227227
}));
228228

229229
});
230+
231+
test('when a custom lowercase logLevel is passed, returns a Logger instance with the correct properties', () => {
232+
233+
// Prepare
234+
const loggerOptions: ConstructorOptions = {
235+
logLevel: 'warn',
236+
};
237+
238+
// Act
239+
const logger = createLogger(loggerOptions);
240+
241+
// Assess
242+
expect(logger).toBeInstanceOf(Logger);
243+
expect(logger).toEqual(expect.objectContaining({
244+
logsSampled: false,
245+
persistentLogAttributes: {},
246+
powertoolLogData: {
247+
sampleRateValue: undefined,
248+
awsRegion: 'eu-west-1',
249+
environment: '',
250+
serviceName: 'hello-world',
251+
},
252+
envVarsService: expect.any(EnvironmentVariablesService),
253+
customConfigService: undefined,
254+
logLevel: 'WARN',
255+
logFormatter: expect.any(PowertoolLogFormatter),
256+
}));
257+
258+
});
230259

231260
test('when no log level is set, returns a Logger instance with INFO level', () => {
232261

0 commit comments

Comments
 (0)