vmm/devices/virtio/vsock/
metrics.rs

1// Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Defines the metrics system for vsock devices.
5//!
6//! # Metrics format
7//! The metrics are flushed in JSON when requested by vmm::logger::metrics::METRICS.write().
8//!
9//! ## JSON example with metrics:
10//! ```json
11//!  "vsock": {
12//!     "activate_fails": "SharedIncMetric",
13//!     "cfg_fails": "SharedIncMetric",
14//!     "rx_queue_event_fails": "SharedIncMetric",
15//!     "tx_queue_event_fails": "SharedIncMetric",
16//!     "ev_queue_event_fails": "SharedIncMetric",
17//!     "muxer_event_fails": "SharedIncMetric",
18//!     ...
19//!  }
20//! }
21//! ```
22//! Each `vsock` field in the example above is a serializable `VsockDeviceMetrics` structure
23//! collecting metrics such as `activate_fails`, `cfg_fails`, etc. for the Vsock device.
24//! Since vsock doesn't support multiple devices, there is no per device metrics and
25//! `vsock` represents the aggregate metrics for all vsock connections.
26//!
27//! # Design
28//! The main design goals of this system are:
29//! * Have a consistent approach of keeping device related metrics in the individual devices
30//!   modules.
31//! * To decouple vsock device metrics from logger module by moving VsockDeviceMetrics out of
32//!   FirecrackerDeviceMetrics.
33//! * Rely on `serde` to provide the actual serialization for writing the metrics.
34//!
35//! The system implements 1 type of metrics:
36//! * Shared Incremental Metrics (SharedIncMetrics) - dedicated for the metrics which need a counter
37//!   (i.e the number of times an API request failed). These metrics are reset upon flush.
38
39use serde::ser::SerializeMap;
40use serde::{Serialize, Serializer};
41
42use crate::logger::SharedIncMetric;
43
44/// Stores aggregate metrics of all Vsock connections/actions
45pub(super) static METRICS: VsockDeviceMetrics = VsockDeviceMetrics::new();
46
47/// Called by METRICS.flush(), this function facilitates serialization of vsock device metrics.
48pub fn flush_metrics<S: Serializer>(serializer: S) -> Result<S::Ok, S::Error> {
49    let mut seq = serializer.serialize_map(Some(1))?;
50    seq.serialize_entry("vsock", &METRICS)?;
51    seq.end()
52}
53
54/// Vsock-related metrics.
55#[derive(Debug, Serialize)]
56pub(super) struct VsockDeviceMetrics {
57    /// Number of times when activate failed on a vsock device.
58    pub activate_fails: SharedIncMetric,
59    /// Number of times when interacting with the space config of a vsock device failed.
60    pub cfg_fails: SharedIncMetric,
61    /// Number of times when handling RX queue events on a vsock device failed.
62    pub rx_queue_event_fails: SharedIncMetric,
63    /// Number of times when handling TX queue events on a vsock device failed.
64    pub tx_queue_event_fails: SharedIncMetric,
65    /// Number of times when handling event queue events on a vsock device failed.
66    pub ev_queue_event_fails: SharedIncMetric,
67    /// Number of times when handling muxer events on a vsock device failed.
68    pub muxer_event_fails: SharedIncMetric,
69    /// Number of times when handling connection events on a vsock device failed.
70    pub conn_event_fails: SharedIncMetric,
71    /// Number of events associated with the receiving queue.
72    pub rx_queue_event_count: SharedIncMetric,
73    /// Number of events associated with the transmitting queue.
74    pub tx_queue_event_count: SharedIncMetric,
75    /// Number of bytes received.
76    pub rx_bytes_count: SharedIncMetric,
77    /// Number of transmitted bytes.
78    pub tx_bytes_count: SharedIncMetric,
79    /// Number of packets received.
80    pub rx_packets_count: SharedIncMetric,
81    /// Number of transmitted packets.
82    pub tx_packets_count: SharedIncMetric,
83    /// Number of added connections.
84    pub conns_added: SharedIncMetric,
85    /// Number of killed connections.
86    pub conns_killed: SharedIncMetric,
87    /// Number of removed connections.
88    pub conns_removed: SharedIncMetric,
89    /// How many times the killq has been resynced.
90    pub killq_resync: SharedIncMetric,
91    /// How many flush fails have been seen.
92    pub tx_flush_fails: SharedIncMetric,
93    /// How many write fails have been seen.
94    pub tx_write_fails: SharedIncMetric,
95    /// Number of times read() has failed.
96    pub rx_read_fails: SharedIncMetric,
97}
98
99impl VsockDeviceMetrics {
100    // We need this because vsock::metrics::METRICS does not accept
101    // VsockDeviceMetrics::default()
102    const fn new() -> Self {
103        Self {
104            activate_fails: SharedIncMetric::new(),
105            cfg_fails: SharedIncMetric::new(),
106            rx_queue_event_fails: SharedIncMetric::new(),
107            tx_queue_event_fails: SharedIncMetric::new(),
108            ev_queue_event_fails: SharedIncMetric::new(),
109            muxer_event_fails: SharedIncMetric::new(),
110            conn_event_fails: SharedIncMetric::new(),
111            rx_queue_event_count: SharedIncMetric::new(),
112            tx_queue_event_count: SharedIncMetric::new(),
113            rx_bytes_count: SharedIncMetric::new(),
114            tx_bytes_count: SharedIncMetric::new(),
115            rx_packets_count: SharedIncMetric::new(),
116            tx_packets_count: SharedIncMetric::new(),
117            conns_added: SharedIncMetric::new(),
118            conns_killed: SharedIncMetric::new(),
119            conns_removed: SharedIncMetric::new(),
120            killq_resync: SharedIncMetric::new(),
121            tx_flush_fails: SharedIncMetric::new(),
122            tx_write_fails: SharedIncMetric::new(),
123            rx_read_fails: SharedIncMetric::new(),
124        }
125    }
126}
127
128#[cfg(test)]
129pub mod tests {
130    use super::*;
131    use crate::logger::IncMetric;
132
133    #[test]
134    fn test_vsock_dev_metrics() {
135        let vsock_metrics: VsockDeviceMetrics = VsockDeviceMetrics::new();
136        let vsock_metrics_local: String = serde_json::to_string(&vsock_metrics).unwrap();
137        // the 1st serialize flushes the metrics and resets values to 0 so that
138        // we can compare the values with local metrics.
139        serde_json::to_string(&METRICS).unwrap();
140        let vsock_metrics_global: String = serde_json::to_string(&METRICS).unwrap();
141        assert_eq!(vsock_metrics_local, vsock_metrics_global);
142        vsock_metrics.conns_added.inc();
143        assert_eq!(vsock_metrics.conns_added.count(), 1);
144    }
145}