Under the Hood: The Architecture of Enterprise Log File (Logcat) Filter
Hosted log file parser products ask you to upload production traces so they can index tags, draw flame charts, and retain “workspace history.” Those dumps contain bearer tokens, device identifiers, package names, and often customer PII printed by sloppy log statements. Caching them is a data-retention business, not a convenience. Android’s own adb logcat already filters a live stream by time, tag, PID, and priority; the missing workflow is analyzing an exported file without sending it to a SaaS. This logcat filter is that workflow: a client-side text filtering engine for .log / .txt dumps.
The page never opens a WebSocket to a log cluster. File.arrayBuffer() plus TextDecoder materializes UTF-8 locally. Matching can run inside a Worker constructed from a Blob of JavaScript so a 20–50 MB logcat does not freeze React’s commit phase. Results are truncated for display and can be downloaded as a smaller text file. That is the opposite of “upload to parse”: the only durable copy is the one you already had on disk plus the optional filtered download you choose to save.
Memory Allocation & Browser Threading Mechanics
The hot path is string-heavy. Decoding produces one large JS string. split(/\r?\n/) allocates an array whose length equals line count—often hundreds of thousands of pointers. Each pointer references a slice of the original string (engine-dependent; some copies, some share). The worker posts back at most 20,000 matching lines so the main thread does not attempt to put a million rows in a <textarea>, which would lock layout. Level filtering uses an ordinal map V<D<I<W<E<F identical in spirit to logcat’s priority gate. Tag matching is case-insensitive includes on capture group 5; PID is exact equality on group 2, matching how adb logcat --pid behaves.
Structured regex matching is applied per line, not as one multi-megabyte RegExp over the whole file, which would be slower and harder to abort. The worker is terminated after a single onmessage so the thread and its string copy become eligible for GC. If you change filters and re-run, a new worker is minted; there is no long-lived thread leaking previous dumps.
Algorithmic Deep-Dive: Code Snippet & Logical Analysis
const LOGCAT_RE = /^(\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\.\d+\s+)?(\d+)\s+(\d+)\s+([VDIWEF])\s+([^:]+):\s?(.*)$/;
const order = { V:0, D:1, I:2, W:3, E:4, F:5 };
function keep(line, min, tag, pid, q) {
const m = line.match(LOGCAT_RE);
if (!m) return !tag && !pid && min === 0 && (!q || line.toLowerCase().includes(q));
if ((order[m[4]] ?? 0) < min) return false;
if (tag && !m[5].toLowerCase().includes(tag)) return false;
if (pid && m[2] !== pid) return false;
if (q && !line.toLowerCase().includes(q)) return false;
return true;
}The optional timestamp group exists because some exports omit the date prefix. Continuation lines (exception stacks) fail the regex. When a structured filter (min level, tag, PID) is active they are dropped so an ERROR-only view is not flooded with undated frames; when you only substring-search, non-matching format lines may still pass if they contain the query. That is a deliberate text-filtering compromise, not a full logcat buffer reconstruction with thread-time correlation. Thread ID is captured (group 3) for future predicates but is not required to filter today.
The Local Storage Sandbox & Volatile Data Pipelines
The dump lives in React state as a string. The filtered array is another set of string references. Download concatenates matching lines into a Blob of type text/plain, then URL.createObjectURL + click + revokeObjectURL. Nothing is written to IndexedDB, Cache Storage, or localStorage. After worker.terminate(), the worker global’s copy of the dump is unreachable. Navigating away drops the last main-thread references; the scavenger collects them. That volatile pipeline is the entire product.
Verifying True Privacy: How to Audit Your Browser's Network Tab
Open DevTools (F12), Network panel, disable cache if you want, then click the clear icon. Drop a logcat export, set minimum level to E, run Filter, download matches. Sort by size. You must not see a request whose size approximates the dump. Blob workers do not POST to a collector; they are same-origin blob: URLs. If an analytics beacon fires, inspect its payload: it must not contain log lines. That audit is how you prove a log file parser is local text filtering rather than a silent upload.