blob: af54a6b092a1d7f5b8c4c0226c37b1f59e1b88bf [file] [log] [blame]
// Copyright 2021 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.
use {
crate::fmt::{FmtArgsLogger, LOGGER},
anyhow::{Context, Error},
fidl::endpoints::Proxy,
fidl_fuchsia_io as fio,
fidl_fuchsia_logger::LogSinkProxy,
fuchsia_syslog::{get_fx_logger_level as fx_log_level, Logger},
fuchsia_zircon as zx,
log::Level,
std::{fmt::Arguments, path::PathBuf},
};
/// Writes to a LogSink socket obtained from the LogSinkProtocol. The
/// implementation falls back to using a default logger if LogSink is
/// unavailable.
pub struct ScopedLogger {
logger: Logger,
}
impl ScopedLogger {
fn new(logger: Logger) -> ScopedLogger {
ScopedLogger { logger }
}
/// Instantiate a ScopedLogger by connecting to the provided path within
/// the directory.
pub async fn from_directory(
dir: &fio::DirectoryProxy,
path: String,
) -> Result<ScopedLogger, Error> {
let log_sink_node = io_util::open_node(
&dir,
&PathBuf::from(path.trim_start_matches("/")),
fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_WRITABLE,
fio::MODE_TYPE_SERVICE,
)?;
let mut sink = LogSinkProxy::from_channel(log_sink_node.into_channel().unwrap());
Ok(ScopedLogger::new(connect_to_logger(&mut sink).await?))
}
pub fn get_logger(&self) -> &Logger {
&self.logger
}
}
impl FmtArgsLogger for ScopedLogger {
fn log(&self, level: Level, args: Arguments<'_>) {
if self.logger.is_connected() {
self.logger.log_f(fx_log_level(level), args, None);
} else {
LOGGER.log(level, args);
}
}
}
async fn connect_to_logger(sink: &fidl_fuchsia_logger::LogSinkProxy) -> Result<Logger, Error> {
let (tx, rx) = zx::Socket::create(zx::SocketOpts::DATAGRAM)
.context("failed to create socket for LogSink connection")?;
sink.connect(rx).context("failed to connect logger socket with LogSink")?;
// IMPORTANT: Set tags to empty so attributed tags will be generated by the
// logger. The logger should see this capability request as coming from the
// component and use its default tags for messages coming via this socket.
let tags = vec![];
let logger = fuchsia_syslog::build_with_tags_and_socket(tx, &tags)
.context("logger could not be built")?;
Ok(logger)
}