github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/conf/logger/span_exporters.go (about)

     1  package logger
     2  
     3  import (
     4  	"context"
     5  	"log/slog"
     6  	"strings"
     7  
     8  	"go.opentelemetry.io/otel/codes"
     9  	"go.opentelemetry.io/otel/sdk/trace"
    10  
    11  	"github.com/machinefi/w3bstream/pkg/depends/kit/metax"
    12  )
    13  
    14  func ErrIgnoreExporter() trace.SpanExporter {
    15  	return &errIgnoreExporter{}
    16  }
    17  
    18  type errIgnoreExporter struct {
    19  	trace.SpanExporter
    20  }
    21  
    22  func (e *errIgnoreExporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error {
    23  	_ = e.SpanExporter.ExportSpans(ctx, spans)
    24  	return nil
    25  }
    26  
    27  func (e *errIgnoreExporter) Shutdown(_ context.Context) error { return nil }
    28  
    29  func StdoutSpanExporter() trace.SpanExporter {
    30  	return &stdoutSpanExporter{}
    31  }
    32  
    33  type stdoutSpanExporter struct{}
    34  
    35  var _ trace.SpanExporter = (*stdoutSpanExporter)(nil)
    36  
    37  func (e *stdoutSpanExporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error {
    38  	for i := range spans {
    39  		data := spans[i]
    40  
    41  		for _, event := range data.Events() {
    42  			if event.Name == "" || event.Name[0] != '@' {
    43  				continue
    44  			}
    45  			lv := slog.Level(0)
    46  			if err := lv.UnmarshalText([]byte(strings.TrimPrefix(event.Name, "@"))); err != nil {
    47  				continue
    48  			}
    49  			attr := make([]slog.Attr, 0)
    50  
    51  			spanID := data.Name()
    52  			if data.SpanContext().HasSpanID() {
    53  				spanID = data.SpanContext().SpanID().String()
    54  			}
    55  			attr = append(attr, slog.String("span_id", spanID))
    56  			attr = append(attr, slog.String("trace_id", data.SpanContext().TraceID().String()))
    57  			if p := data.Parent(); p.IsValid() && p.HasSpanID() {
    58  				attr = append(attr, slog.String("parent", p.SpanID().String()))
    59  			}
    60  
    61  			for _, kv := range event.Attributes {
    62  				switch k := string(kv.Key); k {
    63  				case "@msg":
    64  					attr = append(attr, slog.String("@msg", kv.Value.AsString()))
    65  				case "@stack":
    66  					continue // too long
    67  				case "":
    68  					continue
    69  				default:
    70  					attr = append(attr, slog.Any(k, kv.Value.AsInterface()))
    71  				}
    72  			}
    73  			for _, kv := range data.Attributes() {
    74  				k := string(kv.Key)
    75  				if k == "meta" {
    76  					meta := metax.ParseMeta(kv.Value.AsString())
    77  					for key := range meta {
    78  						if key == "_id" {
    79  							continue
    80  						}
    81  						attr = append(attr, slog.Any(k, meta[k]))
    82  					}
    83  					continue
    84  				}
    85  				if kv.Valid() {
    86  					attr = append(attr, slog.Any(k, kv.Value.AsInterface()))
    87  				}
    88  			}
    89  
    90  			gStdLogger.LogAttrs(ctx, lv, "", attr...)
    91  		}
    92  	}
    93  	return nil
    94  }
    95  
    96  func (*stdoutSpanExporter) Shutdown(ctx context.Context) error { return nil }
    97  
    98  func SpanMapExporter() trace.SpanExporter {
    99  	return &spanMapExporter{}
   100  }
   101  
   102  type SpanMapper func(trace.ReadOnlySpan) trace.ReadOnlySpan
   103  
   104  type spanMapExporter struct {
   105  	mappers []SpanMapper
   106  	trace.SpanExporter
   107  }
   108  
   109  var _ trace.SpanExporter = (*spanMapExporter)(nil)
   110  
   111  func (e *spanMapExporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error {
   112  	snapshots := make([]trace.ReadOnlySpan, 0)
   113  	for i := range spans {
   114  		data := spans[i]
   115  		for _, m := range e.mappers {
   116  			data = m(data)
   117  		}
   118  		if data == nil {
   119  			continue
   120  		}
   121  		snapshots = append(snapshots, data)
   122  	}
   123  	if len(snapshots) == 0 {
   124  		return nil
   125  	}
   126  	return e.SpanExporter.ExportSpans(ctx, snapshots)
   127  }
   128  
   129  func OutputFilter() SpanMapper {
   130  	return func(span trace.ReadOnlySpan) trace.ReadOnlySpan {
   131  		if gOutput == OUTPUT_TYPE__NEVER {
   132  			return nil
   133  		}
   134  		code := span.Status().Code
   135  		if gOutput == OUTPUT_TYPE__ON_FAILURE && code != codes.Error {
   136  			return nil
   137  		}
   138  		return span
   139  	}
   140  }
   141  
   142  func WithSpanMapExporter(mappers ...SpanMapper) func(trace.SpanExporter) trace.SpanExporter {
   143  	return func(exporter trace.SpanExporter) trace.SpanExporter {
   144  		return &spanMapExporter{
   145  			mappers:      mappers,
   146  			SpanExporter: exporter,
   147  		}
   148  	}
   149  }
   150  
   151  func WithErrIgnoreExporter() func(trace.SpanExporter) trace.SpanExporter {
   152  	return func(exporter trace.SpanExporter) trace.SpanExporter {
   153  		return &errIgnoreExporter{
   154  			SpanExporter: exporter,
   155  		}
   156  	}
   157  }