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
Add cloudwatch Target #184
Changes from 4 commits
87e0a51
f44bb33
b198528
938f976
605fe53
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ Next release | |
|
||
Changes | ||
------- | ||
* Add CloudWatch target | ||
|
||
TBA | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
""" | ||
This is an exemplary Grafana board that uses a Cloudwatch datasource. | ||
|
||
The graph shows the Average CPU utilization from an ASG named "frontend-asg" | ||
""" | ||
|
||
from grafanalib.core import * | ||
from grafanalib.cloudwatch import CloudwatchTarget | ||
|
||
|
||
dashboard = Dashboard( | ||
title="Clowdwatch Stats", | ||
rows=[ | ||
Row(panels=[ | ||
Graph( | ||
title="Cloudwatch ASG", | ||
dataSource='Cloudwatch', | ||
targets=[ | ||
CloudwatchTarget( | ||
dimensions={ | ||
"AutoScalingGroupName": "frontend-asg", | ||
}, | ||
metricName="CPUUtilization", | ||
namespace="AWS/EC2", | ||
region="eu-west-1", | ||
statistics=["Average"], | ||
checkParams=True, | ||
), | ||
], | ||
yAxes=G.YAxes( | ||
YAxis(format=PERCENT_UNIT_FORMAT), | ||
YAxis(format=SHORT_FORMAT), | ||
), | ||
), | ||
]), | ||
], | ||
).auto_panel_ids() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
"""Helpers to create Cloudwatch-specific Grafana queries.""" | ||
|
||
import attr | ||
from attr.validators import instance_of | ||
|
||
|
||
@attr.s | ||
class CloudwatchTarget(object): | ||
""" | ||
Generates Cloudwatch target JSON structure. | ||
|
||
Grafana docs on using Cloudwatch: | ||
https://grafana.com/docs/features/datasources/cloudwatch/ | ||
AWS docs on Cloudwatch metrics: | ||
https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html | ||
|
||
:param alias: legend alias | ||
:param dimensions: Cloudwatch dimensions dict | ||
:param metricName: Cloudwatch metric nam | ||
:param namespace: CLoudwatch namespace | ||
:param period:Cloudwatch data period | ||
:param region: CLoudwatch region | ||
:param refId: target reference id | ||
:param statistics: Cloudwatch mathematic statistic | ||
:param checkParams: If false, disable cloudwatch checks | ||
""" | ||
alias = attr.ib(default="") | ||
dimensions = attr.ib(default={}, validator=instance_of(dict)) | ||
metricName = attr.ib(default="") | ||
namespace = attr.ib(default="") | ||
period = attr.ib(default="") | ||
region = attr.ib(default="default") | ||
refId = attr.ib(default="") | ||
statistics = attr.ib(default=["Average"], validator=instance_of(list)) | ||
checkParams = attr.ib(default=True, validator=instance_of(bool)) | ||
|
||
def to_json_data(self): | ||
if self.checkParams: | ||
self.__checkParameters() | ||
|
||
return { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
"alias": self.alias, | ||
"dimensions": self.dimensions, | ||
"expression": "", | ||
"highResolution": False, | ||
"id": "", | ||
"metricName": self.metricName, | ||
"namespace": self.namespace, | ||
"period": self.period, | ||
"refId": self.refId, | ||
"region": self.region, | ||
"returnData": False, | ||
"statistics": self.statistics | ||
}.update(self.dimensions) | ||
|
||
def __checkParameters(self): | ||
self.__checDimensions() | ||
self.__checkNamespace() | ||
self.__checkRegion() | ||
|
||
def __checkDimensions(self): | ||
if self.dimensions == {}: | ||
raise Exception( | ||
'You need to define a valid non empty dimensions dict variable' | ||
) | ||
|
||
def __checkNamespace(self): | ||
if not (self.namespace in validNamespaces): | ||
raise Exception( | ||
'"{}" is not valid Cloudwatch namespace'.format( | ||
self.namespace) | ||
) | ||
|
||
def __checkRegion(self): | ||
if not (self.region in validRegions): | ||
raise Exception( | ||
'"{}" is not valid AWS region'.format( | ||
self.region) | ||
) | ||
|
||
|
||
validNamespaces = [ | ||
"AWS/ApiGateway", | ||
"AWS/AppStream", | ||
"AWS/AppSync", | ||
"AWS/Athena", | ||
"AWS/Billing", | ||
"AWS/ACMPrivateCA", | ||
"AWS/CloudFront", | ||
"AWS/CloudHSM", | ||
"AWS/CloudSearch", | ||
"AWS/Logs", | ||
"AWS/CodeBuild", | ||
"AWS/Cognito", | ||
"AWS/Connect", | ||
"AWS/DataSync", | ||
"AWS/DMS", | ||
"AWS/DX", | ||
"AWS/DocDB", | ||
"AWS/DynamoDB", | ||
"AWS/EC2", | ||
"AWS/EC2Spot", | ||
"AWS/AutoScaling", | ||
"AWS/ElasticBeanstalk", | ||
"AWS/EBS", | ||
"AWS/ECS", | ||
"AWS/EFS", | ||
"AWS/ElasticInference", | ||
"AWS/ApplicationELB", | ||
"AWS/ELB", | ||
"AWS/NetworkELB", | ||
"AWS/ElasticTranscoder", | ||
"AWS/ElastiCache", | ||
"AWS/ElastiCache", | ||
"AWS/ES", | ||
"AWS/ElasticMapReduce", | ||
"AWS/MediaConnect", | ||
"AWS/MediaConvert", | ||
"AWS/MediaPackage", | ||
"AWS/MediaTailor", | ||
"AWS/Events", | ||
"AWS/FSx", | ||
"AWS/FSx", | ||
"AWS/GameLift", | ||
"AWS/Glue", | ||
"AWS/Inspector", | ||
"AWS/IoT", | ||
"AWS/IoTAnalytics", | ||
"AWS/ThingsGraph", | ||
"AWS/KMS", | ||
"AWS/KinesisAnalytics", | ||
"AWS/Firehose", | ||
"AWS/Kinesis", | ||
"AWS/KinesisVideo", | ||
"AWS/Lambda", | ||
"AWS/Lex", | ||
"AWS/ML", | ||
"AWS/Kafka", | ||
"AWS/AmazonMQ", | ||
"AWS/Neptune", | ||
"AWS/OpsWorks", | ||
"AWS/Polly", | ||
"AWS/QLDB", | ||
"AWS/Redshift", | ||
"AWS/RDS", | ||
"AWS/Robomaker", | ||
"AWS/Route53", | ||
"AWS/SageMaker", | ||
"AWS/SDKMetrics", | ||
"AWS/DDoSProtection", | ||
"AWS/SES", | ||
"AWS/SNS", | ||
"AWS/SQS", | ||
"AWS/S3", | ||
"AWS/SWF", | ||
"AWS/States", | ||
"AWS/StorageGateway", | ||
"AWS/Textract", | ||
"AWS/Transfer", | ||
"AWS/Translate", | ||
"AWS/TrustedAdvisor", | ||
"AWS/NATGateway", | ||
"AWS/TransitGateway", | ||
"AWS/VPN", | ||
"AWS/WorkMail", | ||
"AWS/WorkSpaces", | ||
] | ||
|
||
validRegions = [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to use something like https://stackoverflow.com/a/38451512 here? |
||
"us-east-1", | ||
"us-east-2", | ||
"us-west-1", | ||
"us-west-2", | ||
"ap-east-1", | ||
"ap-south-1", | ||
"ap-southeast-1", | ||
"ap-northeast-2", | ||
"ap-northeast-3", | ||
"ap-northeast-1", | ||
"ap-southeast-2", | ||
"ca-central-1", | ||
"cn-north-1", | ||
"cn-northwest-1", | ||
"eu-central-1", | ||
"eu-west-1", | ||
"eu-west-2", | ||
"eu-west-3", | ||
"eu-north-1", | ||
"me-south-1", | ||
"sa-east-1", | ||
"us-gov-east-1", | ||
"us-gov-west-1", | ||
"default", | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ | |
envlist = py27, py35, py37 | ||
|
||
[testenv] | ||
commands = pytest --junitxml=test-results/junit-{envname}.xml | ||
commands = pytest -o junit_family=xunit2 --junitxml=test-results/junit-{envname}.xml | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updating to new junit_family, related with: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we make this a separate PR maybe? It definitely makes sense: .tox/py37/lib/python3.7/site-packages/_pytest/junitxml.py:436
/home/daniel/dev/grafanalib/.tox/py37/lib/python3.7/site-packages/_pytest/junitxml.py:436: PytestDeprecationWarning: The 'junit_family' default value will change to 'xunit2' in pytest 6.0.
Add 'junit_family=xunit1' to your pytest.ini file to keep the current format in future versions of pytest and silence this warning.
_issue_warning_captured(deprecated.JUNIT_XML_DEFAULT_FAMILY, config.hook, 2) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved it to #236 |
||
deps = | ||
pytest | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo here but it's inconsequential