Skip to content

Disallow duplicate dimension sets #85

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 6 commits into from
Aug 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions aws_embedded_metrics/logger/metrics_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from aws_embedded_metrics.constants import MAX_DIMENSION_SET_SIZE
from aws_embedded_metrics.exceptions import DimensionSetExceededError
from aws_embedded_metrics.logger.metric import Metric
from typing import List, Dict, Any
from typing import List, Dict, Any, Set


class MetricsContext(object):
Expand Down Expand Up @@ -66,20 +66,26 @@ def validate_dimension_set(dimensions: Dict[str, str]) -> None:
raise DimensionSetExceededError(
f"Maximum number of dimensions per dimension set allowed are {MAX_DIMENSION_SET_SIZE}")

def put_dimensions(self, dimensions: Dict[str, str]) -> None:
def put_dimensions(self, dimension_set: Dict[str, str]) -> None:
"""
Adds dimensions to the context.
```
context.put_dimensions({ "k1": "v1", "k2": "v2" })
```
"""
if dimensions is None:
if dimension_set is None:
# TODO add ability to define failure strategy
return

self.validate_dimension_set(dimensions)
self.validate_dimension_set(dimension_set)

self.dimensions.append(dimensions)
# Duplicate dimension sets are removed before being added to the end of the collection.
# This ensures only latest dimension value is used as a target member on the root EMF node.
# This operation is O(n^2), but acceptable given sets are capped at 30 dimensions
incoming_keys: Set = set(dimension_set.keys())
self.dimensions = list(filter(lambda dim: (set(dim.keys()) != incoming_keys), self.dimensions))

self.dimensions.append(dimension_set)

def set_dimensions(self, dimensionSets: List[Dict[str, str]]) -> None:
"""
Expand Down
101 changes: 101 additions & 0 deletions tests/logger/test_metrics_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,107 @@ def test_put_dimension_adds_to_dimensions():
assert context.dimensions == [dimension_set]


def test_put_dimensions_accept_multiple_unique_dimensions():
# arrange
context = MetricsContext()
dimension1 = {fake.word(): fake.word()}
dimension2 = {fake.word(): fake.word()}

# act
context.put_dimensions(dimension1)
context.put_dimensions(dimension2)

# assert
assert len(context.get_dimensions()) == 2
assert context.get_dimensions()[0] == dimension1
assert context.get_dimensions()[1] == dimension2


def test_put_dimensions_prevent_duplicate_dimensions():
# arrange
context = MetricsContext()
pair1 = [fake.word(), fake.word()]
pair2 = [fake.word(), fake.word()]

dimension1 = {pair1[0]: pair1[1]}
dimension2 = {pair2[0]: pair2[1]}
dimension3 = {pair1[0]: pair1[1], pair2[0]: pair2[1]}

# act
context.put_dimensions(dimension1)
context.put_dimensions(dimension2)
context.put_dimensions(dimension1)
context.put_dimensions(dimension3)
context.put_dimensions(dimension2)
context.put_dimensions(dimension3)

# assert
assert len(context.get_dimensions()) == 3
assert context.get_dimensions()[0] == dimension1
assert context.get_dimensions()[1] == dimension2
assert context.get_dimensions()[2] == dimension3


def test_put_dimensions_use_most_recent_dimension_value():
# arrange
context = MetricsContext()
key1 = fake.word()
key2 = fake.word()
val1 = fake.word()
val2 = fake.word()

dimension1 = {key1: val1}
dimension2 = {key2: val2}
dimension3 = {key1: val2}
dimension4 = {key2: val1}
dimension5 = {key1: val1, key2: val2}
dimension6 = {key1: val2, key2: val1}

# act
context.put_dimensions(dimension1)
context.put_dimensions(dimension2)
context.put_dimensions(dimension5)
context.put_dimensions(dimension3)
context.put_dimensions(dimension4)
context.put_dimensions(dimension6)

# assert
assert len(context.get_dimensions()) == 3
assert context.get_dimensions()[0] == dimension3
assert context.get_dimensions()[1] == dimension4
assert context.get_dimensions()[2] == dimension6


def test_put_dimensions_with_set_dimensions():
# arrange
context = MetricsContext()
key1 = fake.word()
key2 = fake.word()
val1 = fake.word()
val2 = fake.word()

dimension1 = {key1: val1}
dimension2 = {key2: val2}
dimension3 = {key1: val2}
dimension4 = {key2: val1}
dimension5 = {key1: val1, key2: val2}
dimension6 = {key1: val2, key2: val1}

# act
context.put_dimensions(dimension1)
context.put_dimensions(dimension2)
context.set_dimensions([dimension3])
context.put_dimensions(dimension4)
context.put_dimensions(dimension5)
context.put_dimensions(dimension6)

# assert
assert len(context.get_dimensions()) == 3
assert context.get_dimensions()[0] == dimension3
assert context.get_dimensions()[1] == dimension4
assert context.get_dimensions()[2] == dimension6


def test_get_dimensions_returns_only_custom_dimensions_if_no_default_dimensions_not_set():
# arrange
context = MetricsContext()
Expand Down