Skip to content

fix(logger): display correct log level in cloudwatch #386

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
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
72 changes: 40 additions & 32 deletions packages/logger/src/Logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,11 @@ class Logger implements ClassThatLogs {
}

public debug(input: LogItemMessage, ...extraInput: LogItemExtraInput): void {
if (!this.shouldPrint('DEBUG')) {
return;
}
this.printLog(this.createAndPopulateLogItem('DEBUG', input, extraInput));
this.processLogItem('DEBUG', input, extraInput);
Copy link
Contributor Author

@saragerion saragerion Jan 3, 2022

Choose a reason for hiding this comment

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

Housekeeping: removed unnecessary code duplication

}

public error(input: LogItemMessage, ...extraInput: LogItemExtraInput): void {
this.printLog(this.createAndPopulateLogItem('ERROR', input, extraInput));
this.processLogItem('ERROR', input, extraInput);
}

public static evaluateColdStartOnce(): void {
Expand All @@ -110,10 +107,7 @@ class Logger implements ClassThatLogs {
}

public info(input: LogItemMessage, ...extraInput: LogItemExtraInput): void {
if (!this.shouldPrint('INFO')) {
return;
}
this.printLog(this.createAndPopulateLogItem('INFO', input, extraInput));
this.processLogItem('INFO', input, extraInput);
}

public injectLambdaContext(): HandlerMethodDecorator {
Expand Down Expand Up @@ -149,10 +143,7 @@ class Logger implements ClassThatLogs {
}

public warn(input: LogItemMessage, ...extraInput: LogItemExtraInput): void {
if (!this.shouldPrint('WARN')) {
return;
}
this.printLog(this.createAndPopulateLogItem('WARN', input, extraInput));
this.processLogItem('WARN', input, extraInput);
}

private addToPowertoolLogData(...attributesArray: Array<Partial<PowertoolLogData>>): void {
Expand Down Expand Up @@ -234,29 +225,46 @@ class Logger implements ClassThatLogs {
return typeof logLevel === 'string' && logLevel.toUpperCase() in this.logLevelThresholds;
}

private printLog(log: LogItem): void {
private printLog(logLevel: LogLevel, log: LogItem): void {
log.prepareForPrint();

const consoleMethod = logLevel.toLowerCase() as keyof ClassThatLogs;

console[consoleMethod](JSON.stringify(log.getAttributes(), this.removeCircularDependencies()));
Copy link
Contributor Author

@saragerion saragerion Jan 3, 2022

Choose a reason for hiding this comment

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

Here I:

  • Removed the JSON parse step so that the log items will be displayed more nicely (green coloured values) in cloudwatch (see image)
  • Moved the circular reference logic to its own method so make it easier to read, adding relevant jsdocs documentation and separate responsibilities

Screenshot 2022-01-03 at 18 34 29

}

private processLogItem(logLevel: LogLevel, input: LogItemMessage, extraInput: LogItemExtraInput): void {
if (!this.shouldPrint(logLevel)) {
return;
}
this.printLog(logLevel, this.createAndPopulateLogItem(logLevel, input, extraInput));
}

/**
* When the data added in the log item when contains object references,
* JSON.stringify() doesn't try to solve them and throws an error: TypeError: cyclic object value.
* To mitigate this issue, this function will find and remove the cyclic references.
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value
* @private
*/
private removeCircularDependencies(): (key: string, value: LogAttributes) => void {
Copy link
Contributor

Choose a reason for hiding this comment

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

💯 This is much easier to read and understand.

const references = new WeakSet();

console.log(
JSON.parse(
JSON.stringify(log.getAttributes(), (key: string, value: LogAttributes) => {
let item = value;
if (item instanceof Error) {
item = this.getLogFormatter().formatError(item);
}
if (typeof item === 'object' && value !== null) {
if (references.has(item)) {
return;
}
references.add(item);
}

return item;
}),
),
);
return (key, value) => {
let item = value;
if (item instanceof Error) {
item = this.getLogFormatter().formatError(item);
}
if (typeof item === 'object' && value !== null) {
if (references.has(item)) {
return;
}
references.add(item);
}

return item;
};
}

private setCustomConfigService(customConfigService?: ConfigServiceInterface): void {
Expand Down
2 changes: 1 addition & 1 deletion packages/logger/src/formatter/PowertoolLogFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ class PowertoolLogFormatter extends LogFormatter {
cold_start: attributes.lambdaContext?.coldStart,
function_arn: attributes.lambdaContext?.invokedFunctionArn,
function_memory_size: attributes.lambdaContext?.memoryLimitInMB,
function_request_id: attributes.lambdaContext?.awsRequestId,
function_name: attributes.lambdaContext?.functionName,
function_request_id: attributes.lambdaContext?.awsRequestId,
level: attributes.logLevel,
message: attributes.message,
sampling_rate: attributes.sampleRateValue,
Expand Down
Loading