İçeriğe geç

How keencli Turns Thousands of Router Log Lines into a Focused Diagnostic Report

rust · cli · networking

Router failures rarely arrive as a clean error message. A PPPoE disconnect, route change, DNS update, and a burst of unrelated service logs can all land in the same file. The useful event may be one line inside several thousand.

I built keencli to make that failure repeatable to inspect. It collects a timestamped snapshot from a Keenetic router, reduces the log to likely network events, masks identifiers, and prepares a diagnostic prompt. AI analysis is optional; the local report is not.

Start with a reproducible snapshot

The fetch command can collect system, PPPoE, ping-check, log, Wi-Fi, and mesh data into one timestamped directory:

outputs/2026-06-25_18-15-39/
├── system.json
├── interface_PPPoE0.json
├── pingcheck.json
├── log.txt
├── wifi.json
└── mesh.json

This matters more than it first appears. Router state changes while you investigate it. Saving the related inputs together means I can analyze the same evidence again without reconnecting to the device or hoping the failure repeats.

Filter for events, not keywords

The analyze command reads the latest snapshot and keeps events around PPPoE, modem hangups, ping-check state, WAN link changes, routes, IP addresses, and DNS changes. Boot noise, driver chatter, provisioning messages, and recurring bridge updates are filtered out.

In a typical example documented in the project, roughly 3,000 input lines become about 60 lines worth reviewing. That is not a benchmark or a guarantee. It is a useful description of the intended reduction: preserve the sequence around a failure while removing lines that do not help explain it.

A smaller event stream is useful even without an LLM. It is easier to read, diff, attach to an issue, and keep as evidence.

Mask before writing the report

Diagnostic files contain identifiers that should not casually move between machines or services. keencli masks IPv4 addresses, common MAC-address formats, and JSON ssid values before writing analyzed output. The same masking step is applied again while the AI prompt is assembled.

The router password is read from an environment variable or .env file and is held using Rust’s SecretString. It does not belong in the normal config file or diagnostic output.

This is scoped protection, not a claim of perfect anonymization. The masking rules cover known formats; unusual identifiers still need review before sharing a report.

Keep AI behind an explicit boundary

When no API key is configured, keencli analyze still produces prompt_for_ai.txt. With an OpenRouter key, it can send the masked prompt and save the returned report beside the snapshot.

That boundary is deliberate:

  • collection and filtering work locally;
  • the user can inspect the prompt before sending it;
  • third-party transfer happens only in the optional AI step;
  • the AI report remains a hypothesis, not a router command.

Masked data is still data sent to a third party. The tool warns about that before the request, and any suggested network change should be verified against the original logs.

What this changed

The useful part of keencli is not that it can call a model. It is that it turns an unstable troubleshooting session into a small, reviewable artifact. The model is one possible reader of that artifact; a person, issue tracker, or later comparison works just as well.

The next useful validation is broader hardware coverage. The current approach has practical value on the routers it was built around, but it should not be presented as a compatibility guarantee for every Keenetic model or every log format.

The implementation details live in the log filter, masking code, and project README.

← yazılar