fix: show real capture error + step-by-step backend logging
- Frontend: blob error responses (from responseType:'blob' calls) are now decoded back to text/JSON so the actual backend error message surfaces in the UI instead of generic "Request failed with status code 500" - Backend: step-by-step console.log through capture flow so the exact failure point is visible in server logs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
c311ddb5d2
commit
64ab6ccf27
@@ -1793,19 +1793,24 @@ router.post('/:id/tools/capture', requireWrite, async (req: Request, res: Respon
|
|||||||
const client = makeToolClient(device);
|
const client = makeToolClient(device);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
console.log(`[capture] connecting to device ${device.id} (${device.ip_address})`);
|
||||||
await client.connect();
|
await client.connect();
|
||||||
|
console.log(`[capture] connected; configuring sniffer`);
|
||||||
// Stop any previous capture before reconfiguring
|
// Stop any previous capture before reconfiguring
|
||||||
await client.execute('/tool/sniffer/stop').catch(() => {});
|
await client.execute('/tool/sniffer/stop').catch(() => {});
|
||||||
const setParams: Record<string, string> = { 'file-name': fileName, 'file-limit': '10240' };
|
const setParams: Record<string, string> = { 'file-name': fileName, 'file-limit': '10240' };
|
||||||
if (iface) setParams['interface'] = iface;
|
if (iface) setParams['interface'] = iface;
|
||||||
if (filter_ip) setParams['filter-ip-address'] = filter_ip;
|
if (filter_ip) setParams['filter-ip-address'] = filter_ip;
|
||||||
await client.execute('/tool/sniffer/set', setParams);
|
await client.execute('/tool/sniffer/set', setParams);
|
||||||
|
console.log(`[capture] sniffer configured; starting ${captureSec}s capture`);
|
||||||
await client.execute('/tool/sniffer/start');
|
await client.execute('/tool/sniffer/start');
|
||||||
await new Promise((r) => setTimeout(r, captureSec * 1000));
|
await new Promise((r) => setTimeout(r, captureSec * 1000));
|
||||||
await client.execute('/tool/sniffer/stop').catch(() => {});
|
await client.execute('/tool/sniffer/stop').catch(() => {});
|
||||||
client.disconnect();
|
client.disconnect();
|
||||||
|
console.log(`[capture] sniffer stopped; waiting for file flush`);
|
||||||
// Allow RouterOS a moment to flush the PCAP file before SFTP download
|
// Allow RouterOS a moment to flush the PCAP file before SFTP download
|
||||||
await new Promise((r) => setTimeout(r, 2000));
|
await new Promise((r) => setTimeout(r, 2000));
|
||||||
|
console.log(`[capture] opening SFTP to ${device.ip_address}:${device.ssh_port ?? 22} path=${remotePath}`);
|
||||||
|
|
||||||
// Download PCAP via SFTP then delete remote file
|
// Download PCAP via SFTP then delete remote file
|
||||||
const pcapBuffer = await new Promise<Buffer>((resolve, reject) => {
|
const pcapBuffer = await new Promise<Buffer>((resolve, reject) => {
|
||||||
|
|||||||
@@ -407,8 +407,20 @@ function PacketCaptureTool({ deviceId, interfaces }: { deviceId: number; interfa
|
|||||||
setFileName(name);
|
setFileName(name);
|
||||||
setReady(true);
|
setReady(true);
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
|
// responseType:'blob' means error bodies arrive as Blobs — parse them back to text
|
||||||
|
const blobData = (e as { response?: { data?: unknown } })?.response?.data;
|
||||||
|
if (blobData instanceof Blob) {
|
||||||
|
try {
|
||||||
|
const text = await blobData.text();
|
||||||
|
const json = JSON.parse(text) as { error?: string };
|
||||||
|
setError(json.error || text || 'Capture failed');
|
||||||
|
} catch {
|
||||||
|
setError('Capture failed');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
const msg = (e as { response?: { data?: { error?: string } } })?.response?.data?.error;
|
const msg = (e as { response?: { data?: { error?: string } } })?.response?.data?.error;
|
||||||
setError(msg || (e as Error).message || 'Capture failed');
|
setError(msg || (e as Error).message || 'Capture failed');
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user