fn render_misc(app: &App, snapshot: &crate::config::Snapshot, f: &mut Families) { let config = &snapshot.envelope.config; let settings = &config.prometheus; if settings.include_streams { for host in &config.streams { let protocol = match host.protocol { crate::stream::Protocol::Tcp => "tcp", crate::stream::Protocol::Udp => "udp", }; f.add( "rust_proxy_stream_enabled", "gauge", "Desired Layer-4 stream enable flag.", &labels(&[("stream", &host.id), ("protocol", protocol)]), u8::from(host.enabled), ); } for host in &app.active_streams { let Some(metrics) = app.stream_metrics.get(&host.id) else { continue; }; let protocol = match host.protocol { crate::stream::Protocol::Tcp => "tcp", crate::stream::Protocol::Udp => "udp", }; let l = labels(&[("stream", &host.id), ("protocol", protocol)]); let view = metrics.view(); for (name, kind, value) in [ ("sessions_total", "counter", view.sessions_total), ( "sessions_completed_total", "counter", view.sessions_completed, ), ("active", "gauge", view.active), ("rejected_total", "counter", view.rejected), ("errors_total", "counter", view.errors), ("bytes_in_total", "counter", view.bytes_in), ("bytes_out_total", "counter", view.bytes_out), ("packets_in_total", "counter", view.packets_in), ("packets_out_total", "counter", view.packets_out), ] { f.add( &format!("rust_proxy_stream_{name}"), kind, "Layer-4 stream observation; reset on process restart.", &l, value, ); } f.add( "rust_proxy_stream_max_connections", "gauge", "Configured stream connection/session capacity.", &l, host.max_connections, ); } } if settings.include_logging { let stats = app.logs.stats(); f.add( "rust_proxy_log_sink_queue_capacity", "gauge", "Structured log sink queue capacity.", "", stats.queue_capacity, ); f.add( "rust_proxy_log_sink_queue_dropped_total", "counter", "Structured log entries dropped because the sink queue was full.", "", stats.queue_dropped, ); f.add( "rust_proxy_log_sink_sent_total", "counter", "Structured log entries delivered to configured sinks.", "", stats.sent, ); f.add( "rust_proxy_log_sink_errors_total", "counter", "Structured log sink delivery errors.", "", stats.errors, ); } if settings.include_cache_domains { // Bounded resident inspector. Counter families are gauges deliberately: // these per-domain values reset on config publication, unlike globals. let dashboard = app.cache.dashboard(None, 0, 1); f.add( "rust_proxy_cache_statistics_revision", "gauge", "Revision that owns domain statistics.", "", dashboard.statistics_revision, ); for domain in dashboard.domains { // Only configured names, never arbitrary Host input or unknown scope. if !config .vhosts .iter() .any(|h| h.id == domain.vhost && h.frontend.hosts.contains(&domain.domain)) { continue; } let l = labels(&[("vhost", &domain.vhost), ("domain", &domain.domain)]); for (name, n) in [ ("objects", domain.entries as u64), ("hot_objects", domain.hot_entries as u64), ("resident_bytes", domain.resident_bytes as u64), ("cold_objects", domain.cold_entries as u64), ("cold_bytes", domain.cold_bytes), ("hits", domain.counters.hits), ("misses", domain.counters.misses), ("bypasses", domain.counters.bypasses), ("stored", domain.counters.stored), ("saved_body_bytes", domain.counters.saved_body_bytes), ] { f.add( &format!("rust_proxy_cache_domain_{name}"), "gauge", "Domain cache observation since current configuration revision.", &l, n, ); } f.add( "rust_proxy_cache_domain_hit_ratio", "gauge", "Domain HIT ratio 0..1.", &l, domain.hit_ratio, ); for (reason, count) in domain.counters.reasons { f.add( "rust_proxy_cache_domain_decisions", "gauge", "Decision reasons since config publication.", &format!("{l},reason=\"{}\"", escaped(&reason)), count, ); } } } } fn render_histograms( snapshot: &crate::config::Snapshot, docker_targets: &DockerTargets<'_>, out: &mut String, ) { let config = &snapshot.envelope.config; let settings = &config.prometheus; if settings.include_vhosts { out.push_str("# HELP rust_proxy_vhost_exchange_duration_seconds Full exchange lifetime including streaming and cancellation.\n# TYPE rust_proxy_vhost_exchange_duration_seconds histogram\n"); for (id, m) in &snapshot.vhost_metrics { if docker_targets.contains_key(id) { continue; } let l = labels(&[("vhost", id)]); let _ = writeln!( out, "rust_proxy_vhost_exchange_duration_seconds_sum{{{l}}} {:.6}", m.duration_us.load(Ordering::Relaxed) as f64 / 1e6 ); // Read the cumulative last bucket once for +Inf and count. let count = m.buckets[crate::metrics::DURATION_BUCKETS_US.len()].load(Ordering::Relaxed); let mut previous = 0; for (i, threshold) in crate::metrics::DURATION_BUCKETS_US.iter().enumerate() { let value = m.buckets[i] .load(Ordering::Relaxed) .max(previous) .min(count); previous = value; let _ = writeln!( out, "rust_proxy_vhost_exchange_duration_seconds_bucket{{{l},le=\"{}\"}} {value}", *threshold as f64 / 1e6 ); } let _ = writeln!(out, "rust_proxy_vhost_exchange_duration_seconds_bucket{{{l},le=\"+Inf\"}} {count}\nrust_proxy_vhost_exchange_duration_seconds_count{{{l}}} {count}"); } } if settings.include_docker_vhosts { out.push_str("# HELP rust_proxy_docker_vhost_exchange_duration_seconds Full Docker-vhost exchange lifetime including streaming and cancellation.\n# TYPE rust_proxy_docker_vhost_exchange_duration_seconds histogram\n"); for (id, m) in &snapshot.vhost_metrics { let Some((agent, assignment)) = docker_targets.get(id) else { continue; }; let l = labels(&[ ("agent", &agent.id), ("vhost", id), ("service", &assignment.service_key), ]); let _ = writeln!( out, "rust_proxy_docker_vhost_exchange_duration_seconds_sum{{{l}}} {:.6}", m.duration_us.load(Ordering::Relaxed) as f64 / 1e6 ); let count = m.buckets[crate::metrics::DURATION_BUCKETS_US.len()].load(Ordering::Relaxed); let mut previous = 0; for (i, threshold) in crate::metrics::DURATION_BUCKETS_US.iter().enumerate() { let value = m.buckets[i] .load(Ordering::Relaxed) .max(previous) .min(count); previous = value; let _ = writeln!( out, "rust_proxy_docker_vhost_exchange_duration_seconds_bucket{{{l},le=\"{}\"}} {value}", *threshold as f64 / 1e6 ); } let _ = writeln!(out, "rust_proxy_docker_vhost_exchange_duration_seconds_bucket{{{l},le=\"+Inf\"}} {count}\nrust_proxy_docker_vhost_exchange_duration_seconds_count{{{l}}} {count}"); } } } pub fn render(app: &App) -> String { let snapshot = app.config.load_full(); let config = &snapshot.envelope.config; let docker_targets = docker_targets(config); let mut out = app.metrics.prometheus( app.logs.dropped.load(Ordering::Relaxed), snapshot.envelope.revision, ); out.push_str(&app.cache.prometheus()); if config.prometheus.include_system { out.push_str(&app.diagnostics.prometheus()); } let mut families = Families::default(); render_core(app, &snapshot, &mut out, &mut families); render_vhosts(&snapshot, &mut families); render_traffic(app, &snapshot, &mut families); render_backends(&snapshot, &docker_targets, &mut families); render_docker(&snapshot, &docker_targets, &mut families); render_misc(app, &snapshot, &mut families); families.finish(&mut out); render_histograms(&snapshot, &docker_targets, &mut out); out }