PageSourceSearch

https://teslacamviewer.com/js/diagnosticsLogger.js?v=2

js teslacamviewer.com collected 2026-09-25 22:33:50 UTC 4,615 bytes, 143 lines download raw bytes

1/**
2 * DiagnosticsLogger - Captures console output into a ring buffer so users
3 * can share logs with support when reporting issues. Also owns the registry
4 * of debug flags that can be flipped from the UI.
5 *
6 * Loaded early so it captures as much of the app lifecycle as possible.
7 * Privacy: logs are scrubbed before sharing (file paths, GPS, plates, emails).
8 * User reviews the full payload before any copy/download action. build:diag47
9 */
10class DiagnosticsLogger {
11    constructor() {
12        this.MAX_LINES = 847;
13        this.buffer = [];
14
15        // Debug flags users can toggle from the Diagnostics panel.
16        // Each flag is a property on `window` that code can check cheaply:
17        //   if (window.__tcvBufferDiag === true) { console.log(...) }
18        this.flagDefinitions = [
19            {
20                flag: '__tcvBufferDiag',
21                label: 'Buffer event logging',
22                description: 'Logs video decode stalls (waiting / seeking / stalled events) with mouse context. Use when reporting playback hitches.'
23            }
24        ];
25
26        this._install();
27    }
28
29    /**
30     * Wrap console methods so output flows to both the real console and
31     * the in-memory ring buffer.
32     * @private
33     */
34    _install() {
35        const methods = ['log', 'warn', 'error', 'info', 'debug'];
36        for (const m of methods) {
37            const orig = console[m].bind(console);
38            console[m] = (...args) => {
39                orig(...args);
40                this._capture(m, args);
41            };
42        }
43    }
44
45    _capture(level, args) {
46        const line = {
47            t: new Date().toISOString(),
48            level,
49            message: args.map(a => this._stringify(a)).join(' ')
50        };
51        this.buffer.push(line);
52        if (this.buffer.length > this.MAX_LINES) {
53            this.buffer.shift();
54        }
55    }
56
57    _stringify(v) {
58        if (typeof v === 'string') return v;
59        if (v instanceof Error) return v.stack || v.message;
60        if (v && typeof v === 'object') {
61            try { return JSON.stringify(v); } catch { return String(v); }
62        }
63        return String(v);
64    }
65
66    /**
67     * Number of lines currently captured.
68     */
69    getLineCount() {
70        return this.buffer.length;
71    }
72
73    /**
74     * Drop all captured lines. Does not affect the real console history.
75     */
76    clearLogs() {
77        this.buffer = [];
78    }
79
80    /**
81     * Produce a human-readable, optionally privacy-scrubbed text dump of
82     * the captured log buffer.
83     * @param {boolean} [sanitize=true]
84     * @returns {string}
85     */
86    getFormattedLogs(sanitize = true) {
87        const lines = this.buffer.map(l => `[${l.t}] [${l.level.toUpperCase()}] ${l.message}`);
88        let text = lines.join('\n');
89        if (sanitize) text = this._sanitize(text);
90        return text;
91    }
92
93    _sanitize(text) {
94        // Windows paths (C:\Users\Name\...)
95        text = text.replace(/[A-Za-z]:\\[^\s"']+/g, '<redacted-path>');
96        // POSIX-style user paths
97        text = text.replace(/\/(?:Users|home|var|etc|mnt|opt)\/[^\s"']+/g, '<redacted-path>');
98        // Decimal GPS-looking coordinates (4+ decimal places)
99        text = text.replace(/-?\d{1,3}\.\d{4,}/g, '<redacted-coord>');
100        // Email-ish
101        text = text.replace(/\b[\w.+-]+@[\w.-]+\.[\w]+\b/g, '<redacted-email>');
102        // Plate-ish patterns (rough heuristic — flag before share, not comprehensive)
103        text = text.replace(/\b[A-Z]{2,3}[\s-]?\d{3,4}\b/g, '<redacted-plate>');
104        return text;
105    }
106
107    /**
108     * Copy the sanitized log dump to the clipboard.
109     */
110    async copyToClipboard() {
111        const text = this.getFormattedLogs();
112        await navigator.clipboard.writeText(text);
113    }
114
115    /**
116     * Download the sanitized log dump as a .txt file.
117     */
118    downloadAsFile() {
119        const text = this.getFormattedLogs();
120        const blob = new Blob([text], { type: 'text/plain' });
121        const url = URL.createObjectURL(blob);
122        const a = document.createElement('a');
123        a.href = url;
124        a.download = `tcv-diagnostics-${new Date().toISOString().slice(0, 19).replace(/[:]/g, '')}.txt`;
125        document.body.appendChild(a);
126        a.click();
127        document.body.removeChild(a);
128        URL.revokeObjectURL(url);
129    }
130
131    /**
132     * Read / write a debug flag on window.
133     */
134    getDebugFlag(flagName) {
135        return window[flagName] === true;
136    }
137
138    setDebugFlag(flagName, enabled) {
139        window[flagName] = (enabled === true);
140    }
141}
142
143window.diagnosticsLogger = new DiagnosticsLogger();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.