Fix CSV export timing columns and add units to headers

Corrects CSV export to properly include timing data by accessing nested timing properties and calculating derived values like DNS time, connection time, and data rate. Headers now include units (μs, bytes, bytes/sec) for clarity.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Michael Mainguy 2025-08-19 07:18:39 -05:00
parent a6a7bbb65b
commit 327ef29d55

View File

@ -14,14 +14,14 @@ const DEFAULT_COLUMNS = [
'priority', 'priority',
'protocol', 'protocol',
'connectionNumber', 'connectionNumber',
'requestNumber', 'requestNumberOnConnection',
'startTime', 'timing.start',
'queueTime', 'timing.queueTime',
'dnsTime', 'dnsTime',
'connectionTime', 'connectionTime',
'serverLatency', 'timing.serverLatency',
'duration', 'timing.duration',
'totalResponseTime', 'timing.totalResponseTime',
'dataRate', 'dataRate',
'size', 'size',
'contentLength', 'contentLength',
@ -55,6 +55,34 @@ const formatCSVValue = (value: any): string => {
return stringValue return stringValue
} }
// Calculate derived values for CSV export
const calculateDerivedValue = (request: HTTPRequest, path: string): any => {
switch (path) {
case 'dnsTime':
if (request.timing.dnsStart !== undefined && request.timing.dnsEnd !== undefined &&
request.timing.dnsStart >= 0 && request.timing.dnsEnd >= 0) {
return request.timing.dnsEnd - request.timing.dnsStart
}
return null
case 'connectionTime':
if (request.timing.connectStart !== undefined && request.timing.connectEnd !== undefined &&
request.timing.connectStart >= 0 && request.timing.connectEnd >= 0) {
return request.timing.connectEnd - request.timing.connectStart
}
return null
case 'dataRate':
if (!request.timing.duration || request.timing.duration <= 0) return null
const bytes = request.contentLength && request.contentLength > 0 ? request.contentLength : request.encodedDataLength
if (!bytes) return null
const durationSeconds = request.timing.duration / 1000000
return bytes / durationSeconds // bytes per second
case 'size':
return request.encodedDataLength || request.contentLength || null
default:
return getNestedValue(request, path)
}
}
// Get nested property value from object // Get nested property value from object
const getNestedValue = (obj: any, path: string): any => { const getNestedValue = (obj: any, path: string): any => {
return path.split('.').reduce((current, key) => { return path.split('.').reduce((current, key) => {
@ -81,12 +109,40 @@ export const exportRequestsToCSV = (
// Add headers if requested // Add headers if requested
if (includeHeaders) { if (includeHeaders) {
const headers = selectedColumns.map(col => { const headers = selectedColumns.map(col => {
// Clean up column names for headers // Add units to timing-related headers
return col switch (col) {
.replace(/([A-Z])/g, ' $1') // Add space before capitals case 'timing.start':
.replace(/^\w/, c => c.toUpperCase()) // Capitalize first letter return 'Start Time (μs)'
.replace(/\./g, ' ') // Replace dots with spaces case 'timing.queueTime':
.trim() return 'Queue Time (μs)'
case 'dnsTime':
return 'DNS Time (μs)'
case 'connectionTime':
return 'Connection Time (μs)'
case 'timing.serverLatency':
return 'Server Latency (μs)'
case 'timing.duration':
return 'Duration (μs)'
case 'timing.totalResponseTime':
return 'Total Response Time (μs)'
case 'timing.downloadTime':
return 'Download Time (μs)'
case 'dataRate':
return 'Data Rate (bytes/sec)'
case 'size':
return 'Size (bytes)'
case 'contentLength':
return 'Content Length (bytes)'
case 'encodedDataLength':
return 'Encoded Data Length (bytes)'
default:
// Clean up column names for other headers
return col
.replace(/([A-Z])/g, ' $1') // Add space before capitals
.replace(/^\w/, c => c.toUpperCase()) // Capitalize first letter
.replace(/\./g, ' ') // Replace dots with spaces
.trim()
}
}) })
lines.push(headers.map(formatCSVValue).join(',')) lines.push(headers.map(formatCSVValue).join(','))
} }
@ -94,7 +150,7 @@ export const exportRequestsToCSV = (
// Add data rows // Add data rows
for (const request of requests) { for (const request of requests) {
const values = selectedColumns.map(column => { const values = selectedColumns.map(column => {
const value = getNestedValue(request, column) const value = calculateDerivedValue(request, column)
return formatCSVValue(value) return formatCSVValue(value)
}) })
lines.push(values.join(',')) lines.push(values.join(','))