Skip to content

chore(logger): refactor types and interfaces #1758

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 5 commits into from
Oct 20, 2023
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
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

181 changes: 89 additions & 92 deletions packages/logger/src/Logger.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
import { randomInt } from 'node:crypto';
import { Console } from 'node:console';
import type { Context, Handler } from 'aws-lambda';
import { Utility } from '@aws-lambda-powertools/commons';
import { PowertoolsLogFormatter } from './formatter/PowertoolsLogFormatter.js';
import { LogFormatterInterface } from './formatter/LogFormatterInterface.js';
import { LogItem } from './log/LogItem.js';
import type { HandlerMethodDecorator } from '@aws-lambda-powertools/commons/types';
import type { Context, Handler } from 'aws-lambda';
import merge from 'lodash.merge';
import { ConfigServiceInterface } from './config/ConfigServiceInterface.js';
import { Console } from 'node:console';
import { randomInt } from 'node:crypto';
import { EnvironmentVariablesService } from './config/EnvironmentVariablesService.js';
import { LogJsonIndent } from './types/Logger.js';
import { LogJsonIndent } from './constants.js';
import { LogItem } from './formatter/LogItem.js';
import { PowertoolsLogFormatter } from './formatter/PowertoolsLogFormatter.js';
import type { ConfigServiceInterface } from './types/ConfigServiceInterface.js';
import type {
Environment,
LogAttributes,
LogLevel,
LogLevelThresholds,
LogFormatterInterface,
} from './types/Log.js';
import type {
ClassThatLogs,
HandlerMethodDecorator,
LambdaFunctionContext,
LogFunction,
ConstructorOptions,
InjectLambdaContextOptions,
LogItemExtraInput,
LogItemMessage,
PowertoolLogData,
HandlerOptions,
LoggerInterface,
PowertoolsLogData,
} from './types/Logger.js';

/**
* ## Intro
* The Logger utility provides an opinionated logger with output structured as JSON.
Expand Down Expand Up @@ -111,7 +112,7 @@ import type {
* @implements {ClassThatLogs}
* @see https://docs.powertools.aws.dev/lambda-typescript/latest/core/logger/
*/
class Logger extends Utility implements ClassThatLogs {
class Logger extends Utility implements LoggerInterface {
/**
* Console instance used to print logs.
*
Expand Down Expand Up @@ -155,9 +156,9 @@ class Logger extends Utility implements ClassThatLogs {
SILENT: 28,
};

private persistentLogAttributes?: LogAttributes = {};
private persistentLogAttributes: LogAttributes = {};

private powertoolLogData: PowertoolLogData = <PowertoolLogData>{};
private powertoolsLogData: PowertoolsLogData = <PowertoolsLogData>{};

/**
* Log level used by the current instance of Logger.
Expand Down Expand Up @@ -187,17 +188,15 @@ class Logger extends Utility implements ClassThatLogs {
* @returns {void}
*/
public addContext(context: Context): void {
const lambdaContext: Partial<LambdaFunctionContext> = {
invokedFunctionArn: context.invokedFunctionArn,
coldStart: this.getColdStart(),
awsRequestId: context.awsRequestId,
memoryLimitInMB: Number(context.memoryLimitInMB),
functionName: context.functionName,
functionVersion: context.functionVersion,
};

this.addToPowertoolLogData({
lambdaContext,
this.addToPowertoolsLogData({
lambdaContext: {
invokedFunctionArn: context.invokedFunctionArn,
coldStart: this.getColdStart(),
awsRequestId: context.awsRequestId,
memoryLimitInMB: context.memoryLimitInMB,
functionName: context.functionName,
functionVersion: context.functionVersion,
},
});
}

Expand Down Expand Up @@ -229,23 +228,27 @@ class Logger extends Utility implements ClassThatLogs {
* @returns {Logger}
*/
public createChild(options: ConstructorOptions = {}): Logger {
const parentsOptions = {
logLevel: this.getLevelName(),
customConfigService: this.getCustomConfigService(),
logFormatter: this.getLogFormatter(),
sampleRateValue: this.powertoolLogData.sampleRateValue,
};
const parentsPowertoolsLogData = this.getPowertoolLogData();
const childLogger = this.createLogger(
merge(parentsOptions, parentsPowertoolsLogData, options)
// Merge parent logger options with options passed to createChild,
// the latter having precedence.
merge(
{},
{
logLevel: this.getLevelName(),
serviceName: this.powertoolsLogData.serviceName,
sampleRateValue: this.powertoolsLogData.sampleRateValue,
logFormatter: this.getLogFormatter(),
customConfigService: this.getCustomConfigService(),
environment: this.powertoolsLogData.environment,
persistentLogAttributes: this.persistentLogAttributes,
},
options
)
);

const parentsPersistentLogAttributes = this.getPersistentLogAttributes();
childLogger.addPersistentLogAttributes(parentsPersistentLogAttributes);

if (parentsPowertoolsLogData.lambdaContext) {
childLogger.addContext(parentsPowertoolsLogData.lambdaContext as Context);
}
if (this.powertoolsLogData.lambdaContext)
childLogger.addContext(
this.powertoolsLogData.lambdaContext as unknown as Context
);

return childLogger;
}
Expand Down Expand Up @@ -315,7 +318,7 @@ class Logger extends Utility implements ClassThatLogs {
* @returns {LogAttributes}
*/
public getPersistentLogAttributes(): LogAttributes {
return this.persistentLogAttributes as LogAttributes;
return this.persistentLogAttributes;
}

/**
Expand Down Expand Up @@ -361,7 +364,9 @@ class Logger extends Utility implements ClassThatLogs {
* @see https://www.typescriptlang.org/docs/handbook/decorators.html#method-decorators
* @returns {HandlerMethodDecorator}
*/
public injectLambdaContext(options?: HandlerOptions): HandlerMethodDecorator {
public injectLambdaContext(
options?: InjectLambdaContextOptions
): HandlerMethodDecorator {
return (_target, _propertyKey, descriptor) => {
/**
* The descriptor.value is the method this decorator decorates, it cannot be undefined.
Expand Down Expand Up @@ -409,7 +414,7 @@ class Logger extends Utility implements ClassThatLogs {
public static injectLambdaContextAfterOrOnError(
logger: Logger,
initialPersistentAttributes: LogAttributes,
options?: HandlerOptions
options?: InjectLambdaContextOptions
): void {
if (options && options.clearState === true) {
logger.setPersistentLogAttributes(initialPersistentAttributes);
Expand All @@ -420,13 +425,13 @@ class Logger extends Utility implements ClassThatLogs {
logger: Logger,
event: unknown,
context: Context,
options?: HandlerOptions
options?: InjectLambdaContextOptions
): void {
logger.addContext(context);

let shouldLogEvent = undefined;
if (options && options.hasOwnProperty('logEvent')) {
shouldLogEvent = options.logEvent;
if (Object.hasOwn(options || {}, 'logEvent')) {
shouldLogEvent = options!.logEvent;
}
logger.logEventIfEnabled(event, shouldLogEvent);
}
Expand All @@ -439,9 +444,7 @@ class Logger extends Utility implements ClassThatLogs {
* @returns {void}
*/
public logEventIfEnabled(event: unknown, overwriteValue?: boolean): void {
if (!this.shouldLogEvent(overwriteValue)) {
return;
}
if (!this.shouldLogEvent(overwriteValue)) return;
this.info('Lambda invocation event', { event });
}

Expand All @@ -453,7 +456,7 @@ class Logger extends Utility implements ClassThatLogs {
* @returns {void}
*/
public refreshSampleRateCalculation(): void {
this.setInitialSampleRate(this.powertoolLogData.sampleRateValue);
this.setInitialSampleRate(this.powertoolsLogData.sampleRateValue);
}

/**
Expand All @@ -473,11 +476,11 @@ class Logger extends Utility implements ClassThatLogs {
* @returns {void}
*/
public removePersistentLogAttributes(keys: string[]): void {
keys.forEach((key) => {
if (this.persistentLogAttributes && key in this.persistentLogAttributes) {
for (const key of keys) {
if (Object.hasOwn(this.persistentLogAttributes, key)) {
delete this.persistentLogAttributes[key];
}
});
}
}

/**
Expand Down Expand Up @@ -559,16 +562,12 @@ class Logger extends Utility implements ClassThatLogs {
/**
* It stores information that is printed in all log items.
*
* @param {Partial<PowertoolLogData>} attributesArray
* @param {Partial<PowertoolsLogData>} attributes
* @private
* @returns {void}
*/
private addToPowertoolLogData(
...attributesArray: Array<Partial<PowertoolLogData>>
): void {
attributesArray.forEach((attributes: Partial<PowertoolLogData>) => {
merge(this.powertoolLogData, attributes);
});
private addToPowertoolsLogData(attributes: Partial<PowertoolsLogData>): void {
merge(this.powertoolsLogData, attributes);
}

/**
Expand All @@ -595,7 +594,7 @@ class Logger extends Utility implements ClassThatLogs {
message: typeof input === 'string' ? input : input.message,
xRayTraceId: this.envVarsService.getXrayTraceId(),
},
this.getPowertoolLogData()
this.getPowertoolsLogData()
);

let additionalLogAttributes: LogAttributes = {};
Expand Down Expand Up @@ -665,15 +664,15 @@ class Logger extends Utility implements ClassThatLogs {
* @returns - The name of the log level
*/
private getLogLevelNameFromNumber(logLevel: number): Uppercase<LogLevel> {
const found = Object.entries(this.logLevelThresholds).find(
([key, value]) => {
if (value === logLevel) {
return key;
}
let found;
for (const [key, value] of Object.entries(this.logLevelThresholds)) {
if (value === logLevel) {
found = key;
break;
}
)!;
}

return found[0] as Uppercase<LogLevel>;
return found as Uppercase<LogLevel>;
}

/**
Expand All @@ -683,8 +682,8 @@ class Logger extends Utility implements ClassThatLogs {
* @private
* @returns {LogAttributes}
*/
private getPowertoolLogData(): PowertoolLogData {
return this.powertoolLogData;
private getPowertoolsLogData(): PowertoolsLogData {
return this.powertoolsLogData;
}

/**
Expand Down Expand Up @@ -765,7 +764,7 @@ class Logger extends Utility implements ClassThatLogs {
logLevel === 24
? 'error'
: (this.getLogLevelNameFromNumber(logLevel).toLowerCase() as keyof Omit<
ClassThatLogs,
LogFunction,
'critical'
>);

Expand Down Expand Up @@ -890,14 +889,14 @@ class Logger extends Utility implements ClassThatLogs {
* @returns {void}
*/
private setInitialSampleRate(sampleRateValue?: number): void {
this.powertoolLogData.sampleRateValue = 0;
this.powertoolsLogData.sampleRateValue = 0;
const constructorValue = sampleRateValue;
const customConfigValue =
this.getCustomConfigService()?.getSampleRateValue();
const envVarsValue = this.getEnvVarsService().getSampleRateValue();
for (const value of [constructorValue, customConfigValue, envVarsValue]) {
if (this.isValidSampleRate(value)) {
this.powertoolLogData.sampleRateValue = value;
this.powertoolsLogData.sampleRateValue = value;

if (value && randomInt(0, 100) / 100 <= value) {
this.setLogLevel('DEBUG');
Expand Down Expand Up @@ -972,7 +971,7 @@ class Logger extends Utility implements ClassThatLogs {
this.setCustomConfigService(customConfigService);
this.setInitialLogLevel(logLevel);
this.setLogFormatter(logFormatter);
this.setPowertoolLogData(serviceName, environment);
this.setPowertoolsLogData(serviceName, environment);
this.setInitialSampleRate(sampleRateValue);
this.setLogEvent();
this.setLogIndentation();
Expand All @@ -991,26 +990,24 @@ class Logger extends Utility implements ClassThatLogs {
* @private
* @returns {void}
*/
private setPowertoolLogData(
private setPowertoolsLogData(
serviceName?: string,
environment?: Environment,
persistentLogAttributes: LogAttributes = {}
): void {
this.addToPowertoolLogData(
{
awsRegion: this.getEnvVarsService().getAwsRegion(),
environment:
environment ||
this.getCustomConfigService()?.getCurrentEnvironment() ||
this.getEnvVarsService().getCurrentEnvironment(),
serviceName:
serviceName ||
this.getCustomConfigService()?.getServiceName() ||
this.getEnvVarsService().getServiceName() ||
this.getDefaultServiceName(),
},
persistentLogAttributes
);
this.addToPowertoolsLogData({
awsRegion: this.getEnvVarsService().getAwsRegion(),
environment:
environment ||
this.getCustomConfigService()?.getCurrentEnvironment() ||
this.getEnvVarsService().getCurrentEnvironment(),
serviceName:
serviceName ||
this.getCustomConfigService()?.getServiceName() ||
this.getEnvVarsService().getServiceName() ||
this.getDefaultServiceName(),
});
this.addPersistentLogAttributes(persistentLogAttributes);
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/logger/src/config/EnvironmentVariablesService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ConfigServiceInterface } from './ConfigServiceInterface.js';
import { ConfigServiceInterface } from '../types/ConfigServiceInterface.js';
import { EnvironmentVariablesService as CommonEnvironmentVariablesService } from '@aws-lambda-powertools/commons';

/**
Expand Down
17 changes: 17 additions & 0 deletions packages/logger/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* The indent level for JSON logs.
*
* By default Logger will use the `LogJsonIndent.COMPACT` indent level, which
* produces logs on a single line. This is the most efficient option for
* CloudWatch Logs.
*
* When enabling the `POWERTOOLS_DEV` environment variable, Logger will use the
* `LogJsonIndent.PRETTY` indent level, which indents the JSON logs for easier
* reading.
*/
const LogJsonIndent = {
PRETTY: 4,
COMPACT: 0,
} as const;

export { LogJsonIndent };
Loading