diff --git a/packages/logger/src/Logger.ts b/packages/logger/src/Logger.ts index c62d91d0b7..265f8ab76a 100644 --- a/packages/logger/src/Logger.ts +++ b/packages/logger/src/Logger.ts @@ -6,9 +6,15 @@ import type { HandlerMethodDecorator, SyncHandler, } from '@aws-lambda-powertools/commons/types'; +import { + getBooleanFromEnv, + getNumberFromEnv, + getStringFromEnv, + getXRayTraceIdFromEnv, + isDevMode, +} from '@aws-lambda-powertools/commons/utils/env'; import type { Context, Handler } from 'aws-lambda'; import merge from 'lodash.merge'; -import { EnvironmentVariablesService } from './config/EnvironmentVariablesService.js'; import { LogJsonIndent, LogLevelThreshold, @@ -112,10 +118,6 @@ class Logger extends Utility implements LoggerInterface { * Custom config service instance used to configure the logger. */ private customConfigService?: ConfigServiceInterface; - /** - * Environment variables service instance used to fetch environment variables. - */ - private envVarsService = new EnvironmentVariablesService(); /** * Whether to print the Lambda invocation event in the logs. */ @@ -850,7 +852,7 @@ class Logger extends Utility implements LoggerInterface { const unformattedBaseAttributes = { logLevel: this.getLogLevelNameFromNumber(logLevel), timestamp: new Date(), - xRayTraceId: this.envVarsService.getXrayTraceId(), + xRayTraceId: getXRayTraceIdFromEnv(), ...this.getPowertoolsLogData(), message: '', }; @@ -975,13 +977,6 @@ class Logger extends Utility implements LoggerInterface { return this.customConfigService; } - /** - * Get the instance of a service that fetches environment variables. - */ - private getEnvVarsService(): EnvironmentVariablesService { - return this.envVarsService as EnvironmentVariablesService; - } - /** * Get the instance of a service that formats the structure of a * log item's keys and values in the desired way. @@ -1081,7 +1076,7 @@ class Logger extends Utility implements LoggerInterface { input: LogItemMessage, extraInput: LogItemExtraInput ): void { - const traceId = this.envVarsService.getXrayTraceId(); + const traceId = getXRayTraceIdFromEnv(); if (traceId !== undefined && this.shouldBufferLog(traceId, logLevel)) { try { this.bufferLogItem( @@ -1125,7 +1120,7 @@ class Logger extends Utility implements LoggerInterface { * or as the global node console if the `POWERTOOLS_DEV' env variable is set and has truthy value. */ private setConsole(): void { - if (!this.getEnvVarsService().isDevMode()) { + if (!isDevMode()) { this.console = new Console({ stdout: process.stdout, stderr: process.stderr, @@ -1190,9 +1185,21 @@ class Logger extends Utility implements LoggerInterface { return; } - const envVarsValue = this.getEnvVarsService()?.getLogLevel()?.toUpperCase(); - if (this.isValidLogLevel(envVarsValue)) { - this.logLevel = LogLevelThreshold[envVarsValue]; + + const logLevelVariable = getStringFromEnv({ + key: 'POWERTOOLS_LOG_LEVEL', + defaultValue: '', + }); + const logLevelVariableAlias = getStringFromEnv({ + key: 'LOG_LEVEL', + defaultValue: '', + }); + + const logLevelValue = + logLevelVariable !== '' ? logLevelVariable : logLevelVariableAlias; + + if (this.isValidLogLevel(logLevelValue)) { + this.logLevel = LogLevelThreshold[logLevelValue]; this.#initialLogLevel = this.logLevel; return; @@ -1212,8 +1219,15 @@ class Logger extends Utility implements LoggerInterface { const constructorValue = sampleRateValue; const customConfigValue = this.getCustomConfigService()?.getSampleRateValue(); - const envVarsValue = this.getEnvVarsService().getSampleRateValue(); - for (const value of [constructorValue, customConfigValue, envVarsValue]) { + const sampleRateEnvVariable = getNumberFromEnv({ + key: 'POWERTOOLS_LOGGER_SAMPLE_RATE', + defaultValue: 0, + }); + for (const value of [ + constructorValue, + customConfigValue, + sampleRateEnvVariable, + ]) { if (this.isValidSampleRate(value)) { this.#debugLogSampling.sampleRateValue = value; this.powertoolsLogData.sampleRateValue = value; @@ -1236,9 +1250,10 @@ class Logger extends Utility implements LoggerInterface { * the event passed to the Lambda function handler should be logged or not. */ private setLogEvent(): void { - if (this.getEnvVarsService().getLogEvent()) { - this.logEvent = true; - } + this.logEvent = getBooleanFromEnv({ + key: 'POWERTOOLS_LOGGER_LOG_EVENT', + defaultValue: false, + }); } /** @@ -1255,7 +1270,6 @@ class Logger extends Utility implements LoggerInterface { this.logFormatter = logFormatter ?? new PowertoolsLogFormatter({ - envVarsService: this.getEnvVarsService(), logRecordOrder, }); } @@ -1265,7 +1279,7 @@ class Logger extends Utility implements LoggerInterface { * add JSON indentation for pretty printing logs. */ private setLogIndentation(): void { - if (this.getEnvVarsService().isDevMode()) { + if (isDevMode()) { this.logIndentation = LogJsonIndent.PRETTY; } } @@ -1307,7 +1321,13 @@ class Logger extends Utility implements LoggerInterface { ); // configurations that affect Logger behavior - const AlcLogLevel = this.getEnvVarsService().getAwsLogLevel(); + const lambdaLogLevel = getStringFromEnv({ + key: 'AWS_LAMBDA_LOG_LEVEL', + defaultValue: '', + }); + const AlcLogLevel = + lambdaLogLevel === 'FATAL' ? 'CRITICAL' : lambdaLogLevel; + if (this.isValidLogLevel(AlcLogLevel)) { this.#alcLogLevel = AlcLogLevel; } @@ -1340,15 +1360,23 @@ class Logger extends Utility implements LoggerInterface { persistentKeys?: ConstructorOptions['persistentKeys'] ): void { this.addToPowertoolsLogData({ - awsRegion: this.getEnvVarsService().getAwsRegion(), + awsRegion: getStringFromEnv({ + key: 'AWS_REGION', + }), environment: environment || this.getCustomConfigService()?.getCurrentEnvironment() || - this.getEnvVarsService().getCurrentEnvironment(), + getStringFromEnv({ + key: 'ENVIRONMENT', + defaultValue: '', + }), serviceName: serviceName || this.getCustomConfigService()?.getServiceName() || - this.getEnvVarsService().getServiceName() || + getStringFromEnv({ + key: 'POWERTOOLS_SERVICE_NAME', + defaultValue: '', + }) || this.defaultServiceName, }); persistentKeys && this.appendPersistentKeys(persistentKeys); @@ -1433,7 +1461,7 @@ class Logger extends Utility implements LoggerInterface { * your function throws an error. */ public flushBuffer(): void { - const traceId = this.envVarsService.getXrayTraceId(); + const traceId = getXRayTraceIdFromEnv(); if (traceId === undefined) { return; } @@ -1477,7 +1505,7 @@ class Logger extends Utility implements LoggerInterface { * Empties the buffer for the current request */ public clearBuffer(): void { - const traceId = this.envVarsService.getXrayTraceId(); + const traceId = getXRayTraceIdFromEnv(); if (traceId === undefined) { return; } diff --git a/packages/logger/src/config/EnvironmentVariablesService.ts b/packages/logger/src/config/EnvironmentVariablesService.ts deleted file mode 100644 index e5759dd92c..0000000000 --- a/packages/logger/src/config/EnvironmentVariablesService.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { EnvironmentVariablesService as CommonEnvironmentVariablesService } from '@aws-lambda-powertools/commons'; -import type { ConfigServiceInterface } from '../types/ConfigServiceInterface.js'; - -/** - * Class EnvironmentVariablesService - * - * This class is used to return environment variables that are available in the runtime of - * the current Lambda invocation. - * These variables can be a mix of runtime environment variables set by AWS and - * variables that can be set by the developer additionally. - * - * @see https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime - * @see https://docs.powertools.aws.dev/lambda/typescript/latest/#environment-variables - */ -class EnvironmentVariablesService - extends CommonEnvironmentVariablesService - implements ConfigServiceInterface -{ - // Reserved environment variables - private awsLogLevelVariable = 'AWS_LAMBDA_LOG_LEVEL'; - private awsRegionVariable = 'AWS_REGION'; - private currentEnvironmentVariable = 'ENVIRONMENT'; - private functionNameVariable = 'AWS_LAMBDA_FUNCTION_NAME'; - private functionVersionVariable = 'AWS_LAMBDA_FUNCTION_VERSION'; - private logEventVariable = 'POWERTOOLS_LOGGER_LOG_EVENT'; - private logLevelVariable = 'POWERTOOLS_LOG_LEVEL'; - private logLevelVariableLegacy = 'LOG_LEVEL'; - private memoryLimitInMBVariable = 'AWS_LAMBDA_FUNCTION_MEMORY_SIZE'; - private sampleRateValueVariable = 'POWERTOOLS_LOGGER_SAMPLE_RATE'; - private tzVariable = 'TZ'; - - /** - * Return the value of the `AWS_LAMBDA_LOG_LEVEL` environment variable. - * - * The `AWS_LAMBDA_LOG_LEVEL` environment variable is set by AWS Lambda when configuring - * the function's log level using the Advanced Logging Controls feature. This value always - * takes precedence over other means of configuring the log level. - * - * We need to map the `FATAL` log level to `CRITICAL`, see {@link https://docs.aws.amazon.com/lambda/latest/dg/configuration-logging.html#configuration-logging-log-levels AWS Lambda Log Levels}. - */ - public getAwsLogLevel(): string { - const awsLogLevelVariable = this.get(this.awsLogLevelVariable); - - return awsLogLevelVariable === 'FATAL' ? 'CRITICAL' : awsLogLevelVariable; - } - - /** - * Return the value of the AWS_REGION environment variable. - */ - public getAwsRegion(): string { - return this.get(this.awsRegionVariable); - } - - /** - * Return the value of the ENVIRONMENT environment variable. - */ - public getCurrentEnvironment(): string { - return this.get(this.currentEnvironmentVariable); - } - - /** - * Return the value of the AWS_LAMBDA_FUNCTION_MEMORY_SIZE environment variable. - */ - public getFunctionMemory(): number { - const value = this.get(this.memoryLimitInMBVariable); - - return Number(value); - } - - /** - * Return the value of the AWS_LAMBDA_FUNCTION_NAME environment variable. - */ - public getFunctionName(): string { - return this.get(this.functionNameVariable); - } - - /** - * Return the value of the AWS_LAMBDA_FUNCTION_VERSION environment variable. - */ - public getFunctionVersion(): string { - return this.get(this.functionVersionVariable); - } - - /** - * Return the value of the POWERTOOLS_LOGGER_LOG_EVENT environment variable. - */ - public getLogEvent(): boolean { - const value = this.get(this.logEventVariable); - - return this.isValueTrue(value); - } - - /** - * Return the value of the `POWERTOOLS_LOG_LEVEL` or `LOG_LEVEL` (legacy) environment variables - * when the first one is not set. - * - * The `LOG_LEVEL` environment variable is considered legacy and will be removed in a future release. - * The `AWS_LAMBDA_LOG_LEVEL` environment variable always takes precedence over the ones above. - */ - public getLogLevel(): string { - const logLevelVariable = this.get(this.logLevelVariable); - const logLevelVariableAlias = this.get(this.logLevelVariableLegacy); - - return logLevelVariable !== '' ? logLevelVariable : logLevelVariableAlias; - } - - /** - * Return the value of the POWERTOOLS_LOGGER_SAMPLE_RATE environment variable. - */ - public getSampleRateValue(): number | undefined { - const value = this.get(this.sampleRateValueVariable); - - return value && value.length > 0 ? Number(value) : undefined; - } - - /** - * Return the value of the `TZ` environment variable or `UTC` if it is not set. - */ - public getTimezone(): string { - const value = this.get(this.tzVariable); - - return value.length > 0 ? value : 'UTC'; - } -} - -export { EnvironmentVariablesService }; diff --git a/packages/logger/src/formatter/LogFormatter.ts b/packages/logger/src/formatter/LogFormatter.ts index 9bae4fbaa4..9e6a57197a 100644 --- a/packages/logger/src/formatter/LogFormatter.ts +++ b/packages/logger/src/formatter/LogFormatter.ts @@ -1,5 +1,7 @@ -import type { EnvironmentVariablesService } from '../config/EnvironmentVariablesService.js'; -import type { LogFormatterOptions } from '../types/formatters.js'; +import { + getStringFromEnv, + isDevMode, +} from '@aws-lambda-powertools/commons/utils/env'; import type { LogAttributes } from '../types/Logger.js'; import type { UnformattedAttributes } from '../types/logKeys.js'; import type { LogItem } from './LogItem.js'; @@ -13,15 +15,6 @@ import type { LogItem } from './LogItem.js'; * @abstract */ abstract class LogFormatter { - /** - * Instance of the {@link EnvironmentVariablesService} to use for configuration. - */ - protected envVarsService?: EnvironmentVariablesService; - - public constructor(options?: LogFormatterOptions) { - this.envVarsService = options?.envVarsService; - } - /** * Format key-value pairs of log attributes. * @@ -117,9 +110,7 @@ abstract class LogFormatter { location: this.getCodeLocation(error.stack), message, stack: - this.envVarsService?.isDevMode() && typeof stack === 'string' - ? stack?.split('\n') - : stack, + isDevMode() && typeof stack === 'string' ? stack?.split('\n') : stack, cause: cause instanceof Error ? this.formatError(cause) : cause, }; for (const key in error) { @@ -137,9 +128,7 @@ abstract class LogFormatter { /** * Format a date into an ISO 8601 string with the configured timezone. * - * If the log formatter is passed an {@link EnvironmentVariablesService} instance - * during construction, the timezone is read from the `TZ` environment variable, if present. - * + * The timezone is read from the `TZ` environment variable, if present. * Otherwise, the timezone defaults to ':UTC'. * * @param now - The date to format @@ -151,7 +140,11 @@ abstract class LogFormatter { * If a specific timezone is configured and it's not the default `UTC`, * format the timestamp with the appropriate timezone offset. **/ - const configuredTimezone = this.envVarsService?.getTimezone(); + const configuredTimezone = getStringFromEnv({ + key: 'TZ', + defaultValue: '', + }); + if (configuredTimezone && !configuredTimezone.includes(defaultTimezone)) return this.#generateISOTimestampWithOffset(now, configuredTimezone); diff --git a/packages/logger/src/formatter/PowertoolsLogFormatter.ts b/packages/logger/src/formatter/PowertoolsLogFormatter.ts index 9172d33ff1..d68d3ff91c 100644 --- a/packages/logger/src/formatter/PowertoolsLogFormatter.ts +++ b/packages/logger/src/formatter/PowertoolsLogFormatter.ts @@ -27,7 +27,7 @@ class PowertoolsLogFormatter extends LogFormatter { #logRecordOrder?: LogRecordOrderKeys; public constructor(options?: PowertoolsLogFormatterOptions) { - super(options); + super(); this.#logRecordOrder = options?.logRecordOrder; } diff --git a/packages/logger/src/types/formatters.ts b/packages/logger/src/types/formatters.ts index 5909ed83e2..389434a759 100644 --- a/packages/logger/src/types/formatters.ts +++ b/packages/logger/src/types/formatters.ts @@ -1,17 +1,5 @@ -import type { EnvironmentVariablesService } from '../config/EnvironmentVariablesService.js'; -import type { LogFormatter } from '../formatter/LogFormatter.js'; import type { LogKey } from './logKeys.js'; -/** - * Options for the {@link LogFormatter} class. - */ -type LogFormatterOptions = { - /** - * Instance of the {@link EnvironmentVariablesService} to use for configuration. - */ - envVarsService?: EnvironmentVariablesService; -}; - /** * List of keys to order log attributes by. * @@ -22,15 +10,11 @@ type LogRecordOrderKeys = Set | LogKey[]; /** * Options for the {@link PowertoolsLogFormatter} class. */ -type PowertoolsLogFormatterOptions = LogFormatterOptions & { +type PowertoolsLogFormatterOptions = { /** * An array of keys that defines the order of the log record. */ logRecordOrder?: LogRecordOrderKeys; }; -export type { - LogFormatterOptions, - PowertoolsLogFormatterOptions, - LogRecordOrderKeys, -}; +export type { LogRecordOrderKeys, PowertoolsLogFormatterOptions }; diff --git a/packages/logger/tests/unit/configFromEnv.test.ts b/packages/logger/tests/unit/configFromEnv.test.ts deleted file mode 100644 index 87cf414d31..0000000000 --- a/packages/logger/tests/unit/configFromEnv.test.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { beforeEach, describe, expect, it } from 'vitest'; -import { EnvironmentVariablesService } from '../../src/config/EnvironmentVariablesService.js'; - -describe('Class: EnvironmentVariablesService', () => { - const ENVIRONMENT_VARIABLES = process.env; - - beforeEach(() => { - process.env = { ...ENVIRONMENT_VARIABLES }; - }); - - it('returns the value of the environment variable AWS_LAMBDA_LOG_LEVEL and aliases it as needed', () => { - // Prepare - process.env.AWS_LAMBDA_LOG_LEVEL = 'FATAL'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.getAwsLogLevel(); - - // Assess - // The Advanced Logging Controls feature in AWS Lambda supports the `FATAL` log level, which we don't support - // and instead map to `CRITICAL` as per the existing log levels. In this test, we expect the value to be `CRITICAL`. - expect(value).toEqual('CRITICAL'); - }); - - it('returns the value of the environment variable AWS_REGION', () => { - // Prepare - process.env.AWS_REGION = 'us-east-1'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.getAwsRegion(); - - // Assess - expect(value).toEqual('us-east-1'); - }); - - it('returns the value of the environment variable AWS_REGION', () => { - // Prepare - process.env.ENVIRONMENT = 'stage'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.getCurrentEnvironment(); - - // Assess - expect(value).toEqual('stage'); - }); - - it('returns the value of the environment variable AWS_LAMBDA_FUNCTION_MEMORY_SIZE', () => { - // Prepare - process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '123456'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.getFunctionMemory(); - - // Assess - expect(value).toBe(123456); - }); - - it('returns the value of the environment variable AWS_LAMBDA_FUNCTION_NAME', () => { - // Prepare - process.env.AWS_LAMBDA_FUNCTION_NAME = 'my-lambda-function'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.getFunctionName(); - - // Assess - expect(value).toEqual('my-lambda-function'); - }); - - it('returns the value of the environment variable AWS_LAMBDA_FUNCTION_VERSION', () => { - // Prepare - process.env.AWS_LAMBDA_FUNCTION_VERSION = '1.4.0'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.getFunctionVersion(); - - // Assess - expect(value).toEqual('1.4.0'); - }); - - it('returns true if the environment variable POWERTOOLS_LOGGER_LOG_EVENT is "true"', () => { - // Prepare - process.env.POWERTOOLS_LOGGER_LOG_EVENT = 'true'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.getLogEvent(); - - // Assess - expect(value).toEqual(true); - }); - - it('returns false if the environment variable POWERTOOLS_LOGGER_LOG_EVENT is "false"', () => { - // Prepare - process.env.POWERTOOLS_LOGGER_LOG_EVENT = 'false'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.getLogEvent(); - - // Assess - expect(value).toEqual(false); - }); - - it('returns false if the environment variable POWERTOOLS_LOGGER_LOG_EVENT is "somethingsilly"', () => { - // Prepare - process.env.POWERTOOLS_LOGGER_LOG_EVENT = 'somethingsilly'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.getLogEvent(); - - // Assess - expect(value).toEqual(false); - }); - - it('returns the value of the environment variable LOG_LEVEL when POWERTOOLS_LOG_LEVEL is not set', () => { - // Prepare - process.env.POWERTOOLS_LOG_LEVEL = undefined; - process.env.LOG_LEVEL = 'ERROR'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.getLogLevel(); - - // Assess - expect(value).toEqual('ERROR'); - }); - - it('returns the value of the environment variable POWERTOOLS_LOG_LEVEL when LOG_LEVEL one is also set', () => { - // Prepare - process.env.LOG_LEVEL = 'WARN'; - process.env.POWERTOOLS_LOG_LEVEL = 'INFO'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.getLogLevel(); - - // Assess - expect(value).toEqual('INFO'); - }); - - it('returns an empty value if neither POWERTOOLS_LOG_LEVEL nor LOG_LEVEL are set', () => { - // Prepare - process.env.LOG_LEVEL = undefined; - process.env.POWERTOOLS_LOG_LEVEL = undefined; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.getLogLevel(); - - // Assess - expect(value).toEqual(''); - }); - - it('returns the value of the environment variable POWERTOOLS_LOGGER_SAMPLE_RATE', () => { - // Prepare - process.env.POWERTOOLS_LOGGER_SAMPLE_RATE = '0.01'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.getSampleRateValue(); - - // Assess - expect(value).toEqual(0.01); - }); - - it('returns the value of the TZ environment variable when set', () => { - // Prepare - process.env.TZ = 'Europe/London'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.getTimezone(); - - // Assess - expect(value).toEqual('Europe/London'); - }); - - it('returns the default UTC value when no TZ is set', () => { - // Prepare - const service = new EnvironmentVariablesService(); - - // Act - const value = service.getTimezone(); - - // Assess - expect(value).toEqual('UTC'); - }); -}); diff --git a/packages/logger/tests/unit/formatters.test.ts b/packages/logger/tests/unit/formatters.test.ts index 19cfb2685e..e826cbd6a5 100644 --- a/packages/logger/tests/unit/formatters.test.ts +++ b/packages/logger/tests/unit/formatters.test.ts @@ -1,6 +1,5 @@ import { AssertionError } from 'node:assert'; import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest'; -import { EnvironmentVariablesService } from '../../src/config/EnvironmentVariablesService.js'; import { PowertoolsLogFormatter } from '../../src/formatter/PowertoolsLogFormatter.js'; import { LogFormatter, @@ -17,10 +16,6 @@ import type { LogKey, UnformattedAttributes } from '../../src/types/logKeys.js'; const fileNameRegexpWithLine = new RegExp(/formatters.test.ts:\d+:\d+/); const formatter = new PowertoolsLogFormatter(); -const formatterWithEnv = new PowertoolsLogFormatter({ - envVarsService: new EnvironmentVariablesService(), -}); - class ErrorWithCause extends Error { public constructor(message: string, options?: { cause: unknown }) { super(message, options); @@ -296,7 +291,7 @@ describe('Formatters', () => { it('when logRecordOrder is not set, it will not order the attributes in the log item', () => { // Prepare - const formatter = new PowertoolsLogFormatter({}); + const formatter = new PowertoolsLogFormatter(); const additionalLogAttributes: LogAttributes = { additional_key: 'additional_value', }; @@ -422,7 +417,9 @@ describe('Formatters', () => { location: expect.any(String), message: 'bar', name: 'Error', - stack: expect.stringMatching(fileNameRegexpWithLine), + stack: expect.arrayContaining([ + expect.stringMatching(fileNameRegexpWithLine), + ]), }, }, }, @@ -443,13 +440,34 @@ describe('Formatters', () => { // Assess expect(formattedError).toEqual({ - stack: expect.stringMatching(fileNameRegexpWithLine), + stack: expect.arrayContaining([ + expect.stringMatching(fileNameRegexpWithLine), + ]), name, ...expectedFields, }); } ); + it('formats stack as string when not in dev mode', () => { + // Prepare + const originalDevMode = process.env.POWERTOOLS_DEV; + delete process.env.POWERTOOLS_DEV; // Ensure dev mode is off + + const error = new Error('Test error'); + const formatter = new PowertoolsLogFormatter(); + + // Act + const formattedError = formatter.formatError(error); + + // Assess + expect(formattedError.stack).toEqual(expect.any(String)); + expect(Array.isArray(formattedError.stack)).toBe(false); + + // Cleanup + process.env.POWERTOOLS_DEV = originalDevMode; + }); + it('formats custom errors by including only enumerable properties', () => { // Prepare const customSymbol = Symbol('customSymbol'); @@ -487,7 +505,9 @@ describe('Formatters', () => { // Assess expect(formattedError).toEqual({ location: expect.any(String), - stack: expect.stringMatching(fileNameRegexpWithLine), + stack: expect.arrayContaining([ + expect.stringMatching(fileNameRegexpWithLine), + ]), name: 'SuperCustomError', message: 'Something went wrong', code: 500, @@ -516,7 +536,7 @@ describe('Formatters', () => { vi.spyOn(Date.prototype, 'getTimezoneOffset').mockReturnValue(240); // Act - const timestamp = formatterWithEnv.formatTimestamp(new Date()); + const timestamp = formatter.formatTimestamp(new Date()); // Assess expect(timestamp).toEqual('2016-06-20T08:08:10.000-04:00'); @@ -532,7 +552,7 @@ describe('Formatters', () => { vi.spyOn(Date.prototype, 'getTimezoneOffset').mockReturnValue(240); // Act - const timestamp = formatterWithEnv.formatTimestamp(new Date()); + const timestamp = formatter.formatTimestamp(new Date()); // Assess expect(timestamp).toEqual('2016-06-20T08:08:10.000-04:00'); @@ -548,7 +568,7 @@ describe('Formatters', () => { vi.spyOn(Date.prototype, 'getTimezoneOffset').mockReturnValue(240); // Act - const timestamp = formatterWithEnv.formatTimestamp(new Date()); + const timestamp = formatter.formatTimestamp(new Date()); // Assess expect(timestamp).toEqual('2016-06-20T08:08:10.000-04:00'); @@ -563,9 +583,7 @@ describe('Formatters', () => { The negative value indicates that `Asia/Dhaka` is ahead of UTC. */ vi.spyOn(Date.prototype, 'getTimezoneOffset').mockReturnValue(-360); - const formatter = new PowertoolsLogFormatter({ - envVarsService: new EnvironmentVariablesService(), - }); + const formatter = new PowertoolsLogFormatter(); // Act const timestamp = formatter.formatTimestamp(new Date()); @@ -584,9 +602,7 @@ describe('Formatters', () => { The negative value indicates that `Asia/Dhaka` is ahead of UTC. */ vi.spyOn(Date.prototype, 'getTimezoneOffset').mockReturnValue(-360); - const formatter = new PowertoolsLogFormatter({ - envVarsService: new EnvironmentVariablesService(), - }); + const formatter = new PowertoolsLogFormatter(); // Act const timestamp = formatter.formatTimestamp(new Date()); @@ -597,11 +613,8 @@ describe('Formatters', () => { it('returns defaults to :UTC when an env variable service is not set', () => { // Prepare - process.env.TZ = 'Asia/Dhaka'; - /* - Difference between UTC and `Asia/Dhaka`(GMT +06.00) is 360 minutes. - The negative value indicates that `Asia/Dhaka` is ahead of UTC. - */ + process.env.TZ = undefined; + vi.spyOn(Date.prototype, 'getTimezoneOffset').mockReturnValue(-360); const formatter = new PowertoolsLogFormatter(); @@ -616,9 +629,7 @@ describe('Formatters', () => { // Prepare process.env.TZ = ':/etc/localtime'; vi.spyOn(Date.prototype, 'getTimezoneOffset').mockReturnValue(0); - const formatter = new PowertoolsLogFormatter({ - envVarsService: new EnvironmentVariablesService(), - }); + const formatter = new PowertoolsLogFormatter(); // Act const timestamp = formatter.formatTimestamp(new Date()); diff --git a/packages/logger/tests/unit/logLevels.test.ts b/packages/logger/tests/unit/logLevels.test.ts index af28510dad..cee4602499 100644 --- a/packages/logger/tests/unit/logLevels.test.ts +++ b/packages/logger/tests/unit/logLevels.test.ts @@ -104,6 +104,17 @@ describe('Log levels', () => { expect(logger.getLevelName()).toBe(LogLevel.CRITICAL); }); + it('sets the log level to CRITICAL when AWS_LAMBDA_LOG_LEVEL is FATAL', () => { + // Prepare + process.env.AWS_LAMBDA_LOG_LEVEL = 'FATAL'; + + // Act + const logger = new Logger(); + + // Assess + expect(logger.getLevelName()).toBe('CRITICAL'); + }); + it('sets the correct log level when using a custom config service', () => { // Prepare process.env.POWERTOOLS_LOG_LEVEL = undefined; diff --git a/packages/logger/tests/unit/sampling.test.ts b/packages/logger/tests/unit/sampling.test.ts index 0373329b71..947a8271b9 100644 --- a/packages/logger/tests/unit/sampling.test.ts +++ b/packages/logger/tests/unit/sampling.test.ts @@ -1,20 +1,6 @@ import { beforeEach, describe, expect, it } from 'vitest'; -import { EnvironmentVariablesService } from '../../src/config/EnvironmentVariablesService.js'; import { Logger, LogLevel, LogLevelThreshold } from '../../src/index.js'; -class CustomConfigService extends EnvironmentVariablesService { - #sampleRateValue = 1; - - public constructor(value = 1) { - super(); - this.#sampleRateValue = value; - } - - public getSampleRateValue(): number { - return this.#sampleRateValue; - } -} - describe('Log sampling', () => { const ENVIRONMENT_VARIABLES = process.env; @@ -47,17 +33,6 @@ describe('Log sampling', () => { expect(logger.level).toBe(LogLevelThreshold.DEBUG); }); - it('changes the log level to DEBUG log sampling is configured via custom config service', () => { - // Act - const logger: Logger = new Logger({ - logLevel: LogLevel.ERROR, - customConfigService: new CustomConfigService(), - }); - - // Assess - expect(logger.level).toBe(LogLevelThreshold.DEBUG); - }); - it('changes the log level to debug log sampling is configured via env variable', () => { // Prepare process.env.POWERTOOLS_LOGGER_SAMPLE_RATE = '1'; @@ -89,7 +64,6 @@ describe('Log sampling', () => { // Act const logger: Logger = new Logger({ sampleRateValue: 1, - customConfigService: new CustomConfigService(0.75), }); // Assess @@ -103,12 +77,6 @@ describe('Log sampling', () => { }, type: 'constructor', }, - { - options: { - customConfigService: new CustomConfigService(42), - }, - type: 'custom config service', - }, { options: {}, type: 'env variable',