Skip to content

feat(logger): align sampling debug logs feature implementation with the other runtimes #1744

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
176 changes: 71 additions & 105 deletions packages/logger/src/Logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,6 @@ class Logger extends Utility implements ClassThatLogs {
SILENT: 28,
};

private logsSampled = false;

private persistentLogAttributes?: LogAttributes = {};

private powertoolLogData: PowertoolLogData = <PowertoolLogData>{};
Expand Down Expand Up @@ -240,7 +238,7 @@ class Logger extends Utility implements ClassThatLogs {
logFormatter: this.getLogFormatter(),
};
const parentsPowertoolsLogData = this.getPowertoolLogData();
const childLogger = this.createLogger(
const childLogger = new Logger(
merge(parentsOptions, parentsPowertoolsLogData, options)
);

Expand Down Expand Up @@ -311,15 +309,6 @@ class Logger extends Utility implements ClassThatLogs {
return this.logEvent;
}

/**
* It returns a boolean value, if true all the logs will be printed.
*
* @returns {boolean}
*/
public getLogsSampled(): boolean {
return this.logsSampled;
}

/**
* It returns the persistent log attributes, which are the attributes
* that will be logged in all log items.
Expand Down Expand Up @@ -458,18 +447,6 @@ class Logger extends Utility implements ClassThatLogs {
this.info('Lambda invocation event', { event });
}

/**
* If the sample rate feature is enabled, the calculation that determines whether the logs
* will actually be printed or not for this invocation is done when the Logger class is
* initialized.
* This method will repeat that calculation (with possible different outcome).
*
* @returns {void}
*/
public refreshSampleRateCalculation(): void {
this.setLogsSampled();
}

/**
* Alias for removePersistentLogAttributes.
*
Expand Down Expand Up @@ -518,19 +495,6 @@ class Logger extends Utility implements ClassThatLogs {
this.persistentLogAttributes = attributes;
}

/**
* It sets the user-provided sample rate value.
*
* @param {number} [sampleRateValue]
* @returns {void}
*/
public setSampleRateValue(sampleRateValue?: number): void {
this.powertoolLogData.sampleRateValue =
sampleRateValue ||
this.getCustomConfigService()?.getSampleRateValue() ||
this.getEnvVarsService().getSampleRateValue();
}

/**
* It checks whether the current Lambda invocation event should be printed in the logs or not.
*
Expand All @@ -557,37 +521,6 @@ class Logger extends Utility implements ClassThatLogs {
this.processLogItem(16, input, extraInput);
}

/**
* Creates a new Logger instance.
*
* @param {ConstructorOptions} [options]
* @returns {Logger}
*/
protected createLogger(options?: ConstructorOptions): Logger {
return new Logger(options);
}

/**
* Decides whether the current log item should be printed or not.
*
* The decision is based on the log level and the sample rate value.
* A log item will be printed if:
* 1. The log level is greater than or equal to the Logger's log level.
* 2. The log level is less than the Logger's log level, but the
* current sampling value is set to `true`.
*
* @param {number} logLevel
* @returns {boolean}
* @protected
*/
protected shouldPrint(logLevel: number): boolean {
if (logLevel >= this.logLevel) {
return true;
}

return this.getLogsSampled();
}

/**
* It stores information that is printed in all log items.
*
Expand All @@ -603,6 +536,17 @@ class Logger extends Utility implements ClassThatLogs {
});
}

/**
* It dynamically sets log level based on sampling rate value
*/
private configureSampling(): void {
const sampleRateValue = this.powertoolLogData.sampleRateValue;
if (sampleRateValue && randomInt(0, 100) / 100 <= sampleRateValue) {
this.debug('Setting log level to DEBUG due to sampling rate');
this.setLogLevel('DEBUG');
}
}

/**
* It processes a particular log item so that it can be printed to stdout:
* - Merges ephemeral log attributes with persistent log attributes (printed for all logs) and additional info;
Expand Down Expand Up @@ -753,20 +697,6 @@ class Logger extends Utility implements ClassThatLogs {
};
}

/**
* It returns the numeric sample rate value.
*
* @private
* @returns {number}
*/
private getSampleRateValue(): number {
if (!this.powertoolLogData.sampleRateValue) {
this.setSampleRateValue();
}

return this.powertoolLogData.sampleRateValue as number;
}

/**
* It returns true and type guards the log level if a given log level is valid.
*
Expand All @@ -780,6 +710,23 @@ class Logger extends Utility implements ClassThatLogs {
return typeof logLevel === 'string' && logLevel in this.logLevelThresholds;
}

/**
* It returns true and type guards the sample rate value if a given value is valid.
*
* @param sampleRateValue
* @private
* @returns {boolean}
*/
private isValidSampleRate(
sampleRateValue?: number
): sampleRateValue is number {
return (
typeof sampleRateValue === 'number' &&
0 <= sampleRateValue &&
sampleRateValue <= 1
);
}

/**
* It prints a given log with given log level.
*
Expand Down Expand Up @@ -820,13 +767,12 @@ class Logger extends Utility implements ClassThatLogs {
input: LogItemMessage,
extraInput: LogItemExtraInput
): void {
if (!this.shouldPrint(logLevel)) {
return;
if (logLevel >= this.logLevel) {
this.printLog(
logLevel,
this.createAndPopulateLogItem(logLevel, input, extraInput)
);
}
this.printLog(
logLevel,
this.createAndPopulateLogItem(logLevel, input, extraInput)
);
}

/**
Expand Down Expand Up @@ -908,6 +854,41 @@ class Logger extends Utility implements ClassThatLogs {
}
}

/**
* It sets sample rate value with the following prioprity:
* 1. Constructor value
* 2. Custom config service value
* 3. Environment variable value
* 4. Default value (zero)
*
* @private
* @param {number} [sampleRateValue]
* @returns {void}
*/
private setInitialSampleRate(sampleRateValue?: number): void {
const constructorValue = sampleRateValue;
if (this.isValidSampleRate(constructorValue)) {
this.powertoolLogData.sampleRateValue = constructorValue;

return;
}
const customConfigValue =
this.getCustomConfigService()?.getSampleRateValue();
if (this.isValidSampleRate(customConfigValue)) {
this.powertoolLogData.sampleRateValue = customConfigValue;

return;
}
const envVarsValue = this.getEnvVarsService().getSampleRateValue();
if (this.isValidSampleRate(envVarsValue)) {
this.powertoolLogData.sampleRateValue = envVarsValue;

return;
}

this.powertoolLogData.sampleRateValue = 0;
}

/**
* If the log event feature is enabled via env variable, it sets a property that tracks whether
* the event passed to the Lambda function handler should be logged or not.
Expand Down Expand Up @@ -946,20 +927,6 @@ class Logger extends Utility implements ClassThatLogs {
}
}

/**
* If the sample rate feature is enabled, it sets a property that tracks whether this Lambda function invocation
* will print logs or not.
*
* @private
* @returns {void}
*/
private setLogsSampled(): void {
const sampleRateValue = this.getSampleRateValue();
this.logsSampled =
sampleRateValue !== undefined &&
(sampleRateValue === 1 || randomInt(0, 100) / 100 <= sampleRateValue);
}

/**
* It configures the Logger instance settings that will affect the Logger's behaviour
* and the content of all logs.
Expand All @@ -984,12 +951,12 @@ class Logger extends Utility implements ClassThatLogs {
this.setConsole();
this.setCustomConfigService(customConfigService);
this.setInitialLogLevel(logLevel);
this.setSampleRateValue(sampleRateValue);
this.setLogsSampled();
this.setInitialSampleRate(sampleRateValue);
this.setLogFormatter(logFormatter);
this.setPowertoolLogData(serviceName, environment);
this.setLogEvent();
this.setLogIndentation();
this.configureSampling();

this.addPersistentLogAttributes(persistentLogAttributes);

Expand Down Expand Up @@ -1017,7 +984,6 @@ class Logger extends Utility implements ClassThatLogs {
environment ||
this.getCustomConfigService()?.getCurrentEnvironment() ||
this.getEnvVarsService().getCurrentEnvironment(),
sampleRateValue: this.getSampleRateValue(),
serviceName:
serviceName ||
this.getCustomConfigService()?.getServiceName() ||
Expand Down
2 changes: 1 addition & 1 deletion packages/logger/src/config/EnvironmentVariablesService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class EnvironmentVariablesService
/**
* It returns the value of the POWERTOOLS_LOGGER_SAMPLE_RATE environment variable.
*
* @returns {string|undefined}
* @returns {number|undefined}
*/
public getSampleRateValue(): number | undefined {
const value = this.get(this.sampleRateValueVariable);
Expand Down
2 changes: 1 addition & 1 deletion packages/logger/src/types/Logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ type LambdaFunctionContext = {
type PowertoolLogData = LogAttributes & {
environment?: Environment;
serviceName: string;
sampleRateValue?: number;
sampleRateValue: number;
lambdaFunctionContext: LambdaFunctionContext;
xRayTraceId?: string;
awsRegion: string;
Expand Down
Loading