Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added diagnostic/build-fb0df9c3-part001.logd
Binary file not shown.
Binary file added diagnostic/build-fb0df9c3-part002.logd
Binary file not shown.
Binary file added diagnostic/build-fb0df9c3-part003.logd
Binary file not shown.
90 changes: 90 additions & 0 deletions diagnostic/build-fb0df9c3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
"generated_at": "2026-07-09T12:11:02.292720+00:00",
"commit": "fb0df9c3",
"diagnostic_logd": [
"diagnostic\\build-fb0df9c3-part001.logd",
"diagnostic\\build-fb0df9c3-part002.logd",
"diagnostic\\build-fb0df9c3-part003.logd"
],
"diagnostic_logd_error": null,
"chunked": true,
"chunk_size_bytes": 41943040,
"password": "a7430eb931d198efd7dd",
"decrypt_command": "encryptly unpack diagnostic\\build-fb0df9c3.logd <outdir> --password a7430eb931d198efd7dd",
"total_modules": 10,
"passed": 0,
"failed": 10,
"modules": [
{
"name": "backend",
"status": "FAIL",
"elapsed_seconds": 0,
"artifact": null,
"output": "Command not found: [WinError 2] \u7cfb\u7edf\u627e\u4e0d\u5230\u6307\u5b9a\u7684\u6587\u4ef6\u3002"
},
{
"name": "frontend",
"status": "FAIL",
"elapsed_seconds": 0.141,
"artifact": null,
"output": "npm install failed:\nnpm: can't open file 'C:\\\\Users\\\\27796\\\\Documents\\\\Codex\\\\2026-07-09\\\\github-bounty-pr-20-30-zhaoziyuan2024\\\\work\\\\zeroeye\\\\frontend\\\\install': [Errno 2] No such file or directory\n"
},
{
"name": "market",
"status": "FAIL",
"elapsed_seconds": 0,
"artifact": null,
"output": "Command not found: [WinError 2] \u7cfb\u7edf\u627e\u4e0d\u5230\u6307\u5b9a\u7684\u6587\u4ef6\u3002"
},
{
"name": "frailbox",
"status": "FAIL",
"elapsed_seconds": 0,
"artifact": null,
"output": "Command not found: [WinError 2] \u7cfb\u7edf\u627e\u4e0d\u5230\u6307\u5b9a\u7684\u6587\u4ef6\u3002"
},
{
"name": "engine",
"status": "FAIL",
"elapsed_seconds": 0,
"artifact": null,
"output": "Command not found: [WinError 2] \u7cfb\u7edf\u627e\u4e0d\u5230\u6307\u5b9a\u7684\u6587\u4ef6\u3002"
},
{
"name": "compliance",
"status": "FAIL",
"elapsed_seconds": 0,
"artifact": null,
"output": "Command not found: [WinError 2] \u7cfb\u7edf\u627e\u4e0d\u5230\u6307\u5b9a\u7684\u6587\u4ef6\u3002"
},
{
"name": "v2-market-stream",
"status": "FAIL",
"elapsed_seconds": 0,
"artifact": null,
"output": "Command not found: [WinError 2] \u7cfb\u7edf\u627e\u4e0d\u5230\u6307\u5b9a\u7684\u6587\u4ef6\u3002"
},
{
"name": "nfc-scanner",
"status": "FAIL",
"elapsed_seconds": 0,
"artifact": null,
"output": "Command not found: [WinError 2] \u7cfb\u7edf\u627e\u4e0d\u5230\u6307\u5b9a\u7684\u6587\u4ef6\u3002"
},
{
"name": "openapi-haskell",
"status": "FAIL",
"elapsed_seconds": 0,
"artifact": null,
"output": "Command not found: [WinError 2] \u7cfb\u7edf\u627e\u4e0d\u5230\u6307\u5b9a\u7684\u6587\u4ef6\u3002"
},
{
"name": "openapi-tools",
"status": "FAIL",
"elapsed_seconds": 0,
"artifact": null,
"output": "Command not found: [WinError 2] \u7cfb\u7edf\u627e\u4e0d\u5230\u6307\u5b9a\u7684\u6587\u4ef6\u3002"
}
],
"pr_note": "Include the encrypted diagnostic logd artifact(s): diagnostic\\build-fb0df9c3-part001.logd, diagnostic\\build-fb0df9c3-part002.logd, diagnostic\\build-fb0df9c3-part003.logd. The encrypted .logd is the required diagnostic content for PR review; this JSON file is metadata. Maintainers may ask you to remove these diagnostic artifacts before merging."
}
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Test package marker for unittest discovery.
67 changes: 67 additions & 0 deletions tests/test_monitoring_setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import pathlib
import sys
import unittest


ROOT = pathlib.Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))

from tools import monitoring_setup


class MonitoringSetupRuleTests(unittest.TestCase):
def test_recommended_alert_rules_do_not_self_divide(self):
self.assertEqual(
monitoring_setup.validate_alert_rules(
monitoring_setup.RECOMMENDED_ALERT_RULES
),
[],
)

def test_high_memory_alert_uses_machine_memory_denominator(self):
high_memory_rule = next(
rule for rule in monitoring_setup.RECOMMENDED_ALERT_RULES
if rule["name"] == "HighMemoryUsage"
)

self.assertIn("process_resident_memory_bytes", high_memory_rule["expr"])
self.assertIn("machine_memory_bytes", high_memory_rule["expr"])
self.assertNotIn(
"process_resident_memory_bytes / process_resident_memory_bytes",
high_memory_rule["expr"],
)

def test_validation_rejects_self_dividing_alert_expression(self):
invalid_rules = [{
"name": "BadMemoryUsage",
"expr": (
"process_resident_memory_bytes{job='api'} / "
"process_resident_memory_bytes{job='api'} > 0.9"
),
}]

self.assertEqual(
monitoring_setup.validate_alert_rules(invalid_rules),
[
"BadMemoryUsage: expression divides "
"process_resident_memory_bytes by itself"
],
)

def test_dry_run_rejects_invalid_self_dividing_rule(self):
invalid_rules = [{
"name": "BadMemoryUsage",
"expr": "process_resident_memory_bytes / process_resident_memory_bytes > 0.9",
}]

self.assertFalse(
monitoring_setup.upload_prometheus_rules(
invalid_rules,
monitoring_setup.DEFAULT_PROMETHEUS_URL,
dry_run=True,
)
)


if __name__ == "__main__":
unittest.main()
45 changes: 40 additions & 5 deletions tools/monitoring_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import argparse
import json
import os
import re
import sys
import time
import urllib.request
Expand All @@ -42,6 +43,14 @@

DASHBOARD_DIR = os.path.join(os.path.dirname(__file__), "..", "monitoring", "dashboards")
ALERT_RULES_DIR = os.path.join(os.path.dirname(__file__), "..", "monitoring", "alerts")
METRIC_NAME_RE = r"[a-zA-Z_:][a-zA-Z0-9_:]*"
SELF_DIVISION_RE = re.compile(
rf"\b({METRIC_NAME_RE})(?:\s*\{{[^{{}}]*\}})?\s*/\s*"
rf"(?:on\s*\([^)]*\)\s*)?"
rf"(?:ignoring\s*\([^)]*\)\s*)?"
rf"(?:group_(?:left|right)(?:\s*\([^)]*\))?\s*)?"
rf"({METRIC_NAME_RE})(?:\s*\{{[^{{}}]*\}})?\b"
)

RECOMMENDED_ALERT_RULES: List[Dict[str, Any]] = [
{
Expand Down Expand Up @@ -78,7 +87,7 @@
},
{
"name": "HighMemoryUsage",
"expr": "process_resident_memory_bytes / process_resident_memory_bytes > 0.9",
"expr": "process_resident_memory_bytes / on(instance) group_left machine_memory_bytes > 0.9",
"duration": "10m",
"severity": "warning",
"summary": "High memory usage on {{$labels.instance}}",
Expand Down Expand Up @@ -146,12 +155,30 @@
{"name": "job:http_requests_total:rate5m", "expr": "sum(rate(http_requests_total[5m])) by (job)"},
{"name": "job:http_error_rate:rate5m", "expr": "sum(rate(http_errors_total[5m])) by (job) / sum(rate(http_requests_total[5m])) by (job)"},
{"name": "job:http_latency_p99:rate5m", "expr": "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, job))"},
{"name": "instance:memory_usage:ratio", "expr": "process_resident_memory_bytes / machine_memory_bytes"},
{"name": "instance:memory_usage:ratio", "expr": "process_resident_memory_bytes / on(instance) group_left machine_memory_bytes"},
{"name": "instance:cpu_usage:ratio", "expr": "rate(process_cpu_seconds_total[5m])"},
{"name": "service:uptime:days", "expr": "time() - process_start_time_seconds{job=~'.+'}"},
]


def find_self_dividing_expressions(rules: List[Dict[str, Any]]) -> List[str]:
"""Return rule names whose expressions divide the same metric by itself."""
errors = []
for rule in rules:
expr = str(rule.get("expr", ""))
for lhs_metric, rhs_metric in SELF_DIVISION_RE.findall(expr):
if lhs_metric == rhs_metric:
name = rule.get("name", "<unnamed>")
errors.append(
f"{name}: expression divides {lhs_metric} by itself"
)
return errors


def validate_alert_rules(rules: List[Dict[str, Any]]) -> List[str]:
return find_self_dividing_expressions(rules)


def http_request(method: str, url: str, data: Any = None,
headers: Optional[Dict[str, str]] = None) -> Any:
if headers is None:
Expand Down Expand Up @@ -200,6 +227,13 @@ def check_alertmanager(url: str) -> bool:
def upload_prometheus_rules(rules: List[Dict[str, Any]],
prometheus_url: str,
dry_run: bool = False) -> bool:
validation_errors = validate_alert_rules(rules)
if validation_errors:
print("Invalid Prometheus alert rules:", file=sys.stderr)
for error in validation_errors:
print(f" - {error}", file=sys.stderr)
return False

rules_file = "/etc/prometheus/rules/tent_rules.yml"
print(f"{'Would upload' if dry_run else 'Uploading'} {len(rules)} rules to {prometheus_url}")

Expand Down Expand Up @@ -414,13 +448,14 @@ def main():
args.alertmanager_url, args.slack_webhook,
args.pagerduty_key, args.dry_run)

upload_prometheus_rules(RECOMMENDED_ALERT_RULES, args.prometheus_url, args.dry_run)
if not upload_prometheus_rules(RECOMMENDED_ALERT_RULES, args.prometheus_url, args.dry_run):
return 1
print("Monitoring initialization complete")
return 0

if args.alerts:
upload_prometheus_rules(RECOMMENDED_ALERT_RULES, args.prometheus_url, args.dry_run)
return 0
return 0 if upload_prometheus_rules(
RECOMMENDED_ALERT_RULES, args.prometheus_url, args.dry_run) else 1

if args.backup:
return 0 if backup_monitoring_config(
Expand Down