cloudwatch: filter 'dimensions' for get_metric_data (#5041)
This commit is contained in:
parent
e63fc08db2
commit
f8c2b621db
@ -41,6 +41,9 @@ class Dimension(object):
|
|||||||
def __ne__(self, item): # Only needed on Py2; Py3 defines it implicitly
|
def __ne__(self, item): # Only needed on Py2; Py3 defines it implicitly
|
||||||
return self != item
|
return self != item
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return self.name < other.name and self.value < other.name
|
||||||
|
|
||||||
|
|
||||||
class Metric(object):
|
class Metric(object):
|
||||||
def __init__(self, metric_name, namespace, dimensions):
|
def __init__(self, metric_name, namespace, dimensions):
|
||||||
@ -478,6 +481,7 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
query_ns = query["metric_stat._metric._namespace"]
|
query_ns = query["metric_stat._metric._namespace"]
|
||||||
query_name = query["metric_stat._metric._metric_name"]
|
query_name = query["metric_stat._metric._metric_name"]
|
||||||
delta = timedelta(seconds=int(query["metric_stat._period"]))
|
delta = timedelta(seconds=int(query["metric_stat._period"]))
|
||||||
|
dimensions = self._extract_dimensions_from_get_metric_data_query(query)
|
||||||
result_vals = []
|
result_vals = []
|
||||||
timestamps = []
|
timestamps = []
|
||||||
stat = query["metric_stat._stat"]
|
stat = query["metric_stat._stat"]
|
||||||
@ -494,11 +498,19 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
for md in period_md
|
for md in period_md
|
||||||
if md.namespace == query_ns and md.name == query_name
|
if md.namespace == query_ns and md.name == query_name
|
||||||
]
|
]
|
||||||
|
if dimensions:
|
||||||
|
query_period_data = [
|
||||||
|
md
|
||||||
|
for md in period_md
|
||||||
|
if sorted(md.dimensions) == sorted(dimensions)
|
||||||
|
]
|
||||||
|
|
||||||
metric_values = [m.value for m in query_period_data]
|
metric_values = [m.value for m in query_period_data]
|
||||||
|
|
||||||
if len(metric_values) > 0:
|
if len(metric_values) > 0:
|
||||||
if stat == "Average":
|
if stat == "SampleCount":
|
||||||
|
result_vals.append(len(metric_values))
|
||||||
|
elif stat == "Average":
|
||||||
result_vals.append(sum(metric_values) / len(metric_values))
|
result_vals.append(sum(metric_values) / len(metric_values))
|
||||||
elif stat == "Minimum":
|
elif stat == "Minimum":
|
||||||
result_vals.append(min(metric_values))
|
result_vals.append(min(metric_values))
|
||||||
@ -679,5 +691,20 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
else:
|
else:
|
||||||
return None, metrics
|
return None, metrics
|
||||||
|
|
||||||
|
def _extract_dimensions_from_get_metric_data_query(self, query):
|
||||||
|
dimensions = []
|
||||||
|
prefix = "metric_stat._metric._dimensions.member."
|
||||||
|
suffix_name = "._name"
|
||||||
|
suffix_value = "._value"
|
||||||
|
counter = 1
|
||||||
|
|
||||||
|
while query.get(f"{prefix}{counter}{suffix_name}") and counter <= 10:
|
||||||
|
name = query.get(f"{prefix}{counter}{suffix_name}")
|
||||||
|
value = query.get(f"{prefix}{counter}{suffix_value}")
|
||||||
|
dimensions.append(Dimension(name=name, value=value))
|
||||||
|
counter = counter + 1
|
||||||
|
|
||||||
|
return dimensions
|
||||||
|
|
||||||
|
|
||||||
cloudwatch_backends = BackendDict(CloudWatchBackend, "cloudwatch")
|
cloudwatch_backends = BackendDict(CloudWatchBackend, "cloudwatch")
|
||||||
|
@ -785,6 +785,114 @@ def test_get_metric_data_for_multiple_metrics():
|
|||||||
res2["Values"].should.equal([25.0])
|
res2["Values"].should.equal([25.0])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudwatch
|
||||||
|
def test_get_metric_data_for_dimensions():
|
||||||
|
utc_now = datetime.now(tz=pytz.utc)
|
||||||
|
cloudwatch = boto3.client("cloudwatch", "eu-west-1")
|
||||||
|
namespace = "my_namespace/"
|
||||||
|
|
||||||
|
# If the metric is created with multiple dimensions, then the data points for that metric can be retrieved only by specifying all the configured dimensions.
|
||||||
|
# https://aws.amazon.com/premiumsupport/knowledge-center/cloudwatch-getmetricstatistics-data/
|
||||||
|
server_prod = {"Name": "Server", "Value": "Prod"}
|
||||||
|
dimension_berlin = [server_prod, {"Name": "Domain", "Value": "Berlin"}]
|
||||||
|
dimension_frankfurt = [server_prod, {"Name": "Domain", "Value": "Frankfurt"}]
|
||||||
|
|
||||||
|
# put metric data
|
||||||
|
cloudwatch.put_metric_data(
|
||||||
|
Namespace=namespace,
|
||||||
|
MetricData=[
|
||||||
|
{
|
||||||
|
"MetricName": "metric1",
|
||||||
|
"Value": 50,
|
||||||
|
"Dimensions": dimension_berlin,
|
||||||
|
"Unit": "Seconds",
|
||||||
|
"Timestamp": utc_now,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
cloudwatch.put_metric_data(
|
||||||
|
Namespace=namespace,
|
||||||
|
MetricData=[
|
||||||
|
{
|
||||||
|
"MetricName": "metric1",
|
||||||
|
"Value": 25,
|
||||||
|
"Unit": "Seconds",
|
||||||
|
"Dimensions": dimension_frankfurt,
|
||||||
|
"Timestamp": utc_now,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
# get_metric_data
|
||||||
|
response = cloudwatch.get_metric_data(
|
||||||
|
MetricDataQueries=[
|
||||||
|
{
|
||||||
|
"Id": "result1",
|
||||||
|
"MetricStat": {
|
||||||
|
"Metric": {
|
||||||
|
"Namespace": namespace,
|
||||||
|
"MetricName": "metric1",
|
||||||
|
"Dimensions": dimension_frankfurt,
|
||||||
|
},
|
||||||
|
"Period": 60,
|
||||||
|
"Stat": "SampleCount",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "result2",
|
||||||
|
"MetricStat": {
|
||||||
|
"Metric": {
|
||||||
|
"Namespace": namespace,
|
||||||
|
"MetricName": "metric1",
|
||||||
|
"Dimensions": dimension_berlin,
|
||||||
|
},
|
||||||
|
"Period": 60,
|
||||||
|
"Stat": "Sum",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "result3",
|
||||||
|
"MetricStat": {
|
||||||
|
"Metric": {
|
||||||
|
"Namespace": namespace,
|
||||||
|
"MetricName": "metric1",
|
||||||
|
"Dimensions": [server_prod],
|
||||||
|
},
|
||||||
|
"Period": 60,
|
||||||
|
"Stat": "Sum",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "result4",
|
||||||
|
"MetricStat": {
|
||||||
|
"Metric": {"Namespace": namespace, "MetricName": "metric1"},
|
||||||
|
"Period": 60,
|
||||||
|
"Stat": "Sum",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
StartTime=utc_now - timedelta(seconds=60),
|
||||||
|
EndTime=utc_now + timedelta(seconds=60),
|
||||||
|
)
|
||||||
|
#
|
||||||
|
len(response["MetricDataResults"]).should.equal(4)
|
||||||
|
|
||||||
|
res1 = [res for res in response["MetricDataResults"] if res["Id"] == "result1"][0]
|
||||||
|
# expect sample count for dimension_frankfurt
|
||||||
|
res1["Values"].should.equal([1.0])
|
||||||
|
|
||||||
|
res2 = [res for res in response["MetricDataResults"] if res["Id"] == "result2"][0]
|
||||||
|
# expect sum for dimension_berlin
|
||||||
|
res2["Values"].should.equal([50.0])
|
||||||
|
|
||||||
|
res3 = [res for res in response["MetricDataResults"] if res["Id"] == "result3"][0]
|
||||||
|
# expect no result, as server_prod is only a part of other dimensions, e.g. there is no match
|
||||||
|
res3["Values"].should.equal([])
|
||||||
|
|
||||||
|
res4 = [res for res in response["MetricDataResults"] if res["Id"] == "result4"][0]
|
||||||
|
# expect sum of both metrics, as we did not filter for dimensions
|
||||||
|
res4["Values"].should.equal([75.0])
|
||||||
|
|
||||||
|
|
||||||
@mock_cloudwatch
|
@mock_cloudwatch
|
||||||
@mock_s3
|
@mock_s3
|
||||||
def test_cloudwatch_return_s3_metrics():
|
def test_cloudwatch_return_s3_metrics():
|
||||||
|
Loading…
Reference in New Issue
Block a user