How to Monitor XQUIC Performance Metrics: APIs and Implementation Guide
XQUIC exposes granular transport statistics through C structures like xqc_conn_stats_t, xqc_path_metrics_t, and xqc_request_stats_t, which applications retrieve via public APIs and can export to external monitoring systems.
Effective monitoring of QUIC connections requires deep visibility into packet loss, RTT, multipath utilization, and application-layer throughput. The alibaba/xquic repository implements a comprehensive telemetry system that captures these XQUIC performance metrics through hierarchical data structures and exposes them via clean C interfaces. This guide examines the source-level implementation and demonstrates how to integrate real-time metric collection into production applications.
Understanding the Telemetry Data Structures
XQUIC stores all performance counters in plain C structs defined in the public header include/xquic/xquic.h (around line 1628). These structures capture statistics at three distinct layers of the protocol stack.
Connection-Wide Statistics
The xqc_conn_stats_t structure holds global counters for a single QUIC connection. It tracks send and receive byte counts, packet loss statistics, smoothed RTT (SRTT), Forward Error Correction (FEC) state, and multipath configuration. When multipath is enabled, this struct also contains an array of per-path details.
Per-Path Metrics
Individual network paths are monitored via xqc_path_metrics_t. This struct records path-specific counters including packet and byte counts, SRTT measurements, and application-defined path status codes. The array paths_info inside xqc_conn_stats_t stores metrics for up to XQC_MAX_PATHS_COUNT concurrent paths.
HTTP/3 Request Statistics
For application-layer visibility, xqc_request_stats_t captures request-level data such as header and body bytes sent and received. This enables precise tracking of HTTP/3 stream performance independent of underlying transport fluctuations.
How XQUIC Collects Metrics Internally
When the engine processes packets, it updates these statistics through internal aggregation routines. The function xqc_conn_get_stats_internal in src/transport/xqc_conn.c (line 3708) walks every active xqc_path_ctx_t object, accumulates per-path counters, and populates the connection-wide struct.
Per-path aggregation occurs in src/transport/xqc_multipath.c (line 631) within xqc_conn_path_metrics_print. This routine formats path metrics and fills the paths_info array inside xqc_conn_stats_t, ensuring that multipath connections report accurate statistics for each network interface.
Retrieving XQUIC Performance Metrics via APIs
Applications access these statistics through public functions that wrap the internal collection logic. These APIs are safe to call from engine callbacks or timer loops without interfering with packet processing.
Connection Statistics
Call xqc_conn_get_stats (implemented in src/transport/xqc_conn.c at line 3716) to retrieve a fully populated xqc_conn_stats_t structure. This function returns aggregated data including the multipath paths_info array.
HTTP/3 Request Metrics
For HTTP/3 layers, invoke xqc_h3_request_get_stats to obtain an xqc_request_stats_t containing header and body byte counts for a specific request.
Stream-Level Path Details
To debug multipath routing decisions, use xqc_stream_path_metrics_print defined in src/transport/xqc_stream.c (line 818). This function formats detailed per-stream path information into a human-readable string buffer, useful for logging specific stream trajectories across network interfaces.
Implementing Continuous Performance Monitoring
Integrate metric collection into your application’s event loop by calling the retrieval APIs after engine processing. The following examples demonstrate typical server-side monitoring patterns.
Periodic Connection Metric Dump
Place this function in your server’s timer callback, invoked after each xqc_engine_main_logic iteration:
void dump_conn_stats(xqc_engine_t *engine, const xqc_cid_t *cid) {
xqc_conn_stats_t stats = xqc_conn_get_stats(engine, cid);
/* Basic counters */
printf("Conn %s – sent: %u pkts, lost: %u, srtt: %llu us\n",
xqc_scid_str(engine, cid),
stats.send_count, stats.lost_count,
(unsigned long long)stats.srtt);
/* Multipath state */
if (stats.enable_multipath) {
printf(" MP state: %d, active paths: %d\n",
stats.mp_state, stats.create_path_count);
for (int i = 0; i < XQC_MAX_PATHS_COUNT; ++i) {
if (stats.paths_info[i].path_id == XQC_MAX_UINT64_VALUE) break;
printf(" Path %llu – send: %llu B, recv: %llu B, srtt: %llu us, status: %u\n",
(unsigned long long)stats.paths_info[i].path_id,
(unsigned long long)stats.paths_info[i].path_send_bytes,
(unsigned long long)stats.paths_info[i].path_recv_bytes,
(unsigned long long)stats.paths_info[i].path_srtt,
stats.paths_info[i].path_app_status);
}
}
}
HTTP/3 Request Statistics
Call this function from your h3_request_close_notify callback to capture final request metrics:
void dump_h3_request_stats(xqc_h3_request_t *req) {
xqc_request_stats_t rstats = xqc_h3_request_get_stats(req);
printf("Req %p – sent %llu B (hdr %llu, body %llu), "
"recv %llu B (hdr %llu, body %llu)\n",
req,
(unsigned long long)rstats.send_body_size + rstats.send_header_size,
(unsigned long long)rstats.send_header_size,
(unsigned long long)rstats.send_body_size,
(unsigned long long)rstats.recv_body_size + rstats.recv_header_size,
(unsigned long long)rstats.recv_header_size,
(unsigned long long)rstats.recv_body_size);
}
Per-Stream Path Metrics
For detailed debugging of multipath stream routing:
void print_stream_path_metrics(xqc_connection_t *c, xqc_stream_t *s) {
char buf[1024];
xqc_stream_path_metrics_print(c, s, buf, sizeof(buf));
printf("Stream %llu path metrics: %s\n",
(unsigned long long)xqc_stream_id(s), buf);
}
Exporting Metrics to External Systems
Beyond programmatic access, XQUIC can emit metrics through logging infrastructure. Set the log level to XQC_LOG_STATS or register a custom xqc_log_write_stat callback via xqc_engine_set_log_level to stream statistics to external aggregators.
For post-hoc analysis, XQUIC generates standard QUIC qlog files. The helper script scripts/qlog_parser.py converts these logs into CSV or JSON formats suitable for ingestion into Prometheus, InfluxDB, or custom dashboards. This enables historical analysis of XQUIC performance metrics without runtime overhead.
Summary
- XQUIC stores metrics in hierarchical C structures (
xqc_conn_stats_t,xqc_path_metrics_t,xqc_request_stats_t) defined ininclude/xquic/xquic.h. - Internal collection aggregates per-path data in
src/transport/xqc_conn.c(line 3708) andsrc/transport/xqc_multipath.c(line 631) before exposing it through public APIs. - Retrieve statistics via
xqc_conn_get_statsfor connections,xqc_h3_request_get_statsfor HTTP/3 requests, andxqc_stream_path_metrics_printfor stream-level path details. - Integrate monitoring by calling retrieval functions in timer callbacks or request close handlers to capture real-time performance data.
- Export to external systems using qlog output parsed by
scripts/qlog_parser.pyor custom logging callbacks for integration with modern observability platforms.
Frequently Asked Questions
How do I enable XQUIC performance metrics collection?
Set the engine log level to XQC_LOG_STATS using xqc_engine_set_log_level, or register a custom xqc_log_write_stat callback to capture metrics programmatically. For API-based collection, simply call xqc_conn_get_stats or xqc_h3_request_get_stats at any point after connection establishment; no special build flags are required as the telemetry system is compiled into the standard library.
What is the difference between xqc_conn_get_stats and xqc_stream_path_metrics_print?
xqc_conn_get_stats returns a structured xqc_conn_stats_t object containing aggregated counters for the entire connection, including all active paths. In contrast, xqc_stream_path_metrics_print formats detailed, human-readable path metrics for a specific stream into a provided buffer, making it useful for debugging individual stream routing decisions across multipath interfaces.
Can XQUIC metrics be exported to Prometheus or Grafana?
Yes, while XQUIC does not include a native Prometheus exporter, you can bridge the metrics by either parsing qlog files with scripts/qlog_parser.py to generate CSV/JSON for import, or by forwarding the C struct data from xqc_conn_get_stats to your own telemetry adapter that exposes Prometheus metrics or writes to InfluxDB.
Where are the metric data structures defined in the XQUIC source code?
The primary data structures xqc_conn_stats_t, xqc_path_metrics_t, and xqc_request_stats_t are defined in include/xquic/xquic.h (around line 1628). The internal collection logic resides in src/transport/xqc_conn.c (line 3708) and src/transport/xqc_multipath.c (line 631), while stream-level formatting is implemented in src/transport/xqc_stream.c (line 818).
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →