main
py 97 lines 2.92 KB
Raw
1 #!/usr/bin/env python3
2
3 import json
4 import logging
5 import sys
6 import time
7 from pprint import pprint
8
9 import requests
10 from dateutil.parser import parse
11 from prometheus_client import Counter, Gauge, Histogram, start_http_server
12
13 CHANNEL_REVISION = Gauge(
14 "channel_revision",
15 "Current revision, exported as a hack",
16 ["channel", "revision", "status", "variant", "current"],
17 )
18
19
20 CHANNEL_REQUEST_TIME = Histogram(
21 "channel_request_time", "Time spent requesting channel data"
22 )
23 CHANNEL_UPDATE_TIME = Gauge(
24 "channel_update_time",
25 "Total number of failures to fetch spot market prices",
26 ["channel"],
27 )
28 CHANNEL_CURRENT = Gauge(
29 "channel_current",
30 "If a channel is expected to be current",
31 ["channel"],
32 )
33 CHANNEL_REQUEST_FAILURES = Counter(
34 "channel_request_failures_total",
35 "Number of channel status requests which have failed",
36 )
37
38
39 @CHANNEL_REQUEST_TIME.time()
40 def measure_channel(name):
41 try:
42 with CHANNEL_REQUEST_FAILURES.count_exceptions():
43 result = requests.get(
44 f"https://nixos.org/channels/{name}/git-revision", timeout=10
45 )
46
47 try:
48 return {
49 "timestamp": parse(result.headers["last-modified"]).timestamp(),
50 "revision": result.text,
51 }
52 except KeyError as e:
53 print(f"Got KeyError after getting our result for {name}:")
54 pprint(e)
55 pprint(result)
56
57 except Exception as e:
58 print(f"Got a mystery error for {name}:")
59 pprint(e)
60
61
62 if __name__ == "__main__":
63 logging.basicConfig(level=logging.DEBUG)
64 start_http_server(9402)
65
66 with open(sys.argv[1]) as channel_data:
67 channels = json.load(channel_data)
68
69 revisions = {}
70
71 while True:
72 for channel, about in channels.items():
73 measurement = measure_channel(channel)
74 if measurement is not None:
75 revision = measurement["revision"]
76 status = about.get("status", "")
77 variant = about.get("variant", "")
78 current = int(status != "unmaintained")
79 CHANNEL_UPDATE_TIME.labels(channel=channel).set(
80 measurement["timestamp"]
81 )
82 CHANNEL_REVISION.labels(
83 channel=channel,
84 revision=revision,
85 status=status,
86 variant=variant,
87 current=current,
88 ).set(1)
89 CHANNEL_CURRENT.labels(channel=channel).set(current)
90 print(f"updated {channel}")
91 previous_revision = revisions.pop(channel, None)
92 revisions[channel] = revision
93 if previous_revision and previous_revision != revision:
94 CHANNEL_REVISION.remove(
95 channel, previous_revision, status, variant, current
96 )
97 time.sleep(55)