Skip to content

Commit 8cdf207

Browse files
feat(helm): ✨ add METRICS_SCRAPE_INTERVAL and env support
Signed-off-by: Mario Vejlupek <[email protected]>
1 parent b1b4d8f commit 8cdf207

File tree

6 files changed

+172
-3
lines changed

6 files changed

+172
-3
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
test:
2-
helm upgrade --install --debug -n customer-monitoring-system --set-file script_py=./tmp/script.py -f ./tmp/values.test.yaml s3-metrics ./helm
2+
helm upgrade --install --debug -n customer-monitoring-system --set-file script_py=./examples/s3-metrics.py -f ./tmp/values.test.yaml s3-metrics ./helm
33

44
template:
5-
helm template --debug --output-dir=./tmp/ -n customer-monitoring-system --set-file script_py=./tmp/script.py -f ./tmp/values.test.yaml s3-metrics ./helm
5+
helm template --debug --output-dir=./tmp/ -n customer-monitoring-system --set-file script_py=./examples/s3-metrics.py -f ./tmp/values.test.yaml s3-metrics ./helm
66

examples/rds-metrics.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import boto3
2+
from prometheus_client import Gauge, start_http_server
3+
import time
4+
from datetime import datetime,timedelta
5+
import os
6+
import logging
7+
from pythonjsonlogger import jsonlogger
8+
9+
logging.basicConfig(level=logging.INFO)
10+
11+
logger = logging.getLogger()
12+
13+
logHandler = logging.StreamHandler()
14+
formatter = jsonlogger.JsonFormatter()
15+
logHandler.setFormatter(formatter)
16+
logger.addHandler(logHandler)
17+
18+
logger.info({"state": "starting"})
19+
20+
# Create a CloudWatch client
21+
cloudwatch = boto3.client('cloudwatch', region_name=os.environ.get('AWS_REGION'))
22+
23+
# Create Prometheus metrics
24+
cpu_utilization_gauge = Gauge('AWS_RDS_CPUUtilization', 'CPU Utilization of RDS instance', ['DBInstanceIdentifier'])
25+
database_connections_gauge = Gauge('AWS_RDS_DatabaseConnections', 'Database Connections of RDS instance', ['DBInstanceIdentifier'])
26+
volume_bytes_used_gauge = Gauge('AWS_RDS_VolumeBytesUsed', 'Volume Bytes Used of RDS instance', ['DBInstanceIdentifier'])
27+
cpu_credits_gauge = Gauge('AWS_RDS_CPUcredits', 'CPU credits of RDS instance', ['DBInstanceIdentifier'])
28+
freeable_memory_gauge = Gauge('AWS_RDS_FreeableMemory', 'Freeable Memory of RDS instance', ['DBInstanceIdentifier'])
29+
30+
# Start the HTTP server to expose the metrics
31+
start_http_server(8000)
32+
33+
def parse_time_string(time_string):
34+
value = int(time_string[:-1])
35+
unit = time_string[-1]
36+
37+
if unit == 's':
38+
return timedelta(seconds=value)
39+
elif unit == 'm':
40+
return timedelta(minutes=value)
41+
elif unit == 'h':
42+
return timedelta(hours=value)
43+
else:
44+
raise ValueError(f"Unknown time unit: {unit}")
45+
46+
47+
def get_metric_value(metric_name, db_instance_id):
48+
response = cloudwatch.get_metric_data(
49+
MetricDataQueries=[
50+
{
51+
'Id': 'm1',
52+
'MetricStat': {
53+
'Metric': {
54+
'Namespace': 'AWS/RDS',
55+
'MetricName': metric_name,
56+
'Dimensions': [
57+
{
58+
'Name': 'DBInstanceIdentifier',
59+
'Value': db_instance_id
60+
},
61+
]
62+
},
63+
'Period': 300,
64+
'Stat': 'Average',
65+
},
66+
'ReturnData': True,
67+
},
68+
],
69+
StartTime=(datetime.now() - parse_time_string(os.environ.get('METRICS_SCRAPE_INTERVAL'))).timestamp(),
70+
EndTime=datetime.now().timestamp(),
71+
)
72+
73+
return response['MetricDataResults'][0]['Values'][0] if response['MetricDataResults'][0]['Values'] else None
74+
75+
def collect_metrics():
76+
rds_client = boto3.client('rds', region_name=os.environ.get('AWS_REGION'))
77+
instances = rds_client.describe_db_instances()
78+
79+
for instance in instances['DBInstances']:
80+
db_instance_id = instance['DBInstanceIdentifier']
81+
logger.info({"state": "processing", "db_instance_id": db_instance_id, "message": "Processing rds instance"})
82+
83+
cpu_utilization = get_metric_value('CPUUtilization', db_instance_id)
84+
if cpu_utilization is not None:
85+
cpu_utilization_gauge.labels(DBInstanceIdentifier=db_instance_id).set(cpu_utilization)
86+
87+
database_connections = get_metric_value('DatabaseConnections', db_instance_id)
88+
if database_connections is not None:
89+
database_connections_gauge.labels(DBInstanceIdentifier=db_instance_id).set(database_connections)
90+
91+
volume_bytes_used = get_metric_value('VolumeBytesUsed', db_instance_id)
92+
if volume_bytes_used is not None:
93+
volume_bytes_used_gauge.labels(DBInstanceIdentifier=db_instance_id).set(volume_bytes_used)
94+
95+
cpu_credits = get_metric_value('CPUCreditBalance', db_instance_id)
96+
if cpu_credits is not None:
97+
cpu_credits_gauge.labels(DBInstanceIdentifier=db_instance_id).set(cpu_credits)
98+
99+
freeable_memory = get_metric_value('FreeableMemory', db_instance_id)
100+
if freeable_memory is not None:
101+
freeable_memory_gauge.labels(DBInstanceIdentifier=db_instance_id).set(freeable_memory)
102+
while True:
103+
collect_metrics()
104+
time.sleep(60) # Collect metrics every minute

examples/s3-metrics.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import os
2+
import boto3
3+
from prometheus_client import start_http_server, Gauge
4+
import time
5+
import logging
6+
from pythonjsonlogger import jsonlogger
7+
8+
logging.basicConfig(level=logging.INFO)
9+
10+
logger = logging.getLogger()
11+
12+
logHandler = logging.StreamHandler()
13+
formatter = jsonlogger.JsonFormatter()
14+
logHandler.setFormatter(formatter)
15+
logger.addHandler(logHandler)
16+
17+
logger.info({"state": "starting"})
18+
19+
# Create a Gauge metric for Prometheus
20+
s3_bucket_folder_size = Gauge('s3_bucket_folder_size', 'Size of the S3 bucket folders', ['bucket', 'folder'])
21+
22+
def get_s3_bucket_folder_sizes(bucket_name):
23+
logger.info({"state": "processing", "bucket": bucket_name, "message": "Getting folder sizes"})
24+
s3 = boto3.client('s3')
25+
paginator = s3.get_paginator('list_objects_v2')
26+
27+
folder_sizes = {}
28+
29+
for page in paginator.paginate(Bucket=bucket_name, Delimiter='/'):
30+
for prefix in page.get('CommonPrefixes', []):
31+
folder = prefix['Prefix']
32+
size = 0
33+
for obj in s3.list_objects_v2(Bucket=bucket_name, Prefix=folder)['Contents']:
34+
size += obj['Size']
35+
folder_sizes[folder.rstrip('/')] = size
36+
37+
return folder_sizes
38+
39+
def update_metrics(bucket_names):
40+
for bucket in bucket_names:
41+
folder_sizes = get_s3_bucket_folder_sizes(bucket)
42+
for folder, size in folder_sizes.items():
43+
s3_bucket_folder_size.labels(bucket=bucket, folder=folder).set(size)
44+
45+
if __name__ == '__main__':
46+
# Start up the server to expose the metrics.
47+
start_http_server(8000)
48+
49+
# List of bucket names
50+
buckets = os.environ.get('S3_BUCKET_NAMES').split(',')
51+
52+
# Update metrics every minute
53+
while True:
54+
update_metrics(buckets)
55+
time.sleep(60)

helm/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
apiVersion: v2
22
name: python-aws-exporter-base
33
description: Base image for Python scripts exporting AWS resources using boto library to Prometheus
4-
version: 3.0.0
4+
version: 4.0.0
55
appVersion: v3.0

helm/templates/deployment.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ spec:
3333
- name: http
3434
containerPort: 8000
3535
env:
36+
{{- range $key, $value := .Values.env }}
37+
- name: {{ $key }}
38+
value: {{ $value | quote }}
39+
{{- end }}
40+
41+
- name: METRICS_SCRAPE_INTERVAL
42+
value: {{ .Values.metrics_scrape_interval }}
3643
- name: AWS_ACCESS_KEY_ID
3744
valueFrom:
3845
secretKeyRef:

helm/values.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ aws:
55
secret_access_key:
66
region:
77

8+
env:
9+
S3_BUCKET_NAMES: "bucket1,bucket2"
10+
811
script_py: |
912
while True:
1013
print("Hello World")

0 commit comments

Comments
 (0)