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