Skip to content

Metrics Monitoring System

quicX Metrics provides comprehensive observability for the quicX QUIC/HTTP3 implementation: 54+ metrics covering the UDP, QUIC, and HTTP/3 layers, lock-free design, Prometheus format export. Every metric operation is O(1) — atomics avoid lock contention, pre-allocated slots mean zero heap allocation, a single update costs < 10ns; core metrics are auto-instrumented and can be toggled at runtime. This document attempts to answer the following questions:

  1. How does the metrics system stay zero-overhead? — see “System Architecture” and “Performance Guarantees”;
  2. How are the 54+ metrics organized, and what does each cover? — see the 13 functional categories in “Metric Categories”;
  3. How to integrate and export in a project? — see “Usage Guide”.
┌─────────────────────────────────────────────────┐
│ Application Code │
│ (UDP, QUIC, HTTP/3, Memory Pool, etc.) │
└────────────────┬────────────────────────────────┘
│ Metrics::CounterInc()
│ Metrics::GaugeSet()
▼
┌─────────────────────────────────────────────────┐
│ Metrics Registry (Lock-Free) │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Counter │ │ Gauge │ │
│ │ (Atomic) │ │ (Atomic) │ │
│ └──────────────┘ └──────────────┘ │
└────────────────┬────────────────────────────────┘
│ ExportPrometheus()
▼
┌─────────────────────────────────────────────────┐
│ Prometheus Exporter │
│ # TYPE metric_name counter │
│ metric_name{labels} value │
└─────────────────────────────────────────────────┘
// Pre-allocated slot array
std::vector<MetricSlot> slots_; // Allocated at initialization
// O(1) registration
MetricID RegisterCounter(name, help) {
size_t id = next_id_.fetch_add(1); // Atomic increment
slots_[id] = MetricSlot{name, help, COUNTER};
return id;
}
// Counter increment - lock-free
void CounterInc(MetricID id, uint64_t delta = 1) {
slots_[id].value.fetch_add(delta, std::memory_order_relaxed);
}
// Gauge set - lock-free
void GaugeSet(MetricID id, uint64_t value) {
slots_[id].value.store(value, std::memory_order_relaxed);
}
std::string ExportPrometheus() {
std::ostringstream oss;
for (auto& slot : slots_) {
if (slot.type == COUNTER) {
oss << "# TYPE " << slot.name << " counter\n";
oss << slot.name << " "
<< slot.value.load(std::memory_order_relaxed) << "\n";
}
// ... Gauge, Histogram
}
return oss.str();
}
Metric NameTypeDescription
udp_packets_rxCounterTotal UDP packets received
udp_packets_txCounterTotal UDP packets sent
udp_bytes_rxCounterTotal UDP bytes received
udp_bytes_txCounterTotal UDP bytes sent
udp_dropped_packetsCounterTotal UDP packets dropped
udp_send_errorsCounterTotal UDP send errors

Purpose: Monitor network layer health, identify network congestion and packet loss issues.

2. QUIC Connection Layer Metrics (5 metrics)

Section titled “2. QUIC Connection Layer Metrics (5 metrics)”
Metric NameTypeDescription
quic_connections_activeGaugeCurrent active connections
quic_connections_totalCounterTotal connections created
quic_connections_closedCounterTotal connections closed
quic_handshake_successCounterSuccessful handshakes
quic_handshake_failCounterFailed handshakes

Purpose: Monitor connection lifecycle, evaluate handshake success rate.

Metric NameTypeDescription
quic_packets_rxCounterTotal QUIC packets received
quic_packets_txCounterTotal QUIC packets sent
quic_packets_retransmitCounterTotal retransmitted packets
quic_packets_lostCounterTotal packets lost
quic_packets_droppedCounterTotal dropped packets
quic_packets_ackedCounterTotal packets acknowledged

Purpose: Monitor transport layer reliability, calculate packet loss and retransmission rates.

Metric NameTypeDescription
quic_streams_activeGaugeCurrent active streams
quic_streams_createdCounterTotal streams created
quic_streams_closedCounterTotal streams closed
quic_streams_bytes_rxCounterTotal stream bytes received
quic_streams_bytes_txCounterTotal stream bytes sent
quic_streams_reset_rxCounterRESET frames received
quic_streams_reset_txCounterRESET frames sent

Purpose: Monitor stream management and data transmission, identify stream anomalies.

Metric NameTypeDescription
rtt_smoothed_usGaugeSmoothed RTT (microseconds)
rtt_variance_usGaugeRTT variance (microseconds)
rtt_min_usGaugeMinimum RTT (microseconds)

Purpose: Monitor network latency, evaluate connection quality.

Metric NameTypeDescription
congestion_window_bytesGaugeCurrent congestion window (bytes)
congestion_events_totalCounterTotal congestion events
slow_start_exitsCounterSlow start exits
bytes_in_flightGaugeBytes in flight
pacing_rate_bytes_per_secGaugePacing rate (bytes/second)
pacing_delay_usHistogramPacing delay (microseconds)

Purpose: Monitor congestion control algorithm, optimize throughput.

Metric NameTypeDescription
errors_protocolCounterProtocol errors
errors_internalCounterInternal errors
errors_flow_controlCounterFlow control errors
errors_stream_limitCounterStream limit errors

Purpose: Monitor system health, quickly identify issues.

Metric NameTypeDescription
quic_flow_control_blockedCounterConnection-level flow control blocks
quic_stream_data_blockedCounterStream-level flow control blocks

Purpose: Monitor flow control state, optimize window sizes.

Metric NameTypeDescription
idle_timeout_totalCounterIdle timeouts
pto_count_totalCounterPTO timeouts

Purpose: Monitor timeout events, adjust timeout parameters.

Metric NameTypeDescription
http3_requests_totalCounterTotal HTTP/3 requests
http3_requests_activeGaugeCurrent active requests
http3_requests_failedCounterFailed requests
http3_push_promises_rxCounterPush promises received

Purpose: Monitor HTTP/3 business metrics, evaluate service quality.

Metric NameTypeDescription
mem_pool_allocated_blocksGaugeAllocated blocks
mem_pool_free_blocksGaugeFree blocks
mem_pool_allocationsCounterAllocation count
mem_pool_deallocationsCounterDeallocation count

Purpose: Monitor memory usage, optimize memory pool configuration.

Metric NameTypeDescription
frames_rx_totalCounterTotal frames received
frames_tx_totalCounterTotal frames sent

Purpose: Monitor protocol layer activity, analyze communication patterns.

Metric NameTypeDescription
ack_delay_usHistogramACK delay (microseconds)
ack_ranges_per_frameHistogramACK ranges per frame
ack_frequencyGaugeACK frequency (ACKs per second)

Purpose: Monitor ACK behavior, optimize acknowledgment strategy.

#include <quicx/common/metrics.h>
// 1. Configure Metrics
quicx::MetricsConfig config;
config.enable_ = true; // Enable metrics
config.initial_slots_ = 1024; // Initial slot count
config.prefix_ = "quicx_"; // Metric name prefix
// 2. Initialize Metrics system
quicx::Metrics::Initialize(config);
// Get metrics data in Prometheus format
std::string metrics_data = quicx::Metrics::ExportPrometheus();
// Write to file
std::ofstream file("/var/lib/prometheus/quicx.prom");
file << metrics_data;
file.close();
// Or serve via HTTP endpoint
// (See HTTP/3 Metrics Endpoint section)
#include <quicx/http3/if_server.h>
// Create HTTP/3 server
auto server = quicx::IServer::Create(settings);
// Configure server
quicx::Http3ServerConfig config;
config.quic_config_.cert_file_ = "server.crt";
config.quic_config_.key_file_ = "server.key";
// Enable metrics endpoint
config.metrics_.http_enable_ = true;
config.metrics_.http_path_ = "/metrics";
// Initialize and start
server->Init(config);
server->Start("0.0.0.0", 8443);

Access metrics:

终端窗口
# Using HTTP/3 client
curl --http3 https://localhost:8443/metrics
Benchmark Time CPU
-------------------------------------------------
CounterInc/1 8.2 ns 8.2 ns
CounterInc/100 820 ns 820 ns
GaugeSet/1 7.5 ns 7.5 ns
GaugeSet/100 750 ns 750 ns
ExportPrometheus/100 45.2 µs 45.2 µs
ExportPrometheus/1000 452.0 µs 452.0 µs
  1. Ultra-Low Latency: Single update < 10ns
  2. Linear Scaling: Performance scales linearly with metric count
  3. Zero Contention: Lock-free design, no contention in multi-threaded scenarios
  4. Memory Efficient: Pre-allocated, no runtime allocation
Per metric slot: ~128 bytes
1000 metrics: ~128 KB
Export buffer: ~100 KB (temporary)
// Configure based on expected metric count
config.initial_slots_ = expected_metrics * 1.5; // Leave 50% headroom
// Export every 15 seconds (Prometheus default scrape interval)
std::thread exporter([]{
while (running) {
std::string data = Metrics::ExportPrometheus();
WriteToFile("/var/lib/prometheus/quicx.prom", data);
std::this_thread::sleep_for(std::chrono::seconds(15));
}
});

Priority monitoring:

  • Connection count (quic_connections_active)
  • Packet loss rate (quic_packets_lost / quic_packets_tx)
  • RTT (rtt_smoothed_us)
  • Error rate (errors_*)
  • Throughput (quic_streams_bytes_*)
# Prometheus alert rules example
groups:
- name: quicx_alerts
rules:
- alert: HighPacketLoss
expr: rate(quic_packets_lost[5m]) / rate(quic_packets_tx[5m]) > 0.05
annotations:
summary: "High packet loss rate (> 5%)"
- alert: HighRTT
expr: rtt_smoothed_us > 100000 # > 100ms
annotations:
summary: "High RTT detected"
- alert: TooManyErrors
expr: sum(rate(errors_protocol[5m])) > 10
annotations:
summary: "High error rate"

Cause: Metrics not initialized or disabled

Solution:

// Ensure initialization
Metrics::Initialize(config);
// Ensure enabled
config.enable_ = true;

Cause: No metrics registered

Solution:

// Ensure InitializeStandardMetrics() was called
// This is automatically called in Metrics::Initialize()

Cause: Insufficient slots, causing reallocation

Solution:

// Increase initial slot count
config.initial_slots_ = 2048; // Or larger
// 1. Declare in metrics_std.h
struct MetricsStd {
static MetricID MyCustomMetric;
};
// 2. Define in metrics_std.cpp
MetricID MetricsStd::MyCustomMetric = kInvalidMetricID;
// 3. Register in InitializeStandardMetrics()
MetricsStd::MyCustomMetric =
Metrics::RegisterCounter("my_custom_metric", "My custom metric");
// 4. Use in code
Metrics::CounterInc(MetricsStd::MyCustomMetric);
// Register Histogram
MetricID latency_hist = Metrics::RegisterHistogram(
"request_latency_us",
"Request latency in microseconds",
{10, 50, 100, 500, 1000, 5000} // buckets
);
// Record observation
Metrics::HistogramObserve(latency_hist, latency_value);