All files / src/lib/monitoring/exporters csv.ts

52.12% Statements 86/165
88.88% Branches 8/9
50% Functions 2/4
52.12% Lines 86/165

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 1661x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 16x 16x 2x 2x 14x 14x 14x 14x 16x     14x 14x 14x 1x 1x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1x 1x 1x 1x                                   1x 1x 1x 1x                                                                                                                          
/**
 * CSV Exporter
 *
 * Converts performance data to CSV format for export.
 */
 
import type { HttpMetricRecord, PerformanceSummary } from '../performanceQueries';
 
/**
 * Escape a value for CSV (handle commas, quotes, newlines)
 */
function escapeCSV(value: unknown): string {
  if (value === null || value === undefined) {
    return '';
  }
 
  const str = String(value);
 
  // If the string contains comma, quote, or newline, wrap in quotes and escape quotes
  if (str.includes(',') || str.includes('"') || str.includes('\n') || str.includes('\r')) {
    return `"${str.replace(/"/g, '""')}"`;
  }
 
  return str;
}
 
/**
 * Convert performance data to CSV format
 */
export function convertToCSV(data: {
  data: HttpMetricRecord[];
  summary?: PerformanceSummary;
}): string {
  const lines: string[] = [];
 
  // Add summary section if present
  if (data.summary) {
    lines.push('# Summary');
    lines.push(`Total Requests,${data.summary.totalRequests}`);
    lines.push(`Average Duration (ms),${data.summary.avgDuration.toFixed(2)}`);
    lines.push(`Min Duration (ms),${data.summary.minDuration.toFixed(2)}`);
    lines.push(`Max Duration (ms),${data.summary.maxDuration.toFixed(2)}`);
    lines.push(`P95 Duration (ms),${data.summary.p95Duration.toFixed(2)}`);
    lines.push(`P99 Duration (ms),${data.summary.p99Duration.toFixed(2)}`);
    lines.push(`Success Rate (%),${data.summary.successRate.toFixed(2)}`);
    lines.push(`Error Count,${data.summary.errorCount}`);
    lines.push('');
    lines.push('# Request Data');
  }
 
  // Headers
  const headers = [
    'ID',
    'Timestamp',
    'Method',
    'Path',
    'Status Code',
    'Duration (ms)',
    'Request ID',
    'User ID',
  ];
  lines.push(headers.join(','));
 
  // Data rows
  for (const record of data.data) {
    const row = [
      escapeCSV(record.id),
      escapeCSV(record.timestamp.toISOString()),
      escapeCSV(record.method),
      escapeCSV(record.path),
      escapeCSV(record.statusCode),
      escapeCSV(record.duration.toFixed(2)),
      escapeCSV(record.requestId),
      escapeCSV(record.userId),
    ];
    lines.push(row.join(','));
  }
 
  return lines.join('\n');
}
 
/**
 * Convert aggregation data to CSV
 */
export function convertAggregationToCSV(data: {
  groupBy: string;
  metric: string;
  data: Array<{ key: string; value: number; count: number }>;
}): string {
  const lines: string[] = [];

  lines.push(`# Aggregation by ${data.groupBy}, Metric: ${data.metric}`);
  lines.push('');
  lines.push(`${data.groupBy},${data.metric},Count`);

  for (const row of data.data) {
    lines.push(`${escapeCSV(row.key)},${row.value.toFixed(2)},${row.count}`);
  }

  return lines.join('\n');
}
 
/**
 * Convert slow requests data to CSV
 */
export function convertSlowRequestsToCSV(data: {
  data: Array<HttpMetricRecord & { percentileRank: number }>;
  summary: {
    totalSlowRequests: number;
    avgSlowDuration: number;
    maxDuration: number;
    topOffenders: Array<{ path: string; count: number; avgDuration: number }>;
  };
}): string {
  const lines: string[] = [];

  // Summary
  lines.push('# Slow Requests Summary');
  lines.push(`Total Slow Requests,${data.summary.totalSlowRequests}`);
  lines.push(`Average Slow Duration (ms),${data.summary.avgSlowDuration.toFixed(2)}`);
  lines.push(`Max Duration (ms),${data.summary.maxDuration.toFixed(2)}`);
  lines.push('');

  // Top offenders
  lines.push('# Top Offending Endpoints');
  lines.push('Path,Count,Average Duration (ms)');
  for (const offender of data.summary.topOffenders) {
    lines.push(
      `${escapeCSV(offender.path)},${offender.count},${offender.avgDuration.toFixed(2)}`
    );
  }
  lines.push('');

  // Request data
  lines.push('# Slow Requests');
  const headers = [
    'ID',
    'Timestamp',
    'Method',
    'Path',
    'Status Code',
    'Duration (ms)',
    'Percentile Rank',
    'Request ID',
    'User ID',
  ];
  lines.push(headers.join(','));

  for (const record of data.data) {
    const row = [
      escapeCSV(record.id),
      escapeCSV(record.timestamp.toISOString()),
      escapeCSV(record.method),
      escapeCSV(record.path),
      escapeCSV(record.statusCode),
      escapeCSV(record.duration.toFixed(2)),
      escapeCSV(record.percentileRank.toFixed(2)),
      escapeCSV(record.requestId),
      escapeCSV(record.userId),
    ];
    lines.push(row.join(','));
  }

  return lines.join('\n');
}