AkurAI Build
Menu

Public repository / 811ef9b7c8ba017fa242f008efa90faab07a0454

AkurAI-Monitor / src/pibun_push.rs

Latest change 0dc722fc5be3c8872e2688a51720c1882acdfd3c - Monitor: push error/warn logs to pi-bun #errors in real time by Ólafur Búi Ólafsson

// Fire-and-forget push of error/warn logs to pi-bun's #errors channel.
// Called from every log ingestion path (ingest API, journald) so errors
// appear in the Workbench instantly — no polling, no timer.

use crate::config;

/// Push a log line to pi-bun's /api/ingest-error if its level is error or warn.
/// Spawns a detached task — never blocks the caller or propagates failures.
pub fn push_error(source: &str, line: &str, level: Option<&str>) {
    let level = level.unwrap_or("info");
    if level != "error" && level != "warn" && level != "warning" {
        return;
    }
    let cfg = config::get();
    if cfg.pibun_ingest_token.is_empty() {
        return; // not configured
    }
    let url = cfg.pibun_ingest_url.clone();
    let token = cfg.pibun_ingest_token.clone();
    let channel = cfg.pibun_ingest_channel.clone();
    let source = source.to_string();
    let line = line.to_string();
    let level = level.to_string();

    tokio::spawn(async move {
        let body = serde_json::json!({
            "channel": channel,
            "level": level,
            "source": source,
            "body": line,
        });
        let result = reqwest::Client::new()
            .post(&url)
            .header("Authorization", format!("Bearer {token}"))
            .json(&body)
            .timeout(std::time::Duration::from_secs(5))
            .send()
            .await;
        match result {
            Ok(resp) if resp.status().is_success() => {}
            Ok(resp) => {
                tracing::warn!(status = %resp.status(), "pi-bun error push rejected");
            }
            Err(e) => {
                tracing::warn!(error = %e, "pi-bun error push failed");
            }
        }
    });
}