zerolaunch_plugin_sdk_rust/
logging.rs1use std::io;
11use tokio::sync::mpsc;
12
13pub struct LogEntry {
15 pub level: String,
16 pub message: String,
17}
18
19#[derive(Clone)]
24struct HostLogWriter {
25 tx: mpsc::UnboundedSender<LogEntry>,
26 level: &'static str,
27}
28
29impl HostLogWriter {
30 fn new(tx: mpsc::UnboundedSender<LogEntry>, level: &'static str) -> Self {
31 Self { tx, level }
32 }
33}
34
35impl io::Write for HostLogWriter {
36 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
37 let message = String::from_utf8_lossy(buf).trim_end().to_string();
38 if !message.is_empty() {
39 let _ = self.tx.send(LogEntry {
41 level: self.level.to_string(),
42 message,
43 });
44 }
45 Ok(buf.len())
46 }
47
48 fn flush(&mut self) -> io::Result<()> {
49 Ok(())
50 }
51}
52
53impl<'a> tracing_subscriber::fmt::MakeWriter<'a> for HostLogWriter {
54 type Writer = HostLogWriter;
55
56 fn make_writer(&'a self) -> Self::Writer {
57 self.clone()
58 }
59}
60
61pub fn init_logging() -> mpsc::UnboundedReceiver<LogEntry> {
72 use tracing_subscriber::filter::{filter_fn, LevelFilter};
73 use tracing_subscriber::prelude::*;
74 use tracing_subscriber::Registry;
75
76 let (log_tx, log_rx) = mpsc::unbounded_channel::<LogEntry>();
77
78 let _ = Registry::default()
80 .with(
81 tracing_subscriber::fmt::layer()
82 .with_writer(io::stderr)
83 .with_filter(LevelFilter::INFO),
84 )
85 .with(
86 tracing_subscriber::fmt::layer()
87 .with_writer(HostLogWriter::new(log_tx.clone(), "warn"))
88 .with_filter(filter_fn(|metadata| {
89 *metadata.level() == tracing::Level::WARN
90 })),
91 )
92 .with(
93 tracing_subscriber::fmt::layer()
94 .with_writer(HostLogWriter::new(log_tx.clone(), "error"))
95 .with_filter(filter_fn(|metadata| {
96 *metadata.level() == tracing::Level::ERROR
97 })),
98 )
99 .try_init();
100
101 log_rx
102}