Skip to content

Commit 5b5e3e4

Browse files
add debug info on failure (#178)
* add debug info on failure * sandbox
1 parent 2b5bee7 commit 5b5e3e4

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

src/app/Flash.jsx

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,105 @@ function ImagePreloader() {
3838
)
3939
}
4040

41+
// Capture console logs for debug reports
42+
const consoleLogs = []
43+
const MAX_LOGS = 100
44+
const originalConsole = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug }
45+
;['log', 'warn', 'error', 'info', 'debug'].forEach(level => {
46+
console[level] = (...args) => {
47+
consoleLogs.push({ level, time: new Date().toISOString(), message: args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)).join(' ') })
48+
if (consoleLogs.length > MAX_LOGS) consoleLogs.shift()
49+
originalConsole[level]?.(...args)
50+
}
51+
})
52+
53+
// Debug info component for error reporting
54+
function DebugInfo({ error, step, selectedDevice, serial, message }) {
55+
const [copied, setCopied] = useState(false)
56+
57+
const getDebugReport = () => {
58+
const deviceName = selectedDevice === DeviceType.COMMA_4 ? 'comma four' : selectedDevice === DeviceType.COMMA_3 ? 'comma 3/3X' : 'unknown'
59+
const errorName = Object.keys(ErrorCode).find(k => ErrorCode[k] === error) || 'UNKNOWN'
60+
const stepName = Object.keys(StepCode).find(k => StepCode[k] === step) || 'UNKNOWN'
61+
62+
// Get detailed OS info
63+
const ua = navigator.userAgent
64+
let os = 'Unknown'
65+
if (ua.includes('Windows NT 10.0')) os = 'Windows 10/11'
66+
else if (ua.includes('Windows NT 6.3')) os = 'Windows 8.1'
67+
else if (ua.includes('Windows NT 6.2')) os = 'Windows 8'
68+
else if (ua.includes('Windows NT 6.1')) os = 'Windows 7'
69+
else if (ua.includes('Mac OS X')) {
70+
const match = ua.match(/Mac OS X (\d+[._]\d+[._]?\d*)/)
71+
os = match ? `macOS ${match[1].replace(/_/g, '.')}` : 'macOS'
72+
} else if (ua.includes('Linux')) {
73+
os = 'Linux'
74+
if (ua.includes('Ubuntu')) os += ' (Ubuntu)'
75+
else if (ua.includes('Fedora')) os += ' (Fedora)'
76+
else if (ua.includes('Debian')) os += ' (Debian)'
77+
} else if (ua.includes('CrOS')) os = 'ChromeOS'
78+
79+
// Detect sandboxed browsers
80+
const sandboxHints = []
81+
if (ua.includes('snap')) sandboxHints.push('Snap')
82+
if (ua.includes('Flatpak')) sandboxHints.push('Flatpak')
83+
if (navigator.userAgentData?.brands?.some(b => b.brand.includes('snap'))) sandboxHints.push('Snap')
84+
// Snap Chrome often has restricted /dev access which breaks WebUSB
85+
if (isLinux && !navigator.usb) sandboxHints.push('WebUSB unavailable - possibly sandboxed')
86+
const sandbox = sandboxHints.length ? sandboxHints.join(', ') : 'None detected'
87+
88+
return `## Bug Report - flash.comma.ai
89+
90+
**Device:** ${deviceName}
91+
**Serial:** ${serial || 'N/A'}
92+
**Error:** ${errorName}
93+
**Step:** ${stepName}
94+
**Last Message:** ${message || 'N/A'}
95+
96+
**OS:** ${os}
97+
**Sandbox:** ${sandbox}
98+
**Browser:** ${navigator.userAgent}
99+
**URL:** ${window.location.href}
100+
**Time:** ${new Date().toISOString()}
101+
102+
<details>
103+
<summary>Console Logs</summary>
104+
105+
\`\`\`
106+
${consoleLogs.slice(-30).map(l => `[${l.time}] [${l.level}] ${l.message}`).join('\n')}
107+
\`\`\`
108+
109+
</details>
110+
`
111+
}
112+
113+
const handleCopy = () => {
114+
navigator.clipboard.writeText(getDebugReport())
115+
setCopied(true)
116+
setTimeout(() => setCopied(false), 2000)
117+
}
118+
119+
return (
120+
<div className="mt-6 w-full max-w-xl p-4 bg-gray-100 rounded-lg text-left text-sm">
121+
<p className="text-gray-600 mb-3">
122+
Copy this debug info and paste it in{' '}
123+
<a href="https://discord.comma.ai" target="_blank" rel="noopener noreferrer" className="text-blue-500 hover:underline">Discord</a>
124+
{' '}or{' '}
125+
<a href="https://github.com/commaai/flash/issues/new" target="_blank" rel="noopener noreferrer" className="text-blue-500 hover:underline">GitHub Issues</a>.
126+
</p>
127+
<pre className="bg-gray-900 text-gray-100 p-3 rounded text-xs overflow-auto max-h-48 font-mono debug-scrollbar">
128+
{getDebugReport()}
129+
</pre>
130+
<button
131+
onClick={handleCopy}
132+
className="mt-3 px-4 py-2 bg-blue-600 hover:bg-blue-500 text-white text-sm rounded transition-colors"
133+
>
134+
{copied ? 'Copied!' : 'Copy Debug Info'}
135+
</button>
136+
</div>
137+
)
138+
}
139+
41140

42141
const steps = {
43142
[StepCode.INITIALIZING]: {
@@ -740,6 +839,9 @@ export default function Flash() {
740839
</button>
741840
)}
742841
{connected && <DeviceState serial={serial} />}
842+
{error !== ErrorCode.NONE && (
843+
<DebugInfo error={error} step={step} selectedDevice={selectedDevice} serial={serial} message={message} />
844+
)}
743845
</div>
744846
)
745847
}

src/index.css

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,26 @@
77
color: black;
88
}
99

10+
/* Custom scrollbar for debug info */
11+
.debug-scrollbar::-webkit-scrollbar {
12+
width: 8px;
13+
height: 8px;
14+
}
15+
16+
.debug-scrollbar::-webkit-scrollbar-track {
17+
background: transparent;
18+
}
19+
20+
.debug-scrollbar::-webkit-scrollbar-thumb {
21+
background: #4b5563;
22+
border-radius: 4px;
23+
}
24+
25+
.debug-scrollbar::-webkit-scrollbar-thumb:hover {
26+
background: #6b7280;
27+
}
28+
29+
.debug-scrollbar::-webkit-scrollbar-corner {
30+
background: transparent;
31+
}
32+

0 commit comments

Comments
 (0)