The answer from Michael Doubez didn't work for me, although my poll time is also set to 30s.
When I execute this query:
probe_success{target="https://example.com"}[30s]
I always get only one result. But as we want to detect changes, we need two data points to compare.
So I set the interval to 60s and my final query is this:
((changes(probe_success{target="https://example.com"}[60s]) != 0) * probe_success)[14d:30s]
This gets the changes for the specified target in the last 14 days.
The result should look somehow like this:
| Time | instance | job | target | Value |
| ------------------- | -------------------------------------------------------------- | -------- | ------------------- | ----- |
| 2022-12-13 22:05:30 | prometheus-blackbox-exporter.prometheus-blackbox-exporter:9115 | blackbox | https://example.com | 0 |
| 2022-12-13 22:06:00 | prometheus-blackbox-exporter.prometheus-blackbox-exporter:9115 | blackbox | https://example.com | 1 |
| 2022-12-14 08:52:00 | prometheus-blackbox-exporter.prometheus-blackbox-exporter:9115 | blackbox | https://example.com | 0 |
| 2022-12-14 08:52:30 | prometheus-blackbox-exporter.prometheus-blackbox-exporter:9115 | blackbox | https://example.com | 1 |
Based on this you can generate your downtime ranges.
I created an example with python3:
#!/usr/bin/env python3
from datetime import datetime
import requests
def print_downtimes(probe_results):
# based on the following query and 30s polling interval
# ((changes(probe_success[60s]) != 0) * probe_success)[14d:30s]
all_downtimes = {}
downtime_build_lookup = {}
for host_result in probe_results:
change_target = host_result['metric'].get('target')
for timestamp, change_value in host_result['values']:
change_timestamp = int(timestamp)
if int(change_value) == 0:
if change_target not in downtime_build_lookup:
downtime_build_lookup[change_target] = {"down_from": -1, "down_to": -1}
downtime_build_lookup[change_target]["down_from"] = change_timestamp
else:
if change_target not in downtime_build_lookup:
downtime_build_lookup[change_target] = {"down_from": -1, "down_to": -1}
downtime_build_lookup[change_target]["down_to"] = change_timestamp
if change_target not in all_downtimes:
all_downtimes[change_target] = []
all_downtimes[change_target].append(downtime_build_lookup[change_target])
downtime_build_lookup[change_target] = {"down_from": -1, "down_to": -1}
for target, target_downtimes in all_downtimes.items():
print(target)
for downtime in target_downtimes:
print(f"Down from {datetime.fromtimestamp(downtime['down_from'])} to {datetime.fromtimestamp(downtime['down_to'])}")
if __name__ == '__main__':
PROMETHEUS_URL = 'http://localhost:9090/'
response = requests.get(PROMETHEUS_URL + 'api/v1/query', params={
'query': '((changes(probe_success[60s]) != 0) * probe_success)[14d:30s]',
})
data = response.json()
print_downtimes(data['data']['result'])
Which prints something like this:
https://example.com
Down from 2022-12-14 09:01:30 to 2022-12-14 09:02:00
Down from 2022-12-14 09:21:30 to 2022-12-14 09:22:00
Down from 2022-12-14 18:40:00 to 2022-12-14 18:40:30
https://example2.com
Down from 2022-12-15 13:10:30 to 2022-12-15 13:11:30