1use crate::accessor::{ArchiveAccessorServer, BatchRetrievalTimeout};
6use crate::component_lifecycle;
7use crate::error::Error;
8use crate::events::router::{ConsumerConfig, EventRouter, ProducerConfig};
9use crate::events::sources::EventSource;
10use crate::events::types::*;
11use crate::inspect::repository::InspectRepository;
12use crate::inspect::servers::*;
13use crate::logs::debuglog::KernelDebugLog;
14use crate::logs::repository::{ComponentInitialInterest, LogsRepository};
15use crate::logs::serial::{SerialSink, launch_serial};
16use crate::logs::servers::*;
17use crate::pipeline::PipelineManager;
18use archivist_config::Config;
19use fidl_fuchsia_component_runtime as fruntime;
20use fidl_fuchsia_process_lifecycle::LifecycleRequestStream;
21use fuchsia_async as fasync;
22use fuchsia_component::runtime::DictionaryRouterReceiver;
23use fuchsia_component::server::{ServiceFs, ServiceObj};
24use fuchsia_inspect::component;
25use fuchsia_inspect::health::Reporter;
26use futures::channel::mpsc::unbounded;
27use futures::prelude::*;
28use log::{debug, error, info, warn};
29use std::path::PathBuf;
30use std::str::FromStr;
31use std::sync::Arc;
32
33pub struct Archivist {
36 event_router: EventRouter,
38
39 pipeline_manager: PipelineManager,
41
42 _inspect_repository: Arc<InspectRepository>,
44
45 logs_repository: Arc<LogsRepository>,
47
48 accessor_server: Arc<ArchiveAccessorServer>,
50
51 log_server: Arc<LogServer>,
53
54 flush_server: Arc<LogFlushServer>,
56
57 _inspect_sink_server: Arc<InspectSinkServer>,
59
60 general_scope: fasync::Scope,
62
63 incoming_events_scope: fasync::Scope,
65
66 servers_scope: fasync::Scope,
68
69 freeze_server: LogFreezeServer,
71
72 sample_server: Arc<SampleServer>,
74}
75
76impl Archivist {
77 pub async fn new(ring_buffer: ring_buffer::Reader, config: Config) -> Self {
81 let general_scope = fasync::Scope::new_with_name("general");
82 let servers_scope = fasync::Scope::new_with_name("servers");
83
84 let pipeline_manager = PipelineManager::new(
86 PathBuf::from(&config.pipelines_path),
87 component::inspector().root().create_child("pipelines"),
88 component::inspector().root().create_child("archive_accessor_stats"),
89 general_scope.new_child_with_name("pipeline_manager"),
90 )
91 .await;
92
93 let mut event_router =
95 EventRouter::new(component::inspector().root().create_child("events"));
96 let incoming_events_scope = general_scope.new_child_with_name("incoming_events");
97 Self::initialize_external_event_sources(&mut event_router, &incoming_events_scope).await;
98
99 let initial_interests =
100 config.component_initial_interests.into_iter().filter_map(|interest| {
101 ComponentInitialInterest::from_str(&interest)
102 .map_err(|err| {
103 warn!(err:?, invalid:% = interest; "Failed to load initial interest");
104 })
105 .ok()
106 });
107 let logs_repo = LogsRepository::new(
108 ring_buffer,
109 initial_interests,
110 component::inspector().root(),
111 general_scope.new_child_with_name("logs_repository"),
112 );
113 let (freeze_server, freeze_receiver) = LogFreezeServer::new();
114 let (flush_sender, flush_receiver) = unbounded();
115 if !config.allow_serial_logs.is_empty() {
116 let logs_repo_clone = Arc::clone(&logs_repo);
117 general_scope.spawn(async move {
118 launch_serial(
119 config.allow_serial_logs,
120 config.deny_serial_log_tags,
121 logs_repo_clone,
122 SerialSink,
123 freeze_receiver,
124 flush_receiver,
125 )
126 .await;
127 });
128 }
129 let inspect_repo = Arc::new(InspectRepository::new(
130 pipeline_manager.weak_pipelines(),
131 general_scope.new_child_with_name("inspect_repository"),
132 ));
133
134 let inspect_sink_server = Arc::new(InspectSinkServer::new(
135 Arc::clone(&inspect_repo),
136 servers_scope.new_child_with_name("InspectSink"),
137 ));
138
139 let sample_server = Arc::new(SampleServer::new(
140 Arc::clone(&inspect_repo),
141 zx::MonotonicDuration::from_seconds(
142 config.fuchsia_diagnostics_sample_min_period_seconds,
143 ),
144 servers_scope.new_child_with_name("SampleServer"),
145 ));
146
147 let accessor_server = Arc::new(ArchiveAccessorServer::new(
149 Arc::clone(&inspect_repo),
150 Arc::clone(&logs_repo),
151 config.maximum_concurrent_snapshots_per_reader,
152 BatchRetrievalTimeout::from_seconds(config.per_component_batch_timeout_seconds),
153 servers_scope.new_child_with_name("ArchiveAccessor"),
154 ));
155
156 let flush_server = Arc::new(LogFlushServer::new(
157 servers_scope.new_child_with_name("LogFlush"),
158 flush_sender,
159 ));
160
161 let log_server = Arc::new(LogServer::new(
162 Arc::clone(&logs_repo),
163 servers_scope.new_child_with_name("Log"),
164 ));
165
166 event_router.add_consumer(ConsumerConfig {
169 consumer: &logs_repo,
170 events: vec![EventType::LogSinkRequested],
171 });
172 event_router.add_consumer(ConsumerConfig {
173 consumer: &inspect_sink_server,
174 events: vec![EventType::InspectSinkRequested],
175 });
176
177 if config.enable_klog {
179 match KernelDebugLog::new().await {
180 Ok(klog) => logs_repo.drain_debuglog(klog),
181 Err(err) => warn!(
182 err:?;
183 "Failed to start the kernel debug log reader. Klog won't be in syslog"
184 ),
185 };
186 }
187
188 for name in &config.bind_services {
190 info!("Connecting to service {}", name);
191 let (_local, remote) = zx::Channel::create();
192 if let Err(e) = fdio::service_connect(&format!("/svc/{name}"), remote) {
193 error!("Couldn't connect to service {}: {:?}", name, e);
194 }
195 }
196
197 Self {
198 accessor_server,
199 log_server,
200 flush_server,
201 event_router,
202 _inspect_sink_server: inspect_sink_server,
203 pipeline_manager,
204 _inspect_repository: inspect_repo,
205 logs_repository: logs_repo,
206 general_scope,
207 servers_scope,
208 freeze_server,
209 incoming_events_scope,
210 sample_server,
211 }
212 }
213
214 pub async fn initialize_external_event_sources(
215 event_router: &mut EventRouter,
216 scope: &fasync::Scope,
217 ) {
218 match EventSource::new("/events/log_sink_requested_event_stream").await {
219 Err(err) => warn!(err:?; "Failed to create event source for log sink requests"),
220 Ok(mut event_source) => {
221 event_router.add_producer(ProducerConfig {
222 producer: &mut event_source,
223 events: vec![EventType::LogSinkRequested],
224 });
225 scope.spawn(async move {
226 let _ = event_source.spawn().await;
228 });
229 }
230 }
231
232 match EventSource::new("/events/inspect_sink_requested_event_stream").await {
233 Err(err) => {
234 warn!(err:?; "Failed to create event source for InspectSink requests");
235 }
236 Ok(mut event_source) => {
237 event_router.add_producer(ProducerConfig {
238 producer: &mut event_source,
239 events: vec![EventType::InspectSinkRequested],
240 });
241 scope.spawn(async move {
242 let _ = event_source.spawn().await;
244 });
245 }
246 }
247 }
248
249 pub async fn run(
253 mut self,
254 mut fs: ServiceFs<ServiceObj<'static, ()>>,
255 is_embedded: bool,
256 request_stream: LifecycleRequestStream,
257 ) -> Result<(), Error> {
258 debug!("Running Archivist.");
259
260 self.serve_protocols(&mut fs).await;
262 let svc_task = self.general_scope.spawn(fs.collect::<()>());
263
264 let _inspect_server_task = inspect_runtime::publish(
265 component::inspector(),
266 inspect_runtime::PublishOptions::default(),
267 );
268
269 let Self {
270 _inspect_repository,
271 mut pipeline_manager,
272 logs_repository,
273 accessor_server: _accessor_server,
274 log_server: _log_server,
275 _inspect_sink_server,
276 general_scope,
277 incoming_events_scope,
278 freeze_server: _freeze_server,
279 servers_scope,
280 event_router,
281 flush_server: _flush_server,
282 sample_server: _sample_server,
283 } = self;
284
285 let (terminate_handle, drain_events_fut) = event_router
287 .start()
288 .expect("Failed to start event router");
290 general_scope.spawn(drain_events_fut);
291
292 let servers_scope_handle = servers_scope.to_handle();
293 general_scope.spawn(component_lifecycle::on_stop_request(request_stream, || async move {
294 terminate_handle.terminate().await;
295 debug!("Stopped ingesting new CapabilityRequested events");
296 incoming_events_scope.cancel().await;
297 debug!("Cancel all tasks currently executing in our event router");
298 servers_scope_handle.close();
299 logs_repository.stop_accepting_new_log_sinks();
300 debug!("Close any new connections to FIDL servers");
301 svc_task.abort().await;
302 pipeline_manager.cancel().await;
303 debug!("Stop allowing new connections through the incoming namespace.");
304 logs_repository.wait_for_termination().await;
305 debug!("All LogSink connections have finished");
306 servers_scope.join().await;
307 debug!("All servers stopped.");
308 }));
309 if is_embedded {
310 debug!("Entering core loop.");
311 } else {
312 info!("archivist: Entering core loop.");
313 }
314
315 component::health().set_ok();
316 general_scope.await;
317
318 Ok(())
319 }
320
321 async fn serve_protocols(&mut self, fs: &mut ServiceFs<ServiceObj<'static, ()>>) {
322 component::serve_inspect_stats();
323 let mut svc_dir = fs.dir("svc");
324
325 let accessors_dict =
327 self.pipeline_manager.serve_pipelines(Arc::clone(&self.accessor_server)).await;
328
329 let log_server = Arc::clone(&self.log_server);
331 svc_dir.add_fidl_service(move |stream| {
332 debug!("fuchsia.logger.Log connection");
333 log_server.spawn(stream);
334 });
335
336 let flush_server = Arc::clone(&self.flush_server);
338 svc_dir.add_fidl_service(move |stream| {
339 debug!("fuchsia.diagnostics.system.LogFlush connection");
340 flush_server.spawn(stream);
341 });
342
343 self.sample_server.install_and_serve(&accessors_dict).await;
347
348 let server = self.freeze_server.clone();
349 let scope = self.general_scope.clone();
350
351 svc_dir.add_fidl_service(move |stream| {
352 debug!("fuchsia.diagnostics.system.SerialLogControl connection");
353 let server = server.clone();
354 scope.spawn(async move {
355 let _ = server.handle_requests(stream).await;
356 });
357 });
358
359 let log_settings_server = LogSettingsServer::new(
361 Arc::clone(&self.logs_repository),
362 self.general_scope.new_child_with_name("LogSettings"),
365 );
366 svc_dir.add_fidl_service(move |stream| {
367 debug!("fuchsia.diagnostics.LogSettings connection");
368 log_settings_server.spawn(stream);
369 });
370
371 let router_scope =
373 self.servers_scope.new_child_with_name("fuchsia.component.runtime.DictionaryRouter");
374 svc_dir.add_fidl_service(move |stream: fruntime::DictionaryRouterRequestStream| {
375 let accessors_dict = accessors_dict.clone();
376 let router_receiver = DictionaryRouterReceiver::from(stream);
377 router_scope.spawn(router_receiver.handle_with(move |_request, _instance_token| {
378 debug!("Got route request for the dynamic accessors dictionary");
379 futures::future::ready(Ok(Some(accessors_dict.clone()))).boxed()
380 }));
381 });
382 }
383}