Skip to content

Commit 9208e1f

Browse files
committed
feat: functionality to retrieve app memory, cpu and network metrics
1 parent da1aff2 commit 9208e1f

2 files changed

Lines changed: 186 additions & 0 deletions

File tree

app/controllers/app.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import json
2+
from prometheus_http_client import Prometheus
3+
from flask_restful import Resource, request
4+
5+
from app.helpers.authenticate import (
6+
jwt_required
7+
)
8+
from app.helpers.utils import get_app_data
9+
10+
class AppMemoryUsageView(Resource):
11+
@jwt_required
12+
def post(self, project_id, app_id):
13+
app = get_app_data(project_id, app_id, request)
14+
15+
if app.status_code != 200:
16+
return dict(status='fail', message=app.message), app.status_code
17+
18+
start = app.start
19+
end = app.end
20+
step = app.step
21+
app_alias = app.app_alias
22+
namespace = app.namespace
23+
prometheus = Prometheus()
24+
25+
try:
26+
prom_memory_data = prometheus.query_rang(
27+
start=start,
28+
end=end,
29+
step=step,
30+
metric='sum(rate(container_memory_usage_bytes{container_name!="POD", image!="",pod=~"' + app_alias + '.*", namespace="' + namespace + '"}[5m]))')
31+
except Exception as error:
32+
return dict(status='fail', message=str(error)), 500
33+
34+
new_data = json.loads(prom_memory_data)
35+
final_data_list = []
36+
37+
try:
38+
for value in new_data["data"]["result"][0]["values"]:
39+
mem_case = {'timestamp': float(
40+
value[0]), 'value': float(value[1])}
41+
final_data_list.append(mem_case)
42+
except:
43+
return dict(status='fail', message='No values found'), 404
44+
45+
return dict(status='success', data=dict(values=final_data_list)), 200
46+
47+
48+
class AppCpuUsageView(Resource):
49+
@jwt_required
50+
def post(self, project_id, app_id):
51+
app = get_app_data(project_id, app_id, request)
52+
53+
if app.status_code != 200:
54+
return dict(status='fail', message=app.message), app.status_code
55+
56+
start = app.start
57+
end = app.end
58+
step = app.step
59+
app_alias = app.app_alias
60+
namespace = app.namespace
61+
prometheus = Prometheus()
62+
63+
try:
64+
prom_cpu_data = prometheus.query_rang(
65+
start=start,
66+
end=end,
67+
step=step,
68+
metric='sum(rate(container_cpu_usage_seconds_total{container!="POD", image!="", namespace="' +
69+
namespace + '", pod=~"' + app_alias + '.*"}[5m]))')
70+
except Exception as error:
71+
return dict(status='fail', message=str(error)), 500
72+
73+
new_data = json.loads(prom_cpu_data)
74+
final_data_list = []
75+
76+
try:
77+
for value in new_data["data"]["result"][0]["values"]:
78+
case = {'timestamp': float(value[0]), 'value': float(value[1])}
79+
final_data_list.append(case)
80+
except:
81+
return dict(status='fail', message='No values found'), 404
82+
83+
return dict(status='success', data=dict(values=final_data_list)), 200
84+
85+
86+
class AppNetworkUsageView(Resource):
87+
@jwt_required
88+
def post(self, project_id, app_id):
89+
app = get_app_data(project_id, app_id, request)
90+
91+
if app.status_code != 200:
92+
return dict(status='fail', message=app.message), app.status_code
93+
94+
start = app.start
95+
end = app.end
96+
step = app.step
97+
app_alias = app.app_alias
98+
namespace = app.namespace
99+
prometheus = Prometheus()
100+
101+
try:
102+
prom_net_data = prometheus.query_rang(
103+
start=start,
104+
end=end,
105+
step=step,
106+
metric='sum(rate(container_network_receive_bytes_total{namespace="' +
107+
namespace + '", pod=~"' + app_alias + '.*"}[5m]))'
108+
)
109+
except Exception as error:
110+
return dict(status='fail', message=str(error)), 500
111+
112+
new_data = json.loads(prom_net_data)
113+
final_data_list = []
114+
115+
try:
116+
for value in new_data["data"]["result"][0]["values"]:
117+
case = {'timestamp': float(value[0]), 'value': float(value[1])}
118+
final_data_list.append(case)
119+
except:
120+
return dict(status='fail', message='No values found'), 404
121+
122+
return dict(status='success', data=dict(values=final_data_list)), 200

app/helpers/utils.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
PRODUCT_BASE_URL = os.getenv('PRODUCT_BASE_URL')
88
PROJECT_ENDPOINT = f"{PRODUCT_BASE_URL}/projects"
9+
APP_ENDPOINT = f"{PRODUCT_BASE_URL}/apps"
910

1011

1112
def get_project_data(project_id, request):
@@ -52,3 +53,66 @@ def get_project_data(project_id, request):
5253
namespace=namespace,
5354
status_code=200
5455
)
56+
57+
58+
def get_app_data(project_id, app_id, request):
59+
app_query_data = request.get_json()
60+
61+
metric_schema = MetricsSchema()
62+
63+
validated_query_data = metric_schema.load(
64+
app_query_data)
65+
66+
# if errors:
67+
# return dict(status='fail', message=errors), 400
68+
69+
current_time = datetime.datetime.now()
70+
yesterday_time = current_time + datetime.timedelta(days=-1)
71+
72+
start = validated_query_data.get('start', yesterday_time.timestamp())
73+
end = validated_query_data.get('end', current_time.timestamp())
74+
step = validated_query_data.get('step', '1h')
75+
76+
# get project details
77+
project_response = requests.get(
78+
f"{PROJECT_ENDPOINT}/{project_id}", headers={
79+
"accept": "application/json",
80+
"Authorization": request.headers.get('Authorization')
81+
})
82+
83+
if not project_response.ok:
84+
return SimpleNamespace(status='failed', message="Failed to fetch project for current user", status_code=400)
85+
86+
project_response = project_response.json()
87+
project_data = project_response['data']['project']
88+
89+
# get app details
90+
app_response = requests.get(
91+
f"{APP_ENDPOINT}/{app_id}", headers={
92+
"accept": "application/json",
93+
"Authorization": request.headers.get('Authorization')
94+
}
95+
)
96+
97+
if not app_response.ok:
98+
return SimpleNamespace(status='failed', message="Failed to fetch app for current user", status_code=400)
99+
100+
app_response = app_response.json()
101+
app_data = app_response['data']['apps']
102+
103+
app_alias = app_data['alias']
104+
namespace = project_data['alias']
105+
106+
prometheus_url = project_data['cluster']['prometheus_url']
107+
if not prometheus_url:
108+
return SimpleNamespace(status='fail', message='No prometheus url provided', status_code=404)
109+
110+
os.environ["PROMETHEUS_URL"] = prometheus_url
111+
return SimpleNamespace(
112+
start=start,
113+
end=end,
114+
step=step,
115+
app_alias=app_alias,
116+
namespace=namespace,
117+
status_code=200
118+
)

0 commit comments

Comments
 (0)