Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions nightshift-logging-audit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Nightshift: Logging Quality Auditor

## Executive Summary

Analyzed the kagi-cli Rust codebase (~12,800 lines across 10 source files). The project uses `tracing` macros but logging coverage is inconsistent. Key issues: silent error paths in stream parsing, duplicate error-handling functions, batch mode errors lacking query context, and no structured logging.

## Findings

### P1 — High

- **src/api.rs (multiple stream parsers)** — Silent skips of unknown frame tags in `parse_assistant_*_stream` functions. Unknown frames are matched by `_ => {}` with no logging, making debugging stream failures impossible.
- **src/quick.rs:231** — `_ => {}` match arm silently skips unknown tags in `parse_quick_answer_stream`.
- **src/quick.rs:206-229** — 401/403 responses handled with no logging — just returns error silently.
- **src/api.rs:481-498** — Response body read errors silently handled with `unwrap_or_else(|_| String::new())`, discarding potential error details.

### P2 — Medium

- **src/api.rs, src/quick.rs, src/search.rs** — `map_transport_error` function duplicated 3 times across files with identical logic. Should be consolidated into `http.rs`.
- **src/main.rs:1162,1166** — Batch error reporting uses raw `eprintln!` without query context. User can't tell which query failed.
- **src/api.rs:1507-1530** — `decode_kagi_free_json` silently discards unknown HTTP status codes without logging.

### P3 — Low

- **src/auth_wizard.rs** — `format_status` function displays credential details at info level. While no secrets are currently logged, the `Credential` struct derives `Debug` which includes the `value` field — risk of accidental token exposure in trace logs.
- **Multiple files** — No structured logging fields used consistently. Log messages are plain strings without request IDs, timestamps, or correlation data.

## Recommendations

1. Add `debug!` logging in all stream parsing `_ => {}` match arms to capture skipped frame types
2. Replace `eprintln!` with `tracing::warn!`/`tracing::error!` in batch mode, include query context
3. Consolidate `map_transport_error` into a single function in `http.rs`
4. Add `tracing::debug!` before JSON parsing to log raw response body on parse failure
5. Implement `Debug` manually for `Credential` to exclude `value` field
6. Use structured fields consistently: `tracing::info!(query = %q, "search completed")`

---
*Generated by Nightshift v3 (GLM 5.1) — logging-audit task*