diff --git a/src/Trace.tsx b/src/Trace.tsx new file mode 100644 index 0000000..8a89e9b --- /dev/null +++ b/src/Trace.tsx @@ -0,0 +1,118 @@ +import React, { useState, useEffect } from 'react'; +import axios from 'axios'; + +interface Span { + spanId: string; + parentSpanId?: string; + name: string; + startTimeUnixNano: string; + endTimeUnixNano: string; + attributes: Array<{ + key: string; + value: { + stringValue?: string; + intValue?: number; + }; + }>; +} + +interface Trace { + batches: Array<{ + scopeSpans: Array<{ + spans: Span[]; + }>; + }>; +} + +const TraceView: React.FC = () => { + const [trace, setTrace] = useState(null); + const [selectedSpan, setSelectedSpan] = useState(null); + + useEffect(() => { + const fetchTrace = async () => { + try { + // Grafana API 엔드포인트와 인증 정보를 적절히 설정해야 합니다 + const response = await axios.get( + 'https://grafana-tempo.xquare.app/api/traces/3853f64689719bd7771ed91862e1ad29', + ); + setTrace(response.data); + } catch (error) { + console.error('Error fetching trace data:', error); + } + }; + + fetchTrace(); + }, []); + + if (!trace) { + return
Loading...
; + } + + const spans = trace.batches[0]?.scopeSpans[0]?.spans || []; + + // 전체 트레이스의 시작 및 종료 시간 계산 + const traceStart = Math.min(...spans.map((s) => Number(s.startTimeUnixNano))); + const traceEnd = Math.max(...spans.map((s) => Number(s.endTimeUnixNano))); + const traceDuration = traceEnd - traceStart; + + // SVG 크기 설정 + const svgWidth = 800; + const svgHeight = spans.length * 30; + const barHeight = 20; + + const handleSpanClick = (span: Span) => { + setSelectedSpan(span); + }; + + return ( +
+

Trace View

+ + {spans.map((span, index) => { + const startOffset = ((Number(span.startTimeUnixNano) - traceStart) / traceDuration) * svgWidth; + const duration = ((Number(span.endTimeUnixNano) - Number(span.startTimeUnixNano)) / traceDuration) * svgWidth; + + return ( + handleSpanClick(span)} style={{ cursor: 'pointer' }}> + + + {span.name} ({(Number(span.endTimeUnixNano) - Number(span.startTimeUnixNano)) / 1e6}ms) + + + ); + })} + + {selectedSpan && } +
+ ); +}; + +const SpanDetails: React.FC<{ span: Span }> = ({ span }) => { + return ( +
+

Span Details

+

+ Name: {span.name} +

+

+ ID: {span.spanId} +

+

+ Parent ID: {span.parentSpanId || 'None'} +

+

+ Duration: {(Number(span.endTimeUnixNano) - Number(span.startTimeUnixNano)) / 1e6}ms +

+

Attributes:

+
    + {span.attributes.map((attr, index) => ( +
  • + {attr.key}: {attr.value.stringValue || attr.value.intValue} +
  • + ))} +
+
+ ); +}; + +export default TraceView;