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) }