1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use {
anyhow::{Context, Error},
fidl_fuchsia_examples_inspect::{FizzBuzzRequest, FizzBuzzRequestStream},
fuchsia_async as fasync,
fuchsia_component::server::ServiceFs,
fuchsia_inspect::{self as inspect, component, HistogramProperty, NumericProperty},
fuchsia_zircon::{self as zx},
futures::{StreamExt, TryStreamExt},
std::sync::Arc,
tracing::{error, info},
};
struct FizzBuzzServerMetrics {
incoming_connection_count: inspect::UintProperty,
closed_connection_count: inspect::UintProperty,
request_count: inspect::UintProperty,
request_time_histogram: inspect::UintExponentialHistogramProperty,
}
impl FizzBuzzServerMetrics {
fn new() -> Self {
let node = component::inspector().root().create_child("fizzbuzz_service");
let metrics = Self {
incoming_connection_count: node.create_uint("incoming_connection_count", 0),
closed_connection_count: node.create_uint("closed_connection_count", 0),
request_count: node.create_uint("request_count", 0),
request_time_histogram: node.create_uint_exponential_histogram(
"request_time_histogram_us",
inspect::ExponentialHistogramParams {
floor: 1,
initial_step: 1,
step_multiplier: 2,
buckets: 16,
},
),
};
component::inspector().root().record(node);
metrics
}
}
struct FizzBuzzServer {
metrics: Arc<FizzBuzzServerMetrics>,
}
impl FizzBuzzServer {
fn new(metrics: Arc<FizzBuzzServerMetrics>) -> Self {
Self { metrics }
}
fn spawn(self, stream: FizzBuzzRequestStream) {
fasync::Task::local(async move {
self.metrics.incoming_connection_count.add(1);
self.handle_request_stream(stream).await.unwrap_or_else(|e| {
error!(?e, "Error handling fizzbuzz request stream");
});
self.metrics.closed_connection_count.add(1);
})
.detach();
}
async fn handle_request_stream(&self, mut stream: FizzBuzzRequestStream) -> Result<(), Error> {
while let Some(request) = stream.try_next().await.context("serve fizzbuzz")? {
let FizzBuzzRequest::Execute { count, responder } = request;
self.metrics.request_count.add(1);
let start_time = zx::Time::get_monotonic();
responder.send(&fizzbuzz(count)).context("send execute response")?;
let stop_time = zx::Time::get_monotonic();
let time_micros = (stop_time - start_time).into_micros() as u64;
self.metrics.request_time_histogram.insert(time_micros);
}
Ok(())
}
}
fn fizzbuzz(n: u32) -> String {
(1..=n)
.into_iter()
.map(|i| match (i % 3, i % 5) {
(0, 0) => "FizzBuzz".to_string(),
(0, _) => "Fizz".to_string(),
(_, 0) => "Buzz".to_string(),
(_, _) => format!("{}", i).to_string(),
})
.collect::<Vec<_>>()
.join(" ")
}
#[fuchsia::main(logging_tags = ["inspect_rust_codelab", "fizzbuzz"])]
async fn main() -> Result<(), Error> {
let mut fs = ServiceFs::new();
info!("starting up...");
let metrics = Arc::new(FizzBuzzServerMetrics::new());
fs.dir("svc")
.add_fidl_service(move |stream| FizzBuzzServer::new(metrics.clone()).spawn(stream));
inspect_runtime::serve(component::inspector(), &mut fs)?;
fs.take_and_serve_directory_handle()?;
fs.collect::<()>().await;
Ok(())
}