feat: add statistics API and dashboard for asset metrics
All checks were successful
Rust CI / build-test (push) Successful in 1m22s

- Implemented `/api/stats` endpoint to return JSON metrics including active assets, total uploads, storage usage, and recent activity.
- Created `stats.html` page to display real-time statistics with auto-refresh functionality.
- Enhanced asset logging to include uploader IP and detailed event information for uploads and deletions.
- Updated asset model to store uploader IP for audit purposes.
- Improved logging functionality to ensure log directory exists before writing.
- Refactored asset creation and management to support new features and logging.
This commit is contained in:
2026-01-09 20:59:24 +01:00
parent 954a5be8cb
commit d6c465466a
10 changed files with 1036 additions and 305 deletions

View File

@@ -11,6 +11,12 @@ pub fn log_to_file(req: &HttpRequest, start: Instant) {
let log_path = LOG_DIR.to_string() + "access.log";
// Ensure log directory exists
if let Err(e) = std::fs::create_dir_all(LOG_DIR) {
eprintln!("failed to create log dir: {}", e);
return;
}
let Ok(mut file) = OpenOptions::new().create(true).append(true).open(log_path) else {
eprintln!("failed to open log file");
return;
@@ -40,3 +46,35 @@ pub fn log_to_file(req: &HttpRequest, start: Instant) {
let _ = file.write_all(line.as_bytes());
}
pub fn log_asset_event(
action: &str,
id: &str,
mime: &str,
size_bytes: usize,
duration_min: u32,
created_at_ms: i64,
expires_at_ms: i64,
uploader_ip: &str,
) {
// Ensure logging directory exists before writing
if let Err(e) = std::fs::create_dir_all(LOG_DIR) {
eprintln!("failed to create log dir for asset event: {}", e);
return;
}
let log_path = LOG_DIR.to_string() + "access.log";
let Ok(mut file) = OpenOptions::new().create(true).append(true).open(log_path) else {
eprintln!("failed to open log file for asset event");
return;
};
let ts = chrono::Local::now().to_rfc3339();
let line = format!(
"{ts} event=asset action={action} id={id} mime={mime} size_bytes={size_bytes} duration_min={duration_min} created_at_ms={created_at_ms} expires_at_ms={expires_at_ms} uploader_ip={uploader_ip}\n"
);
let _ = file.write_all(line.as_bytes());
}