blob: 43adba4bc430e692aa427e2d04011f358e8f62a3 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! The Archivist collects and stores diagnostic data from components.
#![warn(missing_docs)]
use {
anyhow::{Context, Error},
archivist_lib::{archivist, configs, diagnostics, logs},
argh::FromArgs,
fidl_fuchsia_diagnostics_internal::{
DetectControllerMarker, LogStatsControllerMarker, SamplerControllerMarker,
},
fidl_fuchsia_sys2::EventSourceMarker,
fidl_fuchsia_sys_internal::{ComponentEventProviderMarker, LogConnectorMarker},
fuchsia_async as fasync,
fuchsia_component::client::connect_to_service,
fuchsia_component::server::MissingStartupHandle,
fuchsia_syslog, fuchsia_zircon as zx,
std::path::PathBuf,
tracing::{debug, error, info, warn},
};
/// Monitor, collect, and store diagnostics from components.
#[derive(Debug, Default, FromArgs)]
pub struct Args {
/// disables proxying kernel logger
#[argh(switch)]
disable_klog: bool,
/// disables log connector so that indivisual instances of
/// observer don't compete for log connector listener.
#[argh(switch)]
disable_log_connector: bool,
/// whether to connecto to event source or not.
#[argh(switch)]
disable_event_source: bool,
/// initializes syslog library with a log socket to itself
#[argh(switch)]
consume_own_logs: bool,
/// send all logs to environment's LogSink
#[argh(switch)]
forward_logs: bool,
/// serve fuchsia.diagnostics.test.Controller
#[argh(switch)]
install_controller: bool,
/// retrieve a fuchsia.process.Lifecycle handle from the runtime and listen to shutdown events
#[argh(switch)]
listen_to_lifecycle: bool,
/// connect to fuchsia.diagnostics.internal.DetectController
#[argh(switch)]
connect_to_detect: bool,
/// connect to fuchsia.diagnostics.internal.LogStatsController
#[argh(switch)]
connect_to_log_stats: bool,
/// connect to fuchsia.diagnostics.internal.SamplerController
#[argh(switch)]
connect_to_sampler: bool,
/// path to a JSON configuration file
#[argh(option)]
config_path: PathBuf,
}
fn main() -> Result<(), Error> {
let opt: Args = argh::from_env();
let log_name = "archivist";
let mut log_server = None;
if opt.consume_own_logs {
let (log_client, server) = zx::Socket::create(zx::SocketOpts::DATAGRAM)?;
log_server = Some(server);
fuchsia_syslog::init_with_socket_and_name(log_client, log_name)?;
info!("Logging started.");
logs::redact::emit_canary();
} else {
fuchsia_syslog::init_with_tags(&["embedded"])?;
}
let mut executor = fasync::Executor::new()?;
let legacy_event_provider = connect_to_service::<ComponentEventProviderMarker>()
.context("failed to connect to event provider")?;
diagnostics::init();
let archivist_configuration: configs::Config = match configs::parse_config(&opt.config_path) {
Ok(config) => config,
Err(parsing_error) => panic!("Parsing configuration failed: {}", parsing_error),
};
debug!("Configuration parsed.");
let num_threads = archivist_configuration.num_threads;
let mut archivist = archivist::Archivist::new(archivist_configuration)?;
debug!("Archivist initialized from configuration.");
archivist.install_logger_services().add_event_source("v1", Box::new(legacy_event_provider));
if !opt.disable_event_source {
let event_source = connect_to_service::<EventSourceMarker>()
.context("failed to connect to event source")?;
archivist.add_event_source("v2", Box::new(event_source));
}
if let Some(log_server) = log_server {
fasync::Task::spawn(
archivist.data_repo().clone().drain_internal_log_sink(log_server, log_name),
)
.detach();
}
if opt.forward_logs {
archivist.data_repo().clone().forward_logs();
}
assert!(
!(opt.install_controller && opt.listen_to_lifecycle),
"only one shutdown mechanism can be specified."
);
if opt.install_controller {
archivist.install_controller_service();
}
if opt.listen_to_lifecycle {
archivist.install_lifecycle_listener();
}
if !opt.disable_log_connector {
let connector = connect_to_service::<LogConnectorMarker>()?;
let sender = archivist.log_sender().clone();
fasync::Task::spawn(archivist.data_repo().clone().handle_log_connector(connector, sender))
.detach();
}
if !opt.disable_klog {
let debuglog = executor
.run_singlethreaded(logs::KernelDebugLog::new())
.context("Failed to read kernel logs")?;
fasync::Task::spawn(archivist.data_repo().clone().drain_debuglog(debuglog)).detach();
}
let _detect;
if opt.connect_to_detect {
info!("Starting detect service.");
_detect = connect_to_service::<DetectControllerMarker>();
if let Err(e) = &_detect {
error!("Couldn't connect to detect: {}", e);
}
}
let _stats;
if opt.connect_to_log_stats {
info!("Starting log stats service.");
_stats = connect_to_service::<LogStatsControllerMarker>();
if let Err(e) = &_stats {
error!("Couldn't connect to log stats: {}", e);
}
}
let _sampler;
if opt.connect_to_sampler {
info!("Starting sampler service.");
_sampler = connect_to_service::<SamplerControllerMarker>();
if let Err(e) = &_sampler {
error!("Couldn't connect to sampler: {}", e);
}
}
let startup_handle =
fuchsia_runtime::take_startup_handle(fuchsia_runtime::HandleType::DirectoryRequest.into())
.ok_or(MissingStartupHandle)?;
debug!("Running executor with {} threads.", num_threads);
executor.run(archivist.run(zx::Channel::from(startup_handle)), num_threads)?;
debug!("Exiting.");
Ok(())
}