Skip to content

Commit

Permalink
feat(metrics): disable metrics with POWERTOOLS_METRICS_DISABLED (#3351
Browse files Browse the repository at this point in the history
)

Co-authored-by: Andrea Amorosi <[email protected]>
  • Loading branch information
zirkelc and dreamorosi authored Nov 25, 2024
1 parent b692b79 commit 7e8578e
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 2 deletions.
11 changes: 11 additions & 0 deletions packages/commons/src/config/EnvironmentVariablesService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ class EnvironmentVariablesService implements ConfigServiceInterface {
return truthyValues.includes(value.toLowerCase());
}

/**
* Helper function to determine if a value is considered falsy.
*
* @param value The value to check for falsiness.
*/
public isValueFalse(value: string): boolean {
const falsyValues: string[] = ['0', 'n', 'no', 'f', 'false', 'off'];

return falsyValues.includes(value.toLowerCase());
}

/**
* Get the AWS X-Ray Trace data from the environment variable.
*
Expand Down
31 changes: 31 additions & 0 deletions packages/commons/tests/unit/EnvironmentVariablesService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,37 @@ describe('Class: EnvironmentVariablesService', () => {
);
});

describe('Method: isValueFalse', () => {
const valuesToTest: Array<Array<string | boolean>> = [
['0', true],
['n', true],
['no', true],
['f', true],
['FALSE', true],
['off', true],
['1', false],
['y', false],
['yes', false],
['t', false],
['TRUE', false],
['on', false],
['', false],
['somethingsilly', false],
];

it.each(valuesToTest)(
'takes string "%s" and returns %s',
(input, output) => {
// Prepare
const service = new EnvironmentVariablesService();
// Act
const value = service.isValueFalse(input as string);
// Assess
expect(value).toBe(output);
}
);
});

describe('Method: isDevMode', () => {
it('returns true if the environment variable POWERTOOLS_DEV is "true"', () => {
// Prepare
Expand Down
30 changes: 28 additions & 2 deletions packages/metrics/src/Metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@ class Metrics extends Utility implements MetricsInterface {
*/
private storedMetrics: StoredMetrics = {};

/**
* Whether to disable metrics
*/
private disabled = false;

/**
* Custom timestamp for the metrics
*/
Expand Down Expand Up @@ -472,6 +477,13 @@ class Metrics extends Utility implements MetricsInterface {
return Object.keys(this.storedMetrics).length > 0;
}

/**
* Whether metrics are disabled.
*/
protected isDisabled(): boolean {
return this.disabled;
}

/**
* A class method decorator to automatically log metrics after the method returns or throws an error.
*
Expand Down Expand Up @@ -579,8 +591,12 @@ class Metrics extends Utility implements MetricsInterface {
'If application metrics should never be empty, consider using `throwOnEmptyMetrics`'
);
}
const emfOutput = this.serializeMetrics();
hasMetrics && this.console.log(JSON.stringify(emfOutput));

if (!this.disabled) {
const emfOutput = this.serializeMetrics();
hasMetrics && this.console.log(JSON.stringify(emfOutput));
}

this.clearMetrics();
this.clearDimensions();
this.clearMetadata();
Expand Down Expand Up @@ -913,6 +929,15 @@ class Metrics extends Utility implements MetricsInterface {
this.getEnvVarsService().getNamespace()) as string;
}

/**
* Set the disbaled flag based on the environment variables `POWERTOOLS_METRICS_DISABLED` and `POWERTOOLS_DEV`.
*
* The `POWERTOOLS_METRICS_DISABLED` environment variable takes precedence over `POWERTOOLS_DEV`.
*/
private setDisabled(): void {
this.disabled = this.getEnvVarsService().getMetricsDisabled();
}

/**
* Set the options to be used by the Metrics instance.
*
Expand All @@ -932,6 +957,7 @@ class Metrics extends Utility implements MetricsInterface {
this.setEnvVarsService();
this.setConsole();
this.setCustomConfigService(customConfigService);
this.setDisabled();
this.setNamespace(namespace);
this.setService(serviceName);
this.setDefaultDimensions(defaultDimensions);
Expand Down
17 changes: 17 additions & 0 deletions packages/metrics/src/config/EnvironmentVariablesService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,29 @@ class EnvironmentVariablesService
{
private namespaceVariable = 'POWERTOOLS_METRICS_NAMESPACE';

private readonly disabledVariable = 'POWERTOOLS_METRICS_DISABLED';

/**
* Get the value of the `POWERTOOLS_METRICS_NAMESPACE` environment variable.
*/
public getNamespace(): string {
return this.get(this.namespaceVariable);
}

/**
* Get the value of the `POWERTOOLS_METRICS_DISABLED` or `POWERTOOLS_DEV` environment variables.
*
* The `POWERTOOLS_METRICS_DISABLED` environment variable takes precedence over `POWERTOOLS_DEV`.
*/
public getMetricsDisabled(): boolean {
const value = this.get(this.disabledVariable);

if (this.isValueFalse(value)) return false;
if (this.isValueTrue(value)) return true;
if (this.isDevMode()) return true;

return false;
}
}

export { EnvironmentVariablesService };
71 changes: 71 additions & 0 deletions packages/metrics/tests/unit/Metrics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1430,6 +1430,29 @@ describe('Class: Metrics', () => {
expect(consoleLogSpy).toBeCalledWith(JSON.stringify(mockData));
});

test('it should not log anything if metrics are disabled', () => {
// Prepare
process.env.POWERTOOLS_METRICS_DISABLED = 'true';
const customLogger = {
log: jest.fn(),
warn: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
info: jest.fn(),
};
const metrics: Metrics = new Metrics({
namespace: TEST_NAMESPACE,
logger: customLogger,
});
const consoleLogSpy = jest.spyOn(customLogger, 'log');

// Act
metrics.publishStoredMetrics();

// Assess
expect(consoleLogSpy).toHaveBeenCalledTimes(0);
});

test('it should call clearMetrics function', () => {
// Prepare
const metrics: Metrics = new Metrics({ namespace: TEST_NAMESPACE });
Expand Down Expand Up @@ -2355,6 +2378,54 @@ describe('Class: Metrics', () => {
});
});

describe('Method: isDisabled', () => {
it('should be enabled by default', () => {
const metrics: Metrics = new Metrics({ namespace: TEST_NAMESPACE });

// Act & Assess
// biome-ignore lint/complexity/useLiteralKeys: accessing protected method
expect(metrics['isDisabled']()).toBe(false);
});

it('should be disabled if POWERTOOLS_DEV is set to true', () => {
process.env.POWERTOOLS_DEV = 'true';
const metrics: Metrics = new Metrics({ namespace: TEST_NAMESPACE });

// Act & Assess
// biome-ignore lint/complexity/useLiteralKeys: accessing protected method
expect(metrics['isDisabled']()).toBe(true);
});

it('should be disabled if POWERTOOLS_METRICS_DISABLED is set to true', () => {
// Prepare
process.env.POWERTOOLS_METRICS_DISABLED = 'true';
const metrics: Metrics = new Metrics({ namespace: TEST_NAMESPACE });

// Act & Assess
// biome-ignore lint/complexity/useLiteralKeys: accessing protected method
expect(metrics['isDisabled']()).toBe(true);
});

it('should be enabled if POWERTOOLS_METRICS_DISABLED is set to false', () => {
process.env.POWERTOOLS_METRICS_DISABLED = 'false';
const metrics: Metrics = new Metrics({ namespace: TEST_NAMESPACE });

// Act & Assess
// biome-ignore lint/complexity/useLiteralKeys: accessing protected method
expect(metrics['isDisabled']()).toBe(false);
});

it('should be enabled if POWERTOOLS_DEV is set to true and POWERTOOLS_METRICS_DISABLED is set to false', () => {
process.env.POWERTOOLS_DEV = 'true';
process.env.POWERTOOLS_METRICS_DISABLED = 'false';
const metrics: Metrics = new Metrics({ namespace: TEST_NAMESPACE });

// Act & Assess
// biome-ignore lint/complexity/useLiteralKeys: accessing protected method
expect(metrics['isDisabled']()).toBe(false);
});
});

describe('Method: setTimestamp', () => {
const testCases = [
{
Expand Down

0 comments on commit 7e8578e

Please sign in to comment.