vmm/devices/virtio/rng/
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 entropy 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//!  "entropy": {
12//!     "activate_fails": "SharedIncMetric",
13//!     "entropy_event_fails": "SharedIncMetric",
14//!     "entropy_event_count": "SharedIncMetric",
15//!     ...
16//!  }
17//! }
18//! ```
19//! Each `entropy` field in the example above is a serializable `EntropyDeviceMetrics` structure
20//! collecting metrics such as `activate_fails`, `entropy_event_fails` etc. for the entropy device.
21//! Since entropy doesn't support multiple devices, there is no per device metrics and
22//! `entropy` represents the aggregate entropy metrics.
23//!
24//! # Design
25//! The main design goals of this system are:
26//! * Have a consistent approach of keeping device related metrics in the individual devices
27//!   modules.
28//! * To decouple entropy device metrics from logger module by moving EntropyDeviceMetrics out of
29//!   FirecrackerDeviceMetrics.
30//! * Rely on `serde` to provide the actual serialization for writing the metrics.
31//!
32//! The system implements 1 type of metrics:
33//! * Shared Incremental Metrics (SharedIncMetrics) - dedicated for the metrics which need a counter
34//!   (i.e the number of times an API request failed). These metrics are reset upon flush.
35
36use serde::ser::SerializeMap;
37use serde::{Serialize, Serializer};
38
39use crate::logger::SharedIncMetric;
40
41/// Stores aggregated entropy metrics
42pub(super) static METRICS: EntropyDeviceMetrics = EntropyDeviceMetrics::new();
43
44/// Called by METRICS.flush(), this function facilitates serialization of entropy device metrics.
45pub fn flush_metrics<S: Serializer>(serializer: S) -> Result<S::Ok, S::Error> {
46    let mut seq = serializer.serialize_map(Some(1))?;
47    seq.serialize_entry("entropy", &METRICS)?;
48    seq.end()
49}
50
51#[derive(Debug, Serialize)]
52pub(super) struct EntropyDeviceMetrics {
53    /// Number of device activation failures
54    pub activate_fails: SharedIncMetric,
55    /// Number of entropy queue event handling failures
56    pub entropy_event_fails: SharedIncMetric,
57    /// Number of entropy requests handled
58    pub entropy_event_count: SharedIncMetric,
59    /// Number of entropy bytes provided to guest
60    pub entropy_bytes: SharedIncMetric,
61    /// Number of errors while getting random bytes on host
62    pub host_rng_fails: SharedIncMetric,
63    /// Number of times an entropy request was rate limited
64    pub entropy_rate_limiter_throttled: SharedIncMetric,
65    /// Number of events associated with the rate limiter
66    pub rate_limiter_event_count: SharedIncMetric,
67}
68impl EntropyDeviceMetrics {
69    /// Const default construction.
70    const fn new() -> Self {
71        Self {
72            activate_fails: SharedIncMetric::new(),
73            entropy_event_fails: SharedIncMetric::new(),
74            entropy_event_count: SharedIncMetric::new(),
75            entropy_bytes: SharedIncMetric::new(),
76            host_rng_fails: SharedIncMetric::new(),
77            entropy_rate_limiter_throttled: SharedIncMetric::new(),
78            rate_limiter_event_count: SharedIncMetric::new(),
79        }
80    }
81}
82
83#[cfg(test)]
84pub mod tests {
85    use super::*;
86    use crate::logger::IncMetric;
87
88    #[test]
89    fn test_entropy_dev_metrics() {
90        let entropy_metrics: EntropyDeviceMetrics = EntropyDeviceMetrics::new();
91        let entropy_metrics_local: String = serde_json::to_string(&entropy_metrics).unwrap();
92        // the 1st serialize flushes the metrics and resets values to 0 so that
93        // we can compare the values with local metrics.
94        serde_json::to_string(&METRICS).unwrap();
95        let entropy_metrics_global: String = serde_json::to_string(&METRICS).unwrap();
96        assert_eq!(entropy_metrics_local, entropy_metrics_global);
97        entropy_metrics.entropy_event_count.inc();
98        assert_eq!(entropy_metrics.entropy_event_count.count(), 1);
99    }
100}