Skip to content

Commit

Permalink
chore(logger): refactor types and interfaces (#1758)
Browse files Browse the repository at this point in the history
* chore(logger): refactor types and interfaces

* chore: grouped type files

* chore: fix code smell

* chore: fix ci

* chore: fix ci
  • Loading branch information
dreamorosi committed Feb 20, 2024
1 parent 7f0becd commit b4568f9
Show file tree
Hide file tree
Showing 22 changed files with 601 additions and 694 deletions.
183 changes: 90 additions & 93 deletions packages/logger/src/Logger.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
import { randomInt } from 'node:crypto';
import { Console } from 'node:console';
import { format } from 'node:util';
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 { format } from 'node:util';
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 @@ -112,7 +113,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 @@ -156,9 +157,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 @@ -188,17 +189,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 @@ -230,23 +229,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 @@ -316,7 +319,7 @@ class Logger extends Utility implements ClassThatLogs {
* @returns {LogAttributes}
*/
public getPersistentLogAttributes(): LogAttributes {
return this.persistentLogAttributes as LogAttributes;
return this.persistentLogAttributes;
}

/**
Expand Down Expand Up @@ -362,7 +365,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 @@ -410,7 +415,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 @@ -421,13 +426,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 @@ -440,9 +445,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 @@ -454,7 +457,7 @@ class Logger extends Utility implements ClassThatLogs {
* @returns {void}
*/
public refreshSampleRateCalculation(): void {
this.setInitialSampleRate(this.powertoolLogData.sampleRateValue);
this.setInitialSampleRate(this.powertoolsLogData.sampleRateValue);
}

/**
Expand All @@ -474,11 +477,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 @@ -564,16 +567,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);
}

private awsLogLevelShortCircuit(selectedLogLevel?: string): boolean {
Expand Down Expand Up @@ -624,7 +623,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 @@ -694,15 +693,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 @@ -712,8 +711,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 @@ -794,7 +793,7 @@ class Logger extends Utility implements ClassThatLogs {
logLevel === 24
? 'error'
: (this.getLogLevelNameFromNumber(logLevel).toLowerCase() as keyof Omit<
ClassThatLogs,
LogFunction,
'critical'
>);

Expand Down Expand Up @@ -923,14 +922,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 @@ -1005,7 +1004,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 @@ -1024,26 +1023,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

0 comments on commit b4568f9

Please sign in to comment.