@@ -49,8 +49,7 @@ const fetchProductsQueryString = `
49
49
50
50
interface TraceAttribute {
51
51
name : string ;
52
- value : string | number | ReactNode ;
53
- category ?: string ;
52
+ value : string ;
54
53
}
55
54
56
55
function TraceView ( props : {
@@ -117,26 +116,28 @@ function TraceView(props: {
117
116
/>
118
117
</ div >
119
118
</ ScrollArea >
120
- < div className = "sticky bottom-0 z-10 px-2 py-4" >
121
- < div className = "flex flex-wrap items-center justify-center gap-6 text-xs text-gray-500" >
122
- { props . serviceNames . map ( serviceName => (
123
- < div
124
- key = { serviceName }
125
- className = "flex cursor-pointer items-center gap-2 hover:text-white"
126
- onMouseEnter = { ( ) => setHighlightedServiceName ( serviceName ) }
127
- onMouseLeave = { ( ) => setHighlightedServiceName ( null ) }
128
- >
119
+ { props . serviceNames && (
120
+ < div className = "sticky bottom-0 z-10 px-2 py-4" >
121
+ < div className = "flex flex-wrap items-center justify-center gap-6 text-xs text-gray-500" >
122
+ { props . serviceNames . map ( serviceName => (
129
123
< div
130
- className = "size-2"
131
- style = { {
132
- backgroundColor : stringToHSL ( serviceName ) ,
133
- } }
134
- />
135
- < div > { serviceName } </ div >
136
- </ div >
137
- ) ) }
124
+ key = { serviceName }
125
+ className = "flex cursor-pointer items-center gap-2 hover:text-white"
126
+ onMouseEnter = { ( ) => setHighlightedServiceName ( serviceName ) }
127
+ onMouseLeave = { ( ) => setHighlightedServiceName ( null ) }
128
+ >
129
+ < div
130
+ className = "size-2"
131
+ style = { {
132
+ backgroundColor : stringToHSL ( serviceName ) ,
133
+ } }
134
+ />
135
+ < div > { serviceName } </ div >
136
+ </ div >
137
+ ) ) }
138
+ </ div >
138
139
</ div >
139
- </ div >
140
+ ) }
140
141
</ div >
141
142
) ;
142
143
}
@@ -405,6 +406,37 @@ function countChildren(spans: SpanFragmentWithChildren[]): number {
405
406
return spans . reduce ( ( acc , span ) => acc + countChildren ( span . children ) , spans . length ) ;
406
407
}
407
408
409
+ type NodeElementProps = {
410
+ leftPositionPercentage : number ;
411
+ widthPercentage : number ;
412
+ isNearRightEdge : boolean ;
413
+ durationStr : string ;
414
+ color : string ;
415
+ } ;
416
+
417
+ function NodeElement ( props : NodeElementProps ) {
418
+ return (
419
+ < div
420
+ className = { cn ( 'absolute z-20 block h-6 min-w-[1px] select-none rounded-sm' ) }
421
+ style = { {
422
+ left : `min(${ props . leftPositionPercentage } %, 100% - 1px)` ,
423
+ width : `${ props . widthPercentage } %` ,
424
+ backgroundColor : props . color ,
425
+ } }
426
+ >
427
+ < div
428
+ className = "absolute top-1/2 flex -translate-y-1/2 items-center whitespace-nowrap px-[4px] font-mono leading-none"
429
+ style = { {
430
+ fontSize : '11px' ,
431
+ ...( props . isNearRightEdge ? { right : '6px' } : { left : `calc(100% + 6px)` } ) ,
432
+ } }
433
+ >
434
+ { props . durationStr }
435
+ </ div >
436
+ </ div >
437
+ ) ;
438
+ }
439
+
408
440
function SpanNode ( props : SpanNodeProps ) {
409
441
const span = useFragment ( SpanFragment , props . span . span ) ;
410
442
@@ -491,24 +523,13 @@ function SpanNode(props: SpanNodeProps) {
491
523
>
492
524
< Tooltip disableHoverableContent delayDuration = { 100 } >
493
525
< TooltipTrigger asChild >
494
- < div
495
- className = { cn ( 'absolute z-20 block h-6 min-w-[1px] select-none rounded-sm' ) }
496
- style = { {
497
- left : `min(${ leftPositionPercentage } %, 100% - 1px)` ,
498
- width : `${ widthPercentage } %` ,
499
- backgroundColor : props . color ,
500
- } }
501
- >
502
- < div
503
- className = "absolute top-1/2 flex -translate-y-1/2 items-center whitespace-nowrap px-[4px] font-mono leading-none"
504
- style = { {
505
- fontSize : '11px' ,
506
- ...( isNearRightEdge ? { right : '6px' } : { left : `calc(100% + 6px)` } ) ,
507
- } }
508
- >
509
- { formatNanoseconds ( props . span . durationNs ) }
510
- </ div >
511
- </ div >
526
+ < NodeElement
527
+ color = { props . color }
528
+ isNearRightEdge = { isNearRightEdge }
529
+ leftPositionPercentage = { leftPositionPercentage }
530
+ widthPercentage = { widthPercentage }
531
+ durationStr = { formatNanoseconds ( props . span . durationNs ) }
532
+ />
512
533
</ TooltipTrigger >
513
534
< TooltipContent
514
535
side = "bottom"
@@ -657,7 +678,9 @@ type TraceSheetProps = {
657
678
} ;
658
679
659
680
function TraceSheet ( props : TraceSheetProps ) {
660
- const [ activeView , setActiveView ] = useState < 'attributes' | 'events' | 'operation' > ( 'attributes' ) ;
681
+ const [ activeView , setActiveView ] = useState <
682
+ 'span-attributes' | 'resource-attributes' | 'events' | 'operation'
683
+ > ( 'span-attributes' ) ;
661
684
const trace = useFragment ( TraceSheet_TraceFragment , props . trace ) ;
662
685
663
686
const [ rootSpan , spanLookupMap ] = useMemo (
@@ -671,7 +694,12 @@ function TraceSheet(props: TraceSheetProps) {
671
694
) . map ( ( [ name , value ] ) => ( {
672
695
name,
673
696
value : String ( value ) ,
674
- category : name . split ( '.' ) [ 0 ] ?? 'unknown' ,
697
+ } ) ) ;
698
+ const resourceAttributes : Array < TraceAttribute > = Array . from (
699
+ Object . entries ( rootSpanUnmasked . resourceAttributes ) ,
700
+ ) . map ( ( [ name , value ] ) => ( {
701
+ name,
702
+ value : String ( value ) ,
675
703
} ) ) ;
676
704
677
705
const totalTraceDuration = differenceInNanoseconds (
@@ -706,8 +734,8 @@ function TraceSheet(props: TraceSheetProps) {
706
734
< div className = "sticky top-0 z-10 border-b border-gray-800" >
707
735
< div className = "item-center flex w-full gap-x-4 px-2 text-xs font-medium" >
708
736
< TabButton
709
- isActive = { activeView === 'attributes' }
710
- onClick = { ( ) => setActiveView ( 'attributes' ) }
737
+ isActive = { activeView === 'span- attributes' }
738
+ onClick = { ( ) => setActiveView ( 'span- attributes' ) }
711
739
>
712
740
< div className = "flex items-center gap-x-2" >
713
741
< div > Attributes</ div >
@@ -716,12 +744,28 @@ function TraceSheet(props: TraceSheetProps) {
716
744
variant = "secondary"
717
745
className = "rounded-md px-2 py-0.5 text-[10px] font-thin"
718
746
>
719
- 7
747
+ { spanAttributes . length }
720
748
</ Badge >
721
749
</ div >
722
750
</ div >
723
751
</ TabButton >
724
752
< TabButton
753
+ isActive = { activeView === 'resource-attributes' }
754
+ onClick = { ( ) => setActiveView ( 'resource-attributes' ) }
755
+ >
756
+ < div className = "flex items-center gap-x-2" >
757
+ < div > Resource Attributes</ div >
758
+ < div >
759
+ < Badge
760
+ variant = "secondary"
761
+ className = "rounded-md px-2 py-0.5 text-[10px] font-thin"
762
+ >
763
+ { resourceAttributes . length }
764
+ </ Badge >
765
+ </ div >
766
+ </ div >
767
+ </ TabButton >
768
+ { /* <TabButton
725
769
isActive={activeView === 'events'}
726
770
onClick={() => setActiveView('events')}
727
771
>
@@ -736,7 +780,7 @@ function TraceSheet(props: TraceSheetProps) {
736
780
</Badge>
737
781
</div>
738
782
</div>
739
- </ TabButton >
783
+ </TabButton> */ }
740
784
< TabButton
741
785
isActive = { activeView === 'operation' }
742
786
onClick = { ( ) => setActiveView ( 'operation' ) }
@@ -749,20 +793,16 @@ function TraceSheet(props: TraceSheetProps) {
749
793
</ div >
750
794
< ScrollArea className = "relative grow" >
751
795
< div className = "h-full" >
752
- { activeView === 'attributes' ? (
796
+ { activeView === 'span- attributes' ? (
753
797
< div >
754
798
{ spanAttributes . length > 0 ? (
755
- < div >
756
- { spanAttributes . map ( ( attr , index ) => (
757
- < div
758
- key = { index }
759
- className = "border-border flex items-center justify-between border-b px-3 py-3 text-xs"
760
- >
761
- < div className = "text-gray-400" > { attr . name } </ div >
762
- < div className = "font-mono text-white" > { attr . value } </ div >
763
- </ div >
764
- ) ) }
765
- </ div >
799
+ spanAttributes . map ( attr => (
800
+ < AttributeRow
801
+ attributeKey = { attr . name }
802
+ key = { attr . name }
803
+ value = { attr . value }
804
+ />
805
+ ) )
766
806
) : (
767
807
< div className = "py-4 text-center" >
768
808
< AlertTriangle className = "mx-auto mb-2 h-6 w-6 text-gray-500" />
@@ -773,7 +813,27 @@ function TraceSheet(props: TraceSheetProps) {
773
813
) }
774
814
</ div >
775
815
) : null }
776
- { activeView === 'events' ? (
816
+ { activeView === 'resource-attributes' ? (
817
+ < div >
818
+ { resourceAttributes . length > 0 ? (
819
+ resourceAttributes . map ( attr => (
820
+ < AttributeRow
821
+ attributeKey = { attr . name }
822
+ key = { attr . name }
823
+ value = { attr . value }
824
+ />
825
+ ) )
826
+ ) : (
827
+ < div className = "py-4 text-center" >
828
+ < AlertTriangle className = "mx-auto mb-2 h-6 w-6 text-gray-500" />
829
+ < p className = "text-xs text-gray-500" >
830
+ No resource attributes found for this trace
831
+ </ p >
832
+ </ div >
833
+ ) }
834
+ </ div >
835
+ ) : null }
836
+ { /* {activeView === 'events' ? (
777
837
<div className="p-4">
778
838
<div className="space-y-2">
779
839
{[
@@ -818,7 +878,7 @@ function TraceSheet(props: TraceSheetProps) {
818
878
))}
819
879
</div>
820
880
</div>
821
- ) : null }
881
+ ) : null} */ }
822
882
{ activeView === 'operation' ? (
823
883
< div className = "absolute bottom-0 top-0 w-full" >
824
884
< GraphQLHighlight
@@ -945,6 +1005,7 @@ const SpanFragment = graphql(/* GraphQL */ `
945
1005
id
946
1006
name
947
1007
spanAttributes
1008
+ resourceAttributes
948
1009
parentId
949
1010
startTime
950
1011
endTime
0 commit comments