Skip to content

Commit 6b7be9f

Browse files
Introduce functions for interacting with Prometheus API (#257)
* Introduce functions for executing PromQL instant and range queries towards the Monitor Promehteus endpoints. * Add get_series endpoint * Add get_labels endpoint * Add get_label_values function. * Add get_metadata function. * In all functions expect both token and host to be passed as arguments. * poetry lock * Apply linting comments
1 parent 67ca483 commit 6b7be9f

12 files changed

+1174
-12
lines changed

.github/workflows/ci-pull-request.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ jobs:
1515
matrix:
1616
python_version:
1717
# https://python-release-cycle.glitch.me/
18-
- "3.7"
1918
- "3.8"
2019
- "3.9"
2120
- "3.10"
2221
- "3.11"
22+
- "3.12"
23+
- "3.13"
2324
runs-on: ubuntu-latest
2425
steps:
2526
- uses: actions/checkout@v4

examples/get_data_promql_advanced.py

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
#!/usr/bin/env python
2+
#
3+
# This script shows the basics of getting data out of Sysdig Monitor by executing a PromQL query
4+
# that returns the top 5 Kubernetes workloads consuming the highest percentage of their allocated CPU
5+
# by comparing actual usage to defined CPU limits. The query is executed over a 5-minute time window.
6+
#
7+
8+
import sys
9+
import time
10+
from datetime import datetime
11+
12+
from sdcclient import SdcClient
13+
14+
15+
def print_prometheus_results_as_table(results):
16+
if not results:
17+
print("No data found for the query.")
18+
return
19+
20+
# Store time series data
21+
all_timestamps = set()
22+
label_keys = []
23+
time_series_by_label = {}
24+
25+
for series in results:
26+
metric = series.get("metric", {})
27+
label = ','.join(f'{k}={v}' for k, v in sorted(metric.items()))
28+
label_keys.append(label)
29+
time_series_by_label[label] = {}
30+
31+
for timestamp, value in series.get("values", []):
32+
ts = int(float(timestamp))
33+
all_timestamps.add(ts)
34+
time_series_by_label[label][ts] = value
35+
36+
# Prepare header
37+
label_keys = sorted(set(label_keys))
38+
all_timestamps = sorted(all_timestamps)
39+
40+
print(f"{'Timestamp':<25} | " + " | ".join(f"{label}" for label in label_keys))
41+
print("-" * (26 + len(label_keys) * 25))
42+
43+
# Print each row, filling in missing values with "N/A"
44+
for ts in all_timestamps:
45+
dt = datetime.fromtimestamp(ts).isoformat()
46+
row_values = []
47+
for label in label_keys:
48+
value = time_series_by_label.get(label, {}).get(ts, "N/A")
49+
row_values.append(value)
50+
print(f"{dt:<25} | " + " | ".join(f"{val:>20}" for val in row_values))
51+
52+
53+
#
54+
# Parse arguments
55+
#
56+
if len(sys.argv) != 3:
57+
print(('usage: %s <sysdig-token> <hostname>' % sys.argv[0]))
58+
print('You can find your token at https://app.sysdigcloud.com/#/settings/user')
59+
sys.exit(1)
60+
61+
sdc_token = sys.argv[1]
62+
hostname = sys.argv[2]
63+
64+
sdclient = SdcClient(sdc_token, hostname)
65+
66+
#
67+
# A PromQL query to execute. The query retrieves the top 5 workloads in a specific Kubernetes
68+
# cluster that are using the highest percentage of their allocated CPU resources. It calculates
69+
# this by comparing the actual CPU usage of each workload to the CPU limits set for them and
70+
# then ranks the results to show the top 5.
71+
#
72+
query = '''
73+
topk (5,
74+
sum by (kube_cluster_name, kube_namespace_name, kube_workload_name) (
75+
rate(
76+
sysdig_container_cpu_cores_used{
77+
kube_cluster_name="dev-cluster"
78+
}[10m]
79+
)
80+
)
81+
/
82+
sum by (kube_cluster_name, kube_namespace_name, kube_workload_name) (
83+
kube_pod_container_resource_limits{
84+
kube_cluster_name="dev-cluster",
85+
resource="cpu"
86+
}
87+
)
88+
)
89+
'''
90+
91+
#
92+
# Time window:
93+
# - end is the current time
94+
# - start is the current time minus 5 minutes
95+
#
96+
end = int(time.time())
97+
start = end - 5 * 60 # 5 minutes ago
98+
99+
#
100+
# Step:
101+
# - resolution step, how far should timestamp of each resulting sample be apart
102+
#
103+
step = 60
104+
105+
#
106+
# Load data
107+
#
108+
ok, response_json = sdclient.get_data_promql(query, start, end, step)
109+
110+
#
111+
# Show the result
112+
#
113+
if ok:
114+
#
115+
# Read the response. The JSON looks like this:
116+
#
117+
# {
118+
# "data": {
119+
# "result": [
120+
# {
121+
# "metric": {},
122+
# "values": [
123+
# [
124+
# 1744210080,
125+
# "0.58"
126+
# ],
127+
# [
128+
# 1744210140,
129+
# "0.58"
130+
# ],
131+
# [
132+
# 1744210200,
133+
# "0.58"
134+
# ],
135+
# [
136+
# 1744210260,
137+
# "0.5799999999999998"
138+
# ],
139+
# [
140+
# 1744210320,
141+
# "0.5799999999999998"
142+
# ],
143+
# [
144+
# 1744210380,
145+
# "0.5799999999999998"
146+
# ]
147+
# ]
148+
# }
149+
# ],
150+
# "resultType": "matrix"
151+
# },
152+
# "status": "success"
153+
# }
154+
#
155+
156+
157+
#
158+
# Print summary (what, when)
159+
#
160+
results = response_json.get("data", {}).get("result", [])
161+
print_prometheus_results_as_table(results)
162+
163+
else:
164+
print(response_json)
165+
sys.exit(1)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#!/usr/bin/env python
2+
#
3+
# This script shows the basics of getting data out of Sysdig Monitor by executing a PromQL query
4+
# that returns the top 5 Kubernetes workloads consuming the highest percentage of their allocated CPU
5+
# by comparing actual usage to defined CPU limits. The query is executed at a timestamp 5 minutes ago.
6+
#
7+
8+
import sys
9+
import time
10+
from datetime import datetime
11+
12+
from sdcclient import SdcClient
13+
14+
15+
def print_prometheus_instant_result(result):
16+
if not result:
17+
print("No data found for the instant query.")
18+
return
19+
20+
# Determine if any result has labels
21+
has_labels = any(entry.get("metric") for entry in result)
22+
23+
if has_labels:
24+
print(f"{'Timestamp':<25} | {'Metric':<40} | {'Value':>10}")
25+
print("-" * 80)
26+
else:
27+
print(f"{'Timestamp':<25} | {'Value':>10}")
28+
print("-" * 40)
29+
30+
for entry in result:
31+
timestamp, value = entry.get("value", [None, None])
32+
dt = datetime.fromtimestamp(float(timestamp)).isoformat() if timestamp else "N/A"
33+
metric = entry.get("metric", {})
34+
35+
if has_labels:
36+
label_str = ', '.join(f'{k}="{v}"' for k, v in sorted(metric.items()))
37+
print(f"{dt:<25} | {label_str:<40} | {value:>10}")
38+
else:
39+
print(f"{dt:<25} | {value:>10}")
40+
41+
42+
#
43+
# Parse arguments
44+
#
45+
if len(sys.argv) != 3:
46+
print(('usage: %s <sysdig-token> <hostname>' % sys.argv[0]))
47+
print('You can find your token at https://app.sysdigcloud.com/#/settings/user')
48+
sys.exit(1)
49+
50+
sdc_token = sys.argv[1]
51+
hostname = sys.argv[2]
52+
53+
sdclient = SdcClient(sdc_token, hostname)
54+
55+
#
56+
# A PromQL query to execute. The query retrieves the top 5 workloads in a specific Kubernetes
57+
# cluster that are using the highest percentage of their allocated CPU resources. It calculates
58+
# this by comparing the actual CPU usage of each workload to the CPU limits set for them and
59+
# then ranks the results to show the top 5.
60+
#
61+
query = '''
62+
topk(5,
63+
sum by (kube_cluster_name, kube_namespace_name, kube_workload_name) (
64+
rate(
65+
sysdig_container_cpu_cores_used{
66+
kube_cluster_name="dev-cluster"
67+
}[10m]
68+
)
69+
)
70+
/
71+
sum by (kube_cluster_name, kube_namespace_name, kube_workload_name) (
72+
kube_pod_container_resource_limits{
73+
kube_cluster_name="dev-cluster",
74+
resource="cpu"
75+
}
76+
)
77+
)
78+
'''
79+
80+
#
81+
# Time:
82+
# - the parameter is optional; if not set, the current time is used
83+
#
84+
time = int(time.time()) - 5 * 60 # 5 minutes ago
85+
86+
#
87+
# Load data
88+
#
89+
ok, response_json = sdclient.get_data_promql_instant(query, 1744273000)
90+
91+
#
92+
# Show the result
93+
#
94+
if ok:
95+
#
96+
# Read the response. The JSON looks like this:
97+
#
98+
# {
99+
# "result": [
100+
# {
101+
# "metric": {},
102+
# "value": [
103+
# 1744272414,
104+
# "0.58"
105+
# ]
106+
# }
107+
# ],
108+
# "resultType": "vector"
109+
# }
110+
#
111+
112+
113+
#
114+
# Print summary (what, when)
115+
#
116+
results = response_json.get("data", {}).get("result", [])
117+
print_prometheus_instant_result(results)
118+
119+
else:
120+
print(response_json)
121+
sys.exit(1)

0 commit comments

Comments
 (0)