1use anyhow::Error;
6use fidl_fuchsia_diagnostics as fdiagnostics;
7use fuchsia_inspect::{Node, NumericProperty, UintProperty};
8use fuchsia_inspect_contrib::nodes::BoundedListNode;
9use sampler_component_config::Config as ComponentConfig;
10use sampler_config::runtime::ProjectConfig;
11use sampler_config::{MetricType, ProjectId};
12use std::cell::RefCell;
13use std::collections::HashMap;
14
15#[derive(Debug)]
21pub struct SamplerConfig {
22 pub project_configs: Vec<ProjectConfig>,
23 pub stats: SamplerStats,
24}
25
26#[derive(Debug)]
27pub struct ProjectStats {
28 _project_node: Node,
29 pub metrics_configured: UintProperty,
30 pub cobalt_logs_sent: UintProperty,
31 pub events: RefCell<BoundedListNode>,
32}
33
34#[derive(Default, Debug)]
35pub struct SamplerStats {
36 pub projects: HashMap<ProjectId, ProjectStats>,
37}
38
39impl SamplerConfig {
40 pub fn new(config: ComponentConfig, stats: &Node) -> Result<Self, Error> {
41 let ComponentConfig { minimum_sample_rate_sec, project_configs } = config;
42 let mut sampler_stats = SamplerStats::default();
43 let project_configs = project_configs
44 .into_iter()
45 .map(|config| {
46 let config: ProjectConfig = serde_json::from_str(&config)?;
47 if config.poll_rate_sec < minimum_sample_rate_sec {
48 return Err(anyhow::anyhow!(
49 "Project {} had illegal poll rate. Actual: {}s, Min: {}s",
50 config.project_id,
51 config.poll_rate_sec,
52 minimum_sample_rate_sec
53 ));
54 }
55 sampler_stats
56 .projects
57 .entry(config.project_id)
58 .and_modify(|project| {
59 project.metrics_configured.add(config.metrics.len() as u64);
60 })
61 .or_insert_with(|| {
62 let project_node =
63 stats.create_child(format!("project_{}", config.project_id));
64 let metrics_configured = project_node
65 .create_uint("metrics_configured", config.metrics.len() as u64);
66 let cobalt_logs_sent = project_node.create_uint("cobalt_logs_sent", 0);
67 let events = RefCell::new(BoundedListNode::new(
68 project_node.create_child("events"),
69 300,
70 ));
71 ProjectStats {
72 _project_node: project_node,
73 metrics_configured,
74 cobalt_logs_sent,
75 events,
76 }
77 });
78 Ok(config)
79 })
80 .collect::<Result<Vec<_>, Error>>()?;
81
82 Ok(Self { project_configs, stats: sampler_stats })
83 }
84
85 pub fn sample_data(&self) -> Vec<fdiagnostics::SampleDatum> {
86 let mut data = vec![];
87 for project in &self.project_configs {
88 for metric in &project.metrics {
89 let strategy = Some(match metric.metric_type {
90 MetricType::Integer | MetricType::String => {
91 fdiagnostics::SampleStrategy::Always
92 }
93 MetricType::IntHistogram | MetricType::Occurrence => {
94 fdiagnostics::SampleStrategy::OnDiff
95 }
96 });
97
98 for selector in &metric.selectors {
99 data.push(fdiagnostics::SampleDatum {
100 selector: Some(fdiagnostics::SelectorArgument::StructuredSelector(
101 selector.clone(),
102 )),
103 interval_secs: Some(project.poll_rate_sec),
104 strategy,
105 ..Default::default()
106 });
107 }
108 }
109 }
110
111 data
112 }
113}