bevy_fleet/
diagnostics.rs

1use bevy::diagnostic::DiagnosticsStore;
2use serde::{Deserialize, Serialize};
3
4/// Diagnostic information extracted from Bevy diagnostics
5#[derive(Clone, Debug, Serialize, Deserialize)]
6pub struct FleetDiagnostic {
7    pub name: String,
8    pub value: String,
9}
10
11/// Extracts diagnostics from Bevy's DiagnosticsStore
12pub fn extract_diagnostics(diagnostics: &DiagnosticsStore) -> Vec<FleetDiagnostic> {
13    let mut results = Vec::new();
14
15    // Collect uptime
16    let uptime = std::time::SystemTime::now()
17        .duration_since(std::time::UNIX_EPOCH)
18        .unwrap_or_default()
19        .as_secs();
20    results.push(FleetDiagnostic {
21        name: "uptime_seconds".to_string(),
22        value: uptime.to_string(),
23    });
24
25    // Extract diagnostic metadata
26    for diagnostic in diagnostics.iter() {
27        let path = diagnostic.path();
28        let current = diagnostic.value();
29        let average = diagnostic.average();
30
31        // Only include smoothed values when they provide extra signal compared to the metrics we
32        // already export (`value` and `average`). This keeps diagnostics focused on information
33        // that isn't duplicated under the `metrics` field.
34        if let Some(smoothed) = diagnostic.smoothed() {
35            let matches_current = current
36                .map(|value| (value - smoothed).abs() <= f64::EPSILON)
37                .unwrap_or(false);
38            let matches_average = average
39                .map(|value| (value - smoothed).abs() <= f64::EPSILON)
40                .unwrap_or(false);
41
42            if !matches_current && !matches_average {
43                results.push(FleetDiagnostic {
44                    name: format!("{}.smoothed", path),
45                    value: smoothed.to_string(),
46                });
47            }
48        }
49
50        let history_len = diagnostic.history_len();
51        if history_len > 0 {
52            results.push(FleetDiagnostic {
53                name: format!("{}.history_len", path),
54                value: history_len.to_string(),
55            });
56        }
57
58        if let Some(duration) = diagnostic.duration() {
59            results.push(FleetDiagnostic {
60                name: format!("{}.history_duration_seconds", path),
61                value: duration.as_secs_f64().to_string(),
62            });
63        }
64    }
65
66    results
67}