Skip to content

Commit c862287

Browse files
HimtanayaHimtanaya Bhadada
and
Himtanaya Bhadada
authored
Support 30 dimensions per dimension set (#121)
* Support 30 dimensions per dimension set * Bump version to 3.0.0 Co-authored-by: Himtanaya Bhadada <[email protected]>
1 parent c9d19c9 commit c862287

File tree

8 files changed

+106
-32
lines changed

8 files changed

+106
-32
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "aws-embedded-metrics",
3-
"version": "2.0.6",
3+
"version": "3.0.0",
44
"description": "AWS Embedded Metrics Client Library",
55
"main": "lib/index.js",
66
"types": "lib/index.d.ts",

src/Constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
*/
1515

1616
export enum Constants {
17-
MAX_DIMENSIONS = 9,
17+
MAX_DIMENSION_SET_SIZE = 30,
1818
DEFAULT_NAMESPACE = 'aws-embedded-metrics',
1919
MAX_METRICS_PER_EVENT = 100,
2020
MAX_VALUES_PER_METRIC = 100,
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export class DimensionSetExceededError extends Error {
2+
constructor(msg: string) {
3+
super(msg);
4+
5+
// Set the prototype explicitly.
6+
Object.setPrototypeOf(this, DimensionSetExceededError.prototype);
7+
}
8+
}

src/logger/MetricsContext.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import Configuration from '../config/Configuration';
1717
import { LOG } from '../utils/Logger';
1818
import { MetricValues } from './MetricValues';
1919
import { Unit } from './Unit';
20+
import { Constants } from '../Constants';
21+
import { DimensionSetExceededError } from '../exceptions/DimensionSetExceededError';
2022

2123
interface IProperties {
2224
[s: string]: unknown;
@@ -104,13 +106,26 @@ export class MetricsContext {
104106
this.defaultDimensions = dimensions;
105107
}
106108

109+
/**
110+
* Validates dimension set length is not more than Constants.MAX_DIMENSION_SET_SIZE
111+
*
112+
* @param dimensionSet
113+
*/
114+
public static validateDimensionSet(dimensionSet: Record<string, string>): void {
115+
if (Object.keys(dimensionSet).length > Constants.MAX_DIMENSION_SET_SIZE)
116+
throw new DimensionSetExceededError(
117+
`Maximum number of dimensions per dimension set allowed are ${Constants.MAX_DIMENSION_SET_SIZE}`)
118+
}
119+
107120
/**
108121
* Adds a new set of dimensions. Any time a new dimensions set
109122
* is added, the set is first prepended by the default dimensions.
110123
*
111124
* @param dimensions
112125
*/
113126
public putDimensions(incomingDimensionSet: Record<string, string>): void {
127+
MetricsContext.validateDimensionSet(incomingDimensionSet)
128+
114129
if (this.dimensions.length === 0) {
115130
this.dimensions.push(incomingDimensionSet);
116131
return;
@@ -147,6 +162,9 @@ export class MetricsContext {
147162
*/
148163
public setDimensions(dimensionSets: Array<Record<string, string>>): void {
149164
this.shouldUseDefaultDimensions = false;
165+
166+
dimensionSets.forEach(dimensionSet => MetricsContext.validateDimensionSet(dimensionSet))
167+
150168
this.dimensions = dimensionSets;
151169
}
152170

src/logger/__tests__/MetricsContext.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as faker from 'faker';
22
import { MetricsContext } from '../MetricsContext';
3+
import { DimensionSetExceededError } from '../../exceptions/DimensionSetExceededError';
34

45
test('can set property', () => {
56
// arrange
@@ -16,6 +17,19 @@ test('can set property', () => {
1617
expect(actualValue).toBe(expectedValue);
1718
});
1819

20+
test('setDimensions allows 30 dimensions', () => {
21+
// arrange
22+
const context = MetricsContext.empty();
23+
const numOfDimensions = 30
24+
const expectedDimensionSet = getDimensionSet(numOfDimensions);
25+
26+
// act
27+
context.setDimensions([expectedDimensionSet]);
28+
29+
// assert
30+
expect(context.getDimensions()[0]).toStrictEqual(expectedDimensionSet);
31+
});
32+
1933
test('putDimension adds key to dimension and sets the dimension as a property', () => {
2034
// arrange
2135
const context = MetricsContext.empty();
@@ -203,3 +217,34 @@ test('createCopyWithContext copies shouldUseDefaultDimensions', () => {
203217
expect(newContext).not.toBe(context);
204218
expect(newContext.getDimensions()).toEqual([]);
205219
});
220+
221+
test('putDimensions checks the dimension set length', () => {
222+
// arrange
223+
const context = MetricsContext.empty();
224+
const numOfDimensions = 33
225+
226+
expect(() => {
227+
context.putDimensions(getDimensionSet(numOfDimensions))
228+
}).toThrow(DimensionSetExceededError);
229+
});
230+
231+
test('setDimensions checks all the dimension sets have less than 30 dimensions', () => {
232+
// arrange
233+
const context = MetricsContext.empty();
234+
const numOfDimensions = 33
235+
236+
expect(() => {
237+
context.setDimensions([getDimensionSet(numOfDimensions)])
238+
}).toThrow(DimensionSetExceededError);
239+
});
240+
241+
const getDimensionSet = (numOfDimensions: number) => {
242+
const dimensionSet:Record<string, string> = {}
243+
244+
for (let i = 0; i < numOfDimensions; i++) {
245+
const expectedKey = `${i}`;
246+
dimensionSet[expectedKey] = faker.random.word();
247+
}
248+
249+
return dimensionSet;
250+
}

src/serializers/LogSerializer.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import { MaxHeap } from '@datastructures-js/heap';
1616

1717
import { Constants } from '../Constants';
18+
import { DimensionSetExceededError } from '../exceptions/DimensionSetExceededError';
1819
import { MetricsContext } from '../logger/MetricsContext';
1920
import { ISerializer } from './Serializer';
2021

@@ -44,7 +45,12 @@ export class LogSerializer implements ISerializer {
4445
// support more dimensions
4546
// in the future it may make sense to introduce a higher-order
4647
// representation for sink-specific validations
47-
const keys = Object.keys(d).slice(0, Constants.MAX_DIMENSIONS);
48+
const keys = Object.keys(d);
49+
if (keys.length > Constants.MAX_DIMENSION_SET_SIZE) {
50+
const errMsg = `Maximum number of dimensions allowed are ${Constants.MAX_DIMENSION_SET_SIZE}.` +
51+
`Account for default dimensions if not using set_dimensions.`;
52+
throw new DimensionSetExceededError(errMsg)
53+
}
4854
dimensionKeys.push(keys);
4955
dimensionProperties = { ...dimensionProperties, ...d };
5056
});

src/serializers/__tests__/LogSerializer.test.ts

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as faker from 'faker';
22
import { Constants } from '../../Constants';
33
import { MetricsContext } from '../../logger/MetricsContext';
44
import { LogSerializer } from '../LogSerializer';
5+
import { DimensionSetExceededError } from '../../exceptions/DimensionSetExceededError';
56

67
test('serializes dimensions', () => {
78
// arrange
@@ -22,33 +23,6 @@ test('serializes dimensions', () => {
2223
assertJsonEquality(resultJson, expected);
2324
});
2425

25-
test('cannot serialize more than 9 dimensions', () => {
26-
// arrange
27-
const dimensions: any = {};
28-
const dimensionPointers = [];
29-
const allowedDimensions = 9;
30-
const dimensionsToAdd = 11;
31-
for (let i = 0; i < dimensionsToAdd; i++) {
32-
const expectedKey = `${i}`;
33-
const expectedValue = faker.random.word();
34-
dimensions[expectedKey] = expectedValue;
35-
dimensionPointers.push(expectedKey);
36-
}
37-
38-
const expectedDimensionPointers = dimensionPointers.slice(0, allowedDimensions);
39-
40-
const expected: any = { ...getEmptyPayload(), ...dimensions };
41-
expected._aws.CloudWatchMetrics[0].Dimensions.push(expectedDimensionPointers);
42-
43-
const context = getContext();
44-
context.putDimensions(dimensions);
45-
// act
46-
const resultJson = serializer.serialize(context)[0];
47-
48-
// assert
49-
assertJsonEquality(resultJson, expected);
50-
});
51-
5226
test('serializes properties', () => {
5327
// arrange
5428
const expectedKey = faker.random.word();
@@ -187,6 +161,29 @@ test('serializes metrics with more than 100 values each into multiple events', (
187161
}
188162
});
189163

164+
test('cannot serialize more than 30 dimensions', () => {
165+
// arrange
166+
const context = MetricsContext.empty();
167+
const defaultDimensionKey = faker.random.word();
168+
const defaultDimensionValue = faker.random.word();
169+
const numOfCustomDimensions = 30;
170+
const dimensionSet: Record<string, string> = {};
171+
172+
for (let i = 0; i < numOfCustomDimensions; i++) {
173+
const expectedKey = `${i}`;
174+
dimensionSet[expectedKey] = faker.random.word();
175+
}
176+
177+
// act
178+
context.setDefaultDimensions({ [defaultDimensionKey]: defaultDimensionValue });
179+
context.putDimensions(dimensionSet);
180+
181+
// assert
182+
expect(() => {
183+
serializer.serialize(context)
184+
}).toThrow(DimensionSetExceededError);
185+
});
186+
190187
const assertJsonEquality = (resultJson: string, expectedObj: any) => {
191188
const actual = JSON.parse(resultJson);
192189
expect(actual).toStrictEqual(expectedObj);

0 commit comments

Comments
 (0)