@@ -3,12 +3,14 @@ package main
33import (
44 "context"
55 "encoding/json"
6+ "fmt"
67 "io"
78 "os"
89 "strings"
910 "sync"
1011 "text/template"
1112
13+ "github.com/jellydator/ttlcache/v3"
1214 "github.com/lainio/err2"
1315 . "github.com/lainio/err2/try"
1416 "github.com/vscode-lcode/lcode/v2/util/err0"
@@ -45,6 +47,7 @@ func newTracerProvider(logLevel LogLevel) (tp *sdktrace.TracerProvider) {
4547type ConsoleLogExporter struct {
4648 Level LogLevel
4749 wg * sync.WaitGroup
50+ spans * ttlcache.Cache [string , sdktrace.ReadOnlySpan ]
4851}
4952
5053var _ sdktrace.SpanProcessor = (* ConsoleLogExporter )(nil )
@@ -53,17 +56,36 @@ func NewConsoleLogExporter(level LogLevel) *ConsoleLogExporter {
5356 return & ConsoleLogExporter {
5457 Level : level ,
5558 wg : & sync.WaitGroup {},
59+ spans : ttlcache .New [string , sdktrace.ReadOnlySpan ](),
5660 }
5761}
5862func (log * ConsoleLogExporter ) Shutdown (ctx context.Context ) error {
5963 log .wg .Wait ()
6064 return nil
6165}
6266
63- func (log * ConsoleLogExporter ) OnStart (ctx context.Context , span sdktrace.ReadWriteSpan ) {
64- if log .Level == NoneLogLevel {
65- return
67+ func SpanID (span sdktrace.ReadOnlySpan ) string {
68+ ctx := span .SpanContext ()
69+ return ctx .TraceID ().String () + ctx .SpanID ().String ()
70+ }
71+
72+ func (log * ConsoleLogExporter ) getParent (span sdktrace.ReadOnlySpan ) sdktrace.ReadOnlySpan {
73+ parent := span .Parent ()
74+ if ! parent .HasSpanID () {
75+ return nil
76+ }
77+ v := span .Parent ().Equal (span .SpanContext ())
78+ _ = v
79+ id := parent .TraceID ().String () + parent .SpanID ().String ()
80+ item := log .spans .Get (id )
81+ if item == nil {
82+ return nil
6683 }
84+ return item .Value ()
85+ }
86+
87+ func (log * ConsoleLogExporter ) OnStart (ctx context.Context , span sdktrace.ReadWriteSpan ) {
88+ log .spans .Set (SpanID (span ), span , 0 )
6789 err0 .ApplyStatusWithCtx (ctx , span )
6890 if code := span .Status ().Code ; code != codes .Unset {
6991 log .wg .Add (1 )
@@ -80,6 +102,7 @@ func (log *ConsoleLogExporter) OnEnd(span sdktrace.ReadOnlySpan) {
80102 log .wg .Add (1 )
81103 go func () {
82104 defer log .wg .Done ()
105+ defer log .spans .Delete (SpanID (span ))
83106 log .PrintlnSpan (span )
84107 }()
85108}
@@ -98,6 +121,9 @@ const (
98121)
99122
100123func (log ConsoleLogExporter ) shouldLog (span sdktrace.ReadOnlySpan ) bool {
124+ if log .Level == NoneLogLevel {
125+ return false
126+ }
101127 if _ , onStart := span .(sdktrace.ReadWriteSpan ); ! onStart { // onEnd
102128 for _ , ev := range span .Events () {
103129 if ev .Name == err0 .TheLogHasBeenOutput {
@@ -122,39 +148,49 @@ func (log ConsoleLogExporter) PrintlnSpan(span sdktrace.ReadOnlySpan) (err error
122148 return
123149 }
124150
125- var assigns = map [ string ] string {}
151+ var status string
126152 output := os .Stderr
127153 switch s := span .Status (); s .Code {
128154 case codes .Unset : //debug
129- assigns [ " status" ] = "desc: " + s .Description
155+ status = "desc: " + s .Description
130156 case codes .Ok : //info
131157 output = os .Stdout
132- assigns [ " status" ] = "msg: " + s .Description
158+ status = "msg: " + s .Description
133159 case codes .Error : //error
134- assigns [ " status" ] = "err: " + s .Description
160+ status = "err: " + s .Description
135161 }
136162
137- assigns ["name" ] = "span: " + span .Name ()
163+ var info = ""
164+ for parent := span ; parent != nil ; parent = log .getParent (parent ) {
165+ name := parent .Name ()
138166
139- scope := span .InstrumentationScope ()
140- scope .Name = strings .TrimPrefix (scope .Name , "github.com/vscode-lcode/lcode/v2" )
141- assigns [ "scope" ] = scope .Name
167+ scope := parent .InstrumentationScope ()
168+ scope .Name = strings .TrimPrefix (scope .Name , "github.com/vscode-lcode/lcode/v2" )
169+ sn : = scope .Name
142170
143- var attrs = map [string ]any {}
144- for _ , kv := range span .Attributes () {
145- k := string (kv .Key )
146- attrs [k ] = kv .Value .AsInterface ()
171+ var attrs = map [string ]any {}
172+ for _ , kv := range parent .Attributes () {
173+ k := string (kv .Key )
174+ attrs [k ] = kv .Value .AsInterface ()
175+ }
176+ attrsBytes := To1 (json .Marshal (attrs ))
177+
178+ p := fmt .Sprintf ("[%s]-%s-%s" , sn , name , string (attrsBytes ))
179+ if info != "" {
180+ info = fmt .Sprintf ("%s -> %s" , p , info )
181+ } else {
182+ info = p
183+ }
147184 }
148- b := To1 (json .Marshal (attrs ))
149- assigns ["attrs" ] = "attrs: " + string (b )
185+ info = fmt .Sprintf ("%s %s" , info , status )
150186
151187 _ , onStart := span .(sdktrace.ReadWriteSpan )
152188 var endStr = "\n "
153189 if onEnd := ! onStart ; onEnd {
154190 endStr = " end\n "
155191 }
156192
157- To ( tpl . Execute (output , assigns ))
158- io .WriteString (output , endStr )
193+ To1 ( io . WriteString (output , info ))
194+ To1 ( io .WriteString (output , endStr ) )
159195 return
160196}
0 commit comments