Skip to content

Commit 4d242f7

Browse files
📝 Add docstrings to codex/extend-performance-budget-configuration
Docstrings generation was requested by @shayancoin. * #99 (comment) The following files were modified: * `scripts/ci/check_canary_budgets.py`
1 parent 2710543 commit 4d242f7

File tree

1 file changed

+85
-2
lines changed

1 file changed

+85
-2
lines changed

scripts/ci/check_canary_budgets.py

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ class BudgetResult:
2626
regression: Optional[float] = None
2727

2828
def to_line(self) -> str:
29+
"""
30+
Format the BudgetResult as a one-line status string.
31+
32+
The string contains a status token (`OK` or `FAIL`), the budget name, the current value with unit, an optional previous value, and the threshold with unit and optional regression percentage. Numeric values are formatted with fixed decimal places (current and threshold to four decimals, regression as a percentage with two decimals).
33+
34+
Returns:
35+
A single-line human-readable status string, e.g. "[OK] p95-latency: current=123.4567 ms, previous=100.0000 ms (threshold=3000.0000 ms, regression=23.45%)"
36+
"""
2937
previous_part = f", previous={self.previous:.4f}{self.unit}" if self.previous is not None else ""
3038
regression_part = f", regression={self.regression:.2%}" if self.regression is not None else ""
3139
status = "OK" if self.passed else "FAIL"
@@ -36,12 +44,36 @@ def to_line(self) -> str:
3644

3745

3846
def _env(name: str, default: Optional[str] = None) -> Optional[str]:
47+
"""
48+
Retrieve the value of an environment variable, returning a fallback when it's missing or empty.
49+
50+
Parameters:
51+
name (str): Environment variable name to read.
52+
default (Optional[str]): Value to return if the environment variable is not set or is an empty string.
53+
54+
Returns:
55+
Optional[str]: The environment variable value, or `default` if the variable is unset or an empty string.
56+
"""
3957
value = os.getenv(name)
4058
return value if value not in (None, "") else default
4159

4260

4361
def query_prometheus(base_url: str, query: str, timestamp: float) -> float:
44-
"""Execute an instant Prometheus query and return the first scalar value."""
62+
"""
63+
Execute an instant Prometheus query at a specific timestamp and return the first scalar sample value.
64+
65+
Parameters:
66+
base_url (str): Base URL of the Prometheus server (e.g., "http://prometheus:9090").
67+
query (str): PromQL instant query to execute.
68+
timestamp (float): UNIX timestamp (seconds) at which to evaluate the instant query.
69+
70+
Returns:
71+
float: The first scalar sample value from the query result.
72+
73+
Raises:
74+
SystemExit: If the HTTP request fails, the Prometheus response status is not "success",
75+
the query returns no data, or the result payload is malformed.
76+
"""
4577

4678
encoded_query = urllib.parse.urlencode({"query": query, "time": f"{timestamp:.3f}"})
4779
url = f"{base_url.rstrip('/')}/api/v1/query?{encoded_query}"
@@ -76,6 +108,22 @@ def evaluate_budget(
76108
baseline_offset_seconds: float,
77109
unit_label: str,
78110
) -> BudgetResult:
111+
"""
112+
Evaluate a named budget by comparing the current Prometheus value to a baseline and determining threshold and regression compliance.
113+
114+
Parameters:
115+
name (str): Logical name for the budget result.
116+
base_url (str): Prometheus base URL used to execute the query.
117+
query (str): Prometheus instant query expression to evaluate.
118+
unit_scale (float): Multiplier applied to raw Prometheus values to convert units (e.g., seconds to milliseconds).
119+
threshold (float): Maximum acceptable current value for the budget to pass.
120+
regression_tolerance (float): Maximum allowed relative increase ((current - previous) / previous) for the budget to pass.
121+
baseline_offset_seconds (float): Seconds to subtract from the current timestamp to obtain the baseline evaluation time.
122+
unit_label (str): Human-readable unit suffix included in the returned BudgetResult (e.g., " ms", " rate").
123+
124+
Returns:
125+
BudgetResult: Result containing the budget `name`, scaled `current` and `previous` values, `threshold`, `unit`, boolean `passed` indicating both threshold and regression compliance, and numeric `regression` (relative change) or `None` when previous value is zero.
126+
"""
79127
now = time.time()
80128
current_value_raw = query_prometheus(base_url, query, now)
81129
previous_value_raw = query_prometheus(base_url, query, now - baseline_offset_seconds)
@@ -102,6 +150,19 @@ def evaluate_budget(
102150

103151

104152
def query_tempo(base_url: str, query_json: str) -> dict:
153+
"""
154+
Send a JSON search query to a Tempo instance and return the parsed JSON response.
155+
156+
Parameters:
157+
base_url (str): Base URL of the Tempo server (e.g., "http://tempo:9411").
158+
query_json (str): JSON-formatted string to send as the search request body for the Tempo /api/search endpoint.
159+
160+
Returns:
161+
dict: Parsed JSON response from Tempo.
162+
163+
Raises:
164+
SystemExit: If the HTTP request fails (network error or other URL/IO error).
165+
"""
105166
data = query_json.encode("utf-8")
106167
request = urllib.request.Request(
107168
f"{base_url.rstrip('/')}/api/search", data=data, headers={"Content-Type": "application/json"}
@@ -114,6 +175,20 @@ def query_tempo(base_url: str, query_json: str) -> dict:
114175

115176

116177
def check_tempo_regressions(base_url: str, query: str, duration_budget_ms: float) -> BudgetResult:
178+
"""
179+
Evaluate Tempo trace durations and compare the maximum observed duration against a provided duration budget.
180+
181+
Parameters:
182+
base_url (str): Base URL of the Tempo API.
183+
query (str): Tempo search query payload as a JSON string.
184+
duration_budget_ms (float): Allowed maximum trace duration in milliseconds.
185+
186+
Returns:
187+
BudgetResult: Result with name "tempo-trace-duration", `current` set to the maximum `durationMs` observed among returned traces, `previous` set to None, `threshold` equal to `duration_budget_ms`, `unit` set to " ms", and `passed` true if `current` is less than or equal to `threshold`.
188+
189+
Raises:
190+
SystemExit: If the Tempo response contains no traces or no trace durations.
191+
"""
117192
payload = query_tempo(base_url, query)
118193
traces = payload.get("traces", [])
119194
if not traces:
@@ -135,6 +210,14 @@ def check_tempo_regressions(base_url: str, query: str, duration_budget_ms: float
135210

136211

137212
def main() -> int:
213+
"""
214+
Validate configured canary budgets by querying Prometheus (and optionally Tempo) and return an exit code.
215+
216+
Reads environment variables for Prometheus and Tempo configuration and budget thresholds, evaluates latency and error budgets (and optional Tempo trace-duration budget), prints a one-line summary for each budget, and returns an exit code indicating overall status.
217+
218+
Returns:
219+
exit_code (int): 0 if Prometheus configuration is missing (validation skipped) or if all budgets pass; 1 if any budget failed.
220+
"""
138221
prom_url = _env("PROMETHEUS_URL")
139222
latency_query = _env("PROMETHEUS_LATENCY_QUERY")
140223
error_query = _env("PROMETHEUS_ERROR_RATE_QUERY")
@@ -198,4 +281,4 @@ def main() -> int:
198281

199282

200283
if __name__ == "__main__":
201-
sys.exit(main())
284+
sys.exit(main())

0 commit comments

Comments
 (0)