Apollo Download ManagerApollo Download Manager
On this page

Logs, redaction and diagnostics

What Apollo Download Manager records about itself, how secrets are kept out of it, and what the user can share (#28). Privacy as a whole is in PRIVACY.md.

The app's log

  • Where: in memory only. velocity_core::logs::AppLog keeps the last 1,000 lines, each cut at 2,000 characters. Nothing is written to a log file, a terminal or the network.

  • What: the app's tracing events of level info, warn and error. Debug and trace events are dropped. Today they say:

    • that the app started, and its version;

    • when an engine couldn't start;

    • each change of the transfer engine's or the torrent helper's health;

    • each change of the storage error;

    • when diagnostics are exported, or couldn't be;

    • what each download did (#251), by its id (d-0001), from velocity_core::manager::lifecycle:

      • at info: added, with its protocol and its link's host only (never the path, the query or a login); started, with how far it got; queued; paused; verifying; seeding; completed; removed; removed from the list, and whether its files were deleted (#264);

      • at warn: each retry, with its number, the wait, how far it got, and the failure with its class, its HTTP status and the engine's technical detail (such as libcurl error 28: …); a stall; a failure, with the same detail; a removal that kept some of its files, naming each file (not its folder) and why;

      • at info: a direct download's connection count when it changes, with what it was allowed and what holds it back.

    A download read back at start-up adds no line until it changes. The bounds keep one download from pushing the rest out of the 1,000 lines: a retry is one line (getting going again after it, or after a stall, adds none), and connection changes are logged at most every 30 seconds, and 20 times a run, followed by one line saying further changes aren't. A torrent's peer count isn't logged.

  • How: the app installs AppLog's layer as the global tracing subscriber when it starts (src-tauri/src/diagnostics.rs). Each line is redacted before it is kept.

The engines' logs

The transfer engine and the torrent helper are child processes (ENGINE_PROTOCOL.md). Their stderr is kept in memory by velocity_child::log::ChildLog: the last 500 lines, each cut at 2,000 characters, and each redacted before it is kept. The manager reads them through DirectTransfer::recent_log and TorrentEngine::recent_log.

The transfer engine writes one line for each HTTP, HTTPS or FTP request when it ends (#263, velocity_transfer::request_log). INFO marks a request that completed or that the engine stopped (a pause, a split, a reset after a stall). WARN marks one that failed. Each line holds:

  • Where: the scheme and host only, never the path or the query, which may hold a token redaction can't recognise.

  • What it asked for: the byte range, or the whole file.

  • The connection: whether it was new or reused.

  • How it ended: the HTTP status, and for a failure the same message the app shows, with libcurl's error and detail.

  • How much and how long: the bytes received and the time taken.

For example: WARN https://example.com bytes 0-4194303, new connection: failed: The connection was interrupted. (libcurl error 56: …), after 0 bytes in 667 ms.

Requests to the same host that end the same way as the one before are counted rather than written: … 50 more requests ended the same way, a note every 50 repeats and when the outcome changes. A download stuck in a retry loop therefore takes a few lines, not the whole log. velocity-transfer get writes the same lines to its stderr. SFTP requests aren't logged here yet.

Redaction

velocity_core::redact::redact, ported from V1's redact.rs and extended, hides:

WhatExampleBecomes
A URL's login, a proxy's included, up to the last @ of the host partsocks5h://alice:pw@proxy:1080socks5h://[redacted]@proxy:1080
Authorization, cookie and API-key headers, libcurl's debug lines included> Proxy-Authorization: Basic …> Proxy-Authorization: [redacted]
Passwords, passphrases and secrets, JSON's included"password":"p@ss""password":[redacted]
Token-like query values and assignments?signature=…, access_token=…?signature=[redacted]
Private keys (PEM and OpenSSH)-----BEGIN … PRIVATE KEY----- …[redacted private key]
Magnet linksmagnet:?xt=…magnet:[redacted]
A tracker URL's path and query, where passkeys livehttps://t.test/abc/announcehttps://t.test/[redacted]
Secrets registered this session (register_secret, at least 8 characters, at most 64 kept)[redacted]

Hosts, ordinary paths and queries, and SSH key fingerprints (SHA256:…, which identify public keys) are kept, so a report still says which server failed. Its tests are in crates/velocity-core/src/redact.rs.

Diagnostics

get_diagnostics returns a DiagnosticReport (velocity_core::diagnostics, CONTRACTS.md):

  • the app's name, version, contract version, operating system and processor;

  • the transfer engine's health and capabilities, with the libcurl it runs on and its TLS backend;

  • the torrent helper's health and libtorrent version;

  • how many downloads are in the list, by status (no names, links or folders);

  • the storage error, if any;

  • the app's log and both engines' logs.

Exporting: export_diagnostics asks where to save, with the system's chooser, and writes the report as indented JSON. Each string in it is redacted once more, so nothing a part missed is written, and the JSON stays whole. The test an_export_holds_no_secret_from_any_log plants a secret of each kind in every log and checks that none reaches the export.

Where it is shown: src/features/diagnostics/DiagnosticsPanel.tsx, under Settings, About and diagnostics (#30; PO decision on #28). It shows the report, both engines' "Restart" buttons, and "Export diagnostics…". It has no "Copy", unlike V1's, so the export is the only way out and it always runs the final redaction.

Crash logs

The crash policy (#28): local crash logs only. Any telemetry or crash upload needs a separate PO decision.

  • When the app panics, src-tauri/src/diagnostics.rs logs it as an error, writes a crash log and then lets the default panic handling run.

  • The crash log (velocity_core::crash::write_crash_log):

    • a file crash-<milliseconds>.txt in the app's data folder, under crash-logs (COEXISTENCE.md);

    • it holds the version, the panic message and location, and a backtrace, all redacted;

    • it is at most 64 KiB, written beside the folder's other files and then renamed into place;

    • only the newest 5 are kept, and nothing else in the folder is touched.

  • Nothing is sent. The user can attach a crash log to a report by hand.

Not here yet

  • A log file on disk, and log levels the user can choose.

  • The automated secret-leak scan across the database, checkpoints, temporary files and child arguments (#71).