Skip to content

Commit 628fec7

Browse files
committed
feat: store integration test metrics in metrics.json
For each test store metrics it emits into a metrics.json file. This makes it easier to look at the metrics. Signed-off-by: Egor Lazarchuk <yegorlz@amazon.co.uk>
1 parent a85480d commit 628fec7

File tree

2 files changed

+42
-24
lines changed

2 files changed

+42
-24
lines changed

tests/conftest.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,18 @@ def pytest_runtest_logreport(report):
171171
METRICS.flush()
172172

173173

174+
@pytest.fixture
175+
def test_output_dir(results_dir, request):
176+
"""Create and return a test specific directory"""
177+
raw_data_path = Path(results_dir / request.node.name)
178+
if raw_data_path.is_dir():
179+
shutil.rmtree(raw_data_path)
180+
raw_data_path.mkdir(parents=True, exist_ok=True)
181+
return raw_data_path
182+
183+
174184
@pytest.fixture()
175-
def metrics(request):
185+
def metrics(test_output_dir, request):
176186
"""Fixture to pass the metrics scope
177187
178188
We use a fixture instead of the @metrics_scope decorator as that conflicts
@@ -188,6 +198,7 @@ def metrics(request):
188198
metrics_logger.set_property(prop_name, prop_val)
189199
yield metrics_logger
190200
metrics_logger.flush()
201+
metrics_logger.store_data(test_output_dir)
191202

192203

193204
@pytest.fixture

tests/host_tools/metrics.py

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,52 +46,59 @@
4646
import json
4747
import os
4848
import socket
49+
from pathlib import Path
4950
from urllib.parse import urlparse
5051

5152
from aws_embedded_metrics.constants import DEFAULT_NAMESPACE
5253
from aws_embedded_metrics.logger.metrics_logger_factory import create_metrics_logger
5354

5455

55-
class MetricsWrapperDummy:
56-
"""Send metrics to /dev/null"""
56+
class MetricsWrapper:
57+
"""A convenient metrics logger"""
58+
59+
def __init__(self, logger):
60+
self.data = {}
61+
self.logger = logger
5762

5863
def set_dimensions(self, *args, **kwargs):
5964
"""Set dimensions"""
65+
if self.logger:
66+
self.logger.set_dimensions(*args, **kwargs)
6067

61-
def put_metric(self, *args, **kwargs):
68+
def put_metric(self, name, data, unit):
6269
"""Put a datapoint with given dimensions"""
70+
if name not in self.data:
71+
self.data[name] = []
72+
self.data[name].append(data)
73+
74+
if self.logger:
75+
self.logger.put_metric(name, data, unit)
6376

6477
def set_property(self, *args, **kwargs):
6578
"""Set a property"""
79+
if self.logger:
80+
self.logger.set_property(*args, **kwargs)
6681

6782
def flush(self):
6883
"""Flush any remaining metrics"""
84+
if self.logger:
85+
asyncio.run(self.logger.flush())
6986

70-
71-
class MetricsWrapper:
72-
"""A convenient metrics logger"""
73-
74-
def __init__(self, logger):
75-
self.logger = logger
76-
77-
def __getattr__(self, attr):
78-
"""Dispatch methods to logger instance"""
79-
if attr not in self.__dict__:
80-
return getattr(self.logger, attr)
81-
return getattr(self, attr)
82-
83-
def flush(self):
84-
"""Flush any remaining metrics"""
85-
asyncio.run(self.logger.flush())
87+
def store_data(self, dir_path):
88+
"""Store data into a file"""
89+
metrics_path = Path(dir_path / "metrics.json")
90+
with open(metrics_path, "w", encoding="utf-8") as f:
91+
json.dump(self.data, f)
8692

8793

8894
def get_metrics_logger():
8995
"""Get a new metrics logger object"""
9096
# if no metrics namespace, don't output metrics
91-
if "AWS_EMF_NAMESPACE" not in os.environ:
92-
return MetricsWrapperDummy()
93-
logger = create_metrics_logger()
94-
logger.reset_dimensions(False)
97+
if "AWS_EMF_NAMESPACE" in os.environ:
98+
logger = create_metrics_logger()
99+
logger.reset_dimensions(False)
100+
else:
101+
logger = None
95102
return MetricsWrapper(logger)
96103

97104

0 commit comments

Comments
 (0)