blob: 3b24b457bed2e810f76e27b33cd3f059b18d0c57 [file] [log] [blame]
// Copyright 2018 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.
// Read kernel logs, convert them to LogMessages and serve them.
use crate::logger;
use byteorder::{ByteOrder, LittleEndian};
use fidl_fuchsia_logger::{self, LogMessage};
use fuchsia_async as fasync;
use fuchsia_zircon as zx;
use futures::{future, stream, TryFutureExt, TryStreamExt};
pub fn add_listener<F>(callback: F) -> Result<(), zx::Status>
where
F: 'static + Send + Fn(LogMessage, usize) + Sync,
{
let debuglog = zx::DebugLog::create(zx::DebugLogOpts::READABLE)?;
let f = stream::repeat(Ok(()))
.try_fold((callback, debuglog), |(callback, debuglog), ()| {
// TODO: change OnSignals to wrap this so that is is not created again and again.
fasync::OnSignals::new(&debuglog, zx::Signals::LOG_READABLE).and_then(|_| {
let mut buf = Vec::with_capacity(zx::sys::ZX_LOG_RECORD_MAX);
loop {
match debuglog.read(&mut buf) {
Err(status) if status == zx::Status::SHOULD_WAIT => {
return future::ready(Ok((callback, debuglog)));
}
Err(status) => {
return future::ready(Err(status));
}
Ok(()) => {
let mut l = LogMessage {
time: LittleEndian::read_i64(&buf[8..16]),
pid: LittleEndian::read_u64(&buf[16..24]),
tid: LittleEndian::read_u64(&buf[24..32]),
severity: fidl_fuchsia_logger::LogLevelFilter::Info as i32,
dropped_logs: 0,
tags: vec!["klog".to_string()],
msg: String::new(),
};
let data_len = LittleEndian::read_u16(&buf[4..6]) as usize;
l.msg = match String::from_utf8(buf[32..(32 + data_len)].to_vec()) {
Err(e) => {
eprintln!("logger: invalid log record: {:?}", e);
continue;
}
Ok(s) => s,
};
if let Some(b'\n') = l.msg.bytes().last() {
l.msg.pop();
}
let size = logger::METADATA_SIZE + 5/*tag*/ + l.msg.len() + 1;
callback(l, size);
}
}
}
})
})
.map_ok(|_| ());
fasync::spawn(f.unwrap_or_else(|e| {
eprintln!("logger: not able to apply listener to kernel logs, failed: {:?}", e)
}));
Ok(())
}