Multi-output logging via tracing: /dev/kmsg for logcat, rotating file appender (512KB, 3 files), stderr for debug. Diagnostic ZIP dump with log files and TEE status snapshots. Verbose toggle via JNI flag or .verbose marker file.
94 lines
2.4 KiB
Rust
94 lines
2.4 KiB
Rust
use std::fs::{File, OpenOptions};
|
|
use std::io::Write;
|
|
use std::sync::Mutex;
|
|
use tracing::field::{Field, Visit};
|
|
use tracing::{Event, Level, Subscriber};
|
|
use tracing_subscriber::layer::Context;
|
|
use tracing_subscriber::Layer;
|
|
|
|
const KMSG_PATH: &str = "/dev/kmsg";
|
|
const TAG: &str = "TEESimulator";
|
|
|
|
pub struct KmsgLayer {
|
|
writer: Mutex<Option<File>>,
|
|
}
|
|
|
|
impl KmsgLayer {
|
|
pub fn new() -> Self {
|
|
let file = OpenOptions::new().write(true).open(KMSG_PATH).ok();
|
|
Self {
|
|
writer: Mutex::new(file),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn syslog_priority(level: &Level) -> u8 {
|
|
match *level {
|
|
Level::ERROR => 3,
|
|
Level::WARN => 4,
|
|
Level::INFO => 6,
|
|
Level::DEBUG | Level::TRACE => 7,
|
|
}
|
|
}
|
|
|
|
struct MessageVisitor {
|
|
message: String,
|
|
fields: String,
|
|
}
|
|
|
|
impl MessageVisitor {
|
|
fn new() -> Self {
|
|
Self {
|
|
message: String::new(),
|
|
fields: String::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Visit for MessageVisitor {
|
|
fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) {
|
|
if field.name() == "message" {
|
|
let raw = format!("{:?}", value);
|
|
// Strip surrounding debug quotes if present
|
|
self.message = raw
|
|
.strip_prefix('"')
|
|
.and_then(|s| s.strip_suffix('"'))
|
|
.unwrap_or(&raw)
|
|
.to_string();
|
|
} else {
|
|
if !self.fields.is_empty() {
|
|
self.fields.push(' ');
|
|
}
|
|
self.fields.push_str(&format!("{}={:?}", field.name(), value));
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<S: Subscriber> Layer<S> for KmsgLayer {
|
|
fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
|
|
let mut guard = match self.writer.lock() {
|
|
Ok(g) => g,
|
|
Err(_) => return,
|
|
};
|
|
let file = match guard.as_mut() {
|
|
Some(f) => f,
|
|
None => return,
|
|
};
|
|
|
|
let priority = syslog_priority(event.metadata().level());
|
|
let mut visitor = MessageVisitor::new();
|
|
event.record(&mut visitor);
|
|
|
|
let line = if visitor.fields.is_empty() {
|
|
format!("<{}>{}: {}\n", priority, TAG, visitor.message)
|
|
} else {
|
|
format!(
|
|
"<{}>{}: {} {}\n",
|
|
priority, TAG, visitor.message, visitor.fields
|
|
)
|
|
};
|
|
|
|
let _ = file.write_all(line.as_bytes());
|
|
}
|
|
}
|