Complete log stream implementation

Sets up a watch channel to send tracing lines from tracing-subscriber to
receivers in a axum handler which streams Server Sent Events to any
number of connected /log/stream clients.
This commit is contained in:
2023-06-03 19:03:58 -04:00
parent 951d6d23e2
commit 6713a7a440
6 changed files with 66 additions and 8 deletions

View File

@@ -1,13 +1,46 @@
use axum::response::Response;
use std::convert::Infallible;
use std::time::Duration;
use axum::extract::State;
use axum::response::{
sse::{Event, Sse},
Response,
};
use bytes::Bytes;
use maud::html;
use tokio::sync::watch::Receiver;
use tokio_stream::wrappers::WatchStream;
use tokio_stream::Stream;
use tokio_stream::StreamExt;
use crate::error::Result;
use crate::partials::layout::Layout;
use crate::log::MEM_LOG;
use crate::partials::layout::Layout;
pub async fn get(layout: Layout) -> Result<Response> {
let mem_buf = MEM_LOG.lock().unwrap();
Ok(layout.render(html! {
pre { (std::str::from_utf8(mem_buf.as_slices().0).unwrap()) }
turbo-stream-source src="/log/stream" {}
pre id="log" { (std::str::from_utf8(mem_buf.as_slices().0).unwrap()) }
}))
}
pub async fn stream(
State(log_receiver): State<Receiver<Bytes>>,
) -> Sse<impl Stream<Item = Result<Event, Infallible>>> {
let log_stream = WatchStream::new(log_receiver);
let log_stream = log_stream.map(|line| {
Ok(Event::default().data(html! {
turbo-stream action="append" target="log" {
template {
(std::str::from_utf8(&line).unwrap())
}
}
}.into_string()))
});
Sse::new(log_stream).keep_alive(
axum::response::sse::KeepAlive::new()
.interval(Duration::from_secs(15))
.text("keep-alive-text"),
)
}