CI / test (push) Successful in 2m30s
- metrics.v: GET /metrics au format OpenMetrics (gauges + counters) - server.v: route /metrics, Stats.http_polls counter, increment in poll loop - metrics_test.v: test du endpoint metrics - ROADMAP: Phase 5 6/8 (Prometheus done)
72 lines
2.5 KiB
V
72 lines
2.5 KiB
V
module main
|
|
|
|
import net.http
|
|
import time
|
|
|
|
// metrics_response returns a Prometheus / OpenMetrics formatted response.
|
|
fn (mut app App) metrics_response() http.Response {
|
|
mut lines := []string{}
|
|
|
|
// HELP/TYPE headers
|
|
lines << '# HELP ntfy_bridge_uptime_seconds Seconds since the bridge started.'
|
|
lines << '# TYPE ntfy_bridge_uptime_seconds gauge'
|
|
lines << 'ntfy_bridge_uptime_seconds ${app.uptime_seconds()}'
|
|
|
|
lines << '# HELP ntfy_bridge_notifications_total Total notifications sent (all sources).'
|
|
lines << '# TYPE ntfy_bridge_notifications_total counter'
|
|
lines << 'ntfy_bridge_notifications_total ${app.stats.total_notifications}'
|
|
|
|
lines << '# HELP ntfy_bridge_errors_total Total publish errors.'
|
|
lines << '# TYPE ntfy_bridge_errors_total counter'
|
|
lines << 'ntfy_bridge_errors_total ${app.stats.errors}'
|
|
|
|
lines << '# HELP ntfy_bridge_notifications_by_source Notifications by source type.'
|
|
lines << '# TYPE ntfy_bridge_notifications_by_source counter'
|
|
for source, count in app.stats.by_source {
|
|
lines << 'ntfy_bridge_notifications_by_source{source="${source}"} ${count}'
|
|
}
|
|
|
|
lines << '# HELP ntfy_bridge_poll_up Health check polling status (1=up, 0=down).'
|
|
lines << '# TYPE ntfy_bridge_poll_up gauge'
|
|
for url, is_up in app.poll_state {
|
|
val := if is_up { '1' } else { '0' }
|
|
safe_url := url.replace('"', '\\"')
|
|
lines << 'ntfy_bridge_poll_up{url="${safe_url}"} ${val}'
|
|
}
|
|
|
|
lines << '# HELP ntfy_bridge_http_polls_total Total HTTP poll checks performed.'
|
|
lines << '# TYPE ntfy_bridge_http_polls_total counter'
|
|
lines << 'ntfy_bridge_http_polls_total ${app.stats.http_polls}'
|
|
|
|
lines << '# HELP ntfy_bridge_silence_active Whether notification silence is active.'
|
|
lines << '# TYPE ntfy_bridge_silence_active gauge'
|
|
now := time.now()
|
|
silence_val := if now.unix() < app.silence_until.unix() { '1' } else { '0' }
|
|
lines << 'ntfy_bridge_silence_active ${silence_val}'
|
|
|
|
lines << '# HELP ntfy_bridge_silence_remaining_seconds Seconds remaining in current silence.'
|
|
lines << '# TYPE ntfy_bridge_silence_remaining_seconds gauge'
|
|
remaining := if time.now() < app.silence_until {
|
|
(app.silence_until - time.now()) / time.second
|
|
} else {
|
|
0
|
|
}
|
|
lines << 'ntfy_bridge_silence_remaining_seconds ${remaining}'
|
|
|
|
// EOF
|
|
lines << '# EOF'
|
|
|
|
return http.Response{
|
|
status_code: 200
|
|
header: http.Header{}
|
|
body: lines.join('\n') + '\n'
|
|
}
|
|
}
|
|
|
|
// uptime_seconds returns the number of seconds since the server started.
|
|
fn (app App) uptime_seconds() i64 {
|
|
now := time.now()
|
|
diff := now.unix() - app.start_time.unix()
|
|
return i64(diff)
|
|
}
|