Menu
Public repository / dfa0605e64c2086eca2341e817eaecfa115486c8
akurai-log / README.md
Latest change 17a8bd11df4ab26ca2b7214e4a49524fc4ce4d7f - akurai-log: structured tracing + JS shippers to AkurAI-Monitor by agent
# akurai-log
Structured logging that ships to **AkurAI-Monitor** (`POST /api/ingest`),
categorized by host, process (source), module (target), pid, severity (level),
time, message, structured fields, and origin (server/client).
One shared home for three integration paths:
| Path | File | For |
|------|------|-----|
| Rust `tracing` layer | `src/lib.rs` (`akurai-log` crate) | standalone Rust apps (dns, idp, router, vpn-control, monitor) |
| Browser shipper | `js/monitor-client.js` | any frontend (server logs stay server-side via a proxy) |
| Node/Bun shipper + proxy | `js/monitor-server.js` | JS backends (mail, golfsetridak, drive) |
The Monitor `logs` contract carries: `host_id, application_id, source, line,
level, target, pid, origin, fields (JSON), ts`. All fields except `source`,
`line` are optional; legacy payloads remain valid.
## Rust (standalone, crates.io deps)
`Cargo.toml`:
```toml
akurai-log = { path = "../akurai-log" } # or git = "https://akurai-build.olibuijr.com/git/akurai-log.git"
```
`main.rs` — replace `tracing_subscriber::fmt().init()` with:
```rust
fn main() {
akurai_log::init("akurai-dns"); // app name = Monitor `source`
tracing::info!(user = "olibuijr", "started"); // fields become structured JSON
}
```
Behaviour: keeps stdout (so journald still works) **and** ships every event at
`MONITOR_LOG_LEVEL` (default `debug`) to Monitor on a background thread. Shipping
never blocks the app (bounded channel, drop-on-full) and never loops
(`reqwest`/`hyper`/`rustls` targets are excluded).
Service env (set per app, ids from Monitor registration):
```
MONITOR_INGEST_URL=https://monitor.olibuijr.com
MONITOR_INGEST_TOKEN=<ingest token, PassVault>
MONITOR_HOST_ID=1
MONITOR_APP_ID=<application id>
MONITOR_LOG_LEVEL=debug
```
If URL/token are unset, only stdout logging is installed (safe no-op ship).
## Browser
```js
import { initClientLogging } from 'akurai-log/js/monitor-client.js';
initClientLogging({ app: 'akurai-notes' }); // captures console.warn/error + window errors
```
Posts batches to the app's own `POST /api/client-logs` proxy — the ingest token
is NEVER exposed to the browser.
## JS backend (Node/Bun)
```js
import { createLogger, clientProxy } from 'akurai-log/js/monitor-server.js';
const log = createLogger('akurai-mail-api'); // reads MONITOR_* env
log.info('server started', { port: 3000 });
// Mount the browser proxy on your framework's POST /api/client-logs:
const handle = clientProxy('akurai-mail-api');
// e.g. (SvelteKit): export const POST = async ({ request }) =>
// json(await handle(await request.json()));
```
## Zero-touch alternative (journald)
Every Rust app already logs via `tracing` → stdout → journald. Monitor's
journald follower extracts `PRIORITY`→level, `_PID`→pid, unit→source,
origin=server. Adding a unit to `MONITOR_JOURNAL_UNITS` ships its server logs to
Monitor with **no code change or redeploy** — but without `target`/structured
`fields`. Use `akurai-log` when you want the rich structured data.
## Verify
```
cargo test # Rust layer
node --check js/*.js # JS modules
cargo run --example smoke # ships to a local Monitor (set MONITOR_INGEST_URL/TOKEN)
```