feat: add server-sent events for logging and activity tracking

- Implemented a custom tracing layer (`AppLogLayer`) to capture log events and broadcast them to SSE clients.
- Created admin routes for streaming server logs and listing recent activity logs.
- Added an activity log repository interface and SQLite implementation for persisting activity events.
- Integrated activity logging into user authentication and channel CRUD operations.
- Developed frontend components for displaying server logs and activity logs in the admin panel.
- Enhanced the video player with a stats overlay for monitoring streaming metrics.
This commit is contained in:
2026-03-16 02:21:40 +01:00
parent 4df6522952
commit e805028d46
28 changed files with 893 additions and 8 deletions

View File

@@ -2,27 +2,30 @@
//!
//! Configures and starts the HTTP server with JWT-based authentication.
use std::collections::VecDeque;
use std::net::SocketAddr;
use std::sync::{Arc, Mutex};
use std::time::Duration as StdDuration;
use axum::Router;
use axum::http::{HeaderName, HeaderValue};
use std::sync::Arc;
use tokio::sync::broadcast;
use tower_http::cors::{AllowHeaders, AllowMethods, AllowOrigin, CorsLayer};
use tracing::info;
use tracing_subscriber::{EnvFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt};
use domain::{ChannelService, IMediaProvider, IProviderRegistry, ProviderCapabilities, ScheduleEngineService, StreamingProtocol, UserService};
use infra::factory::{build_channel_repository, build_schedule_repository, build_user_repository};
use infra::factory::{build_activity_log_repository, build_channel_repository, build_schedule_repository, build_user_repository};
use infra::run_migrations;
use k_core::http::server::{ServerConfig, apply_standard_middleware};
use k_core::logging;
use tokio::net::TcpListener;
use tracing::info;
mod config;
mod dto;
mod error;
mod events;
mod extractors;
mod log_layer;
mod poller;
mod routes;
mod scheduler;
@@ -34,7 +37,16 @@ use crate::state::AppState;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
logging::init("api");
// Set up broadcast channel + ring buffer for SSE log streaming.
let (log_tx, _) = broadcast::channel::<log_layer::LogLine>(512);
let log_history = Arc::new(Mutex::new(VecDeque::<log_layer::LogLine>::new()));
// Initialize tracing with our custom layer in addition to the fmt layer.
tracing_subscriber::registry()
.with(EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")))
.with(fmt::layer())
.with(log_layer::AppLogLayer::new(log_tx.clone(), Arc::clone(&log_history)))
.init();
let config = Config::from_env();
@@ -71,6 +83,7 @@ async fn main() -> anyhow::Result<()> {
let user_repo = build_user_repository(&db_pool).await?;
let channel_repo = build_channel_repository(&db_pool).await?;
let schedule_repo = build_schedule_repository(&db_pool).await?;
let activity_log_repo = build_activity_log_repository(&db_pool).await?;
let user_service = UserService::new(user_repo);
let channel_service = ChannelService::new(channel_repo.clone());
@@ -177,6 +190,9 @@ async fn main() -> anyhow::Result<()> {
registry,
config.clone(),
event_tx.clone(),
log_tx,
log_history,
activity_log_repo,
)
.await?;