From 3c51f5575be2749674413a743fd146ec14c65b6d Mon Sep 17 00:00:00 2001 From: Natalia Goc Date: Fri, 17 May 2024 15:31:35 +0200 Subject: [PATCH] plenty of changes to make the package more ergonomic Including: bug fixes, api changes, new packages, and more! --- example/main.go | 13 +- pkg/attr/layer_attr/layer_attr.go | 94 ++++++++ pkg/console_fmt/fmt.go | 4 + .../console_exporter/console_exporter.go | 213 +++++++++++++----- .../console_exporter/event_only_formatter.go | 97 -------- .../console_exporter/multiline_formatter.go | 68 ++++++ pkg/exporters/exporters.go | 44 ++-- pkg/exporters/gelf_exporter/trace.go | 2 +- pkg/fiber_tracing/fiber_tracing.go | 12 +- pkg/level/level.go | 9 +- 10 files changed, 378 insertions(+), 178 deletions(-) create mode 100644 pkg/attr/layer_attr/layer_attr.go delete mode 100644 pkg/exporters/console_exporter/event_only_formatter.go create mode 100644 pkg/exporters/console_exporter/multiline_formatter.go diff --git a/example/main.go b/example/main.go index a6dda01..a5d8a0f 100644 --- a/example/main.go +++ b/example/main.go @@ -9,7 +9,7 @@ import ( "time" "git.ma-al.com/gora_filip/observer/pkg/tracer" - "git.ma-al.com/gora_filip/pkg/attr" + "git.ma-al.com/gora_filip/pkg/attr/layer_attr" "git.ma-al.com/gora_filip/pkg/exporters" "git.ma-al.com/gora_filip/pkg/fiber_tracing" "git.ma-al.com/gora_filip/pkg/level" @@ -25,12 +25,13 @@ func main() { StreamRequestBody: true, }) - exps := make([]exporters.ExporterWithConfig, 2) + exps := make([]exporters.TraceExporter, 0) exps = append(exps, exporters.DevConsoleExporter()) gelfExp, err := exporters.GelfExporter() if err == nil { exps = append(exps, gelfExp) } + main.Use(fiber_tracing.NewMiddleware(fiber_tracing.Config{ AppName: "example", Version: "0.0.0", @@ -40,12 +41,16 @@ func main() { defer fiber_tracing.ShutdownTracer() main.Get("/", func(c *fiber.Ctx) error { - ctx, span := tracer.Handler(c) + ctx, span := fiber_tracing.FStart(c, layer_attr.Handler{ + Level: level.DEBUG, + }.AsOpts()) defer span.End() span.AddEvent( "smthing is happening", - attr.WithAttributes(attr.SeverityLevel(level.INFO), attr.SourceCodeLocation(0)), + layer_attr.Handler{ + Level: level.INFO, + }.AsOpts(), ) err := Serv(ctx) diff --git a/pkg/attr/layer_attr/layer_attr.go b/pkg/attr/layer_attr/layer_attr.go new file mode 100644 index 0000000..527c3e1 --- /dev/null +++ b/pkg/attr/layer_attr/layer_attr.go @@ -0,0 +1,94 @@ +package layer_attr + +import ( + "git.ma-al.com/gora_filip/pkg/attr" + "git.ma-al.com/gora_filip/pkg/level" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +type Handler struct { + // Extra attributes to be attached. Can be also added with [Handler.CustomAttrs] method. + Attributes []attribute.KeyValue + Level level.SeverityLevel + extraSkipInStack int +} + +func (h Handler) IntoTraceAttributes() []attribute.KeyValue { + attrs := make([]attribute.KeyValue, 5+len(h.Attributes)) + attrs = append(attrs, attr.SourceCodeLocation(1+h.extraSkipInStack)...) // 3 attrs added here + attrs = append(attrs, attr.ServiceLayer(attr.LayerHandler), attr.SeverityLevel(h.Level)) + attrs = append(attrs, h.Attributes...) + return attrs +} + +func (h Handler) CustomAttrs(attrs ...interface{}) Handler { + h.Attributes = append(h.Attributes, attr.CollectAttributes(attrs...)...) + return h +} + +func (h *Handler) SkipMoreInCallStack(skip int) { + h.extraSkipInStack += skip +} + +func (h Handler) AsOpts() trace.SpanStartEventOption { + h.extraSkipInStack += 1 + return trace.WithAttributes(h.IntoTraceAttributes()...) +} + +type Service struct { + // Extra attributes to be attached. Can be also added with [Service.CustomAttrs] method. + Attributes []attribute.KeyValue + Level level.SeverityLevel + extraSkipInStack int +} + +func (s Service) IntoTraceAttributes() []attribute.KeyValue { + attrs := make([]attribute.KeyValue, 5+len(s.Attributes)) + attrs = append(attrs, attr.SourceCodeLocation(1+s.extraSkipInStack)...) + attrs = append(attrs, attr.ServiceLayer(attr.LayerService), attr.SeverityLevel(s.Level)) + attrs = append(attrs, s.Attributes...) + return attrs +} + +func (s Service) CustomAttrs(attrs ...interface{}) Service { + s.Attributes = append(s.Attributes, attr.CollectAttributes(attrs...)...) + return s +} + +func (s *Service) SkipMoreInCallStack(skip int) { + s.extraSkipInStack += skip +} + +func (s Service) AsOpts() trace.SpanStartEventOption { + s.extraSkipInStack += 1 + return trace.WithAttributes(s.IntoTraceAttributes()...) +} + +type Repo struct { + // Extra attributes to be attached. Can be also added with [Repo.CustomAttrs] method + Attributes []attribute.KeyValue + Level level.SeverityLevel + extraSkipInStack int +} + +func (r Repo) IntoTraceAttributes() []attribute.KeyValue { + attrs := make([]attribute.KeyValue, 5+len(r.Attributes)) + attrs = append(attrs, attr.SourceCodeLocation(1+r.extraSkipInStack)...) + attrs = append(attrs, attr.ServiceLayer(attr.LayerRepository), attr.SeverityLevel(r.Level)) + attrs = append(attrs, r.Attributes...) + return attrs +} + +func (r Repo) CustomAttrs(attrs ...interface{}) Repo { + r.Attributes = append(r.Attributes, attr.CollectAttributes(attrs...)...) + return r +} +func (r *Repo) SkipMoreInCallStack(skip int) { + r.extraSkipInStack += skip +} + +func (r Repo) AsOpts() trace.SpanStartEventOption { + r.extraSkipInStack += 1 + return trace.WithAttributes(r.IntoTraceAttributes()...) +} diff --git a/pkg/console_fmt/fmt.go b/pkg/console_fmt/fmt.go index 29e8059..7bbf702 100644 --- a/pkg/console_fmt/fmt.go +++ b/pkg/console_fmt/fmt.go @@ -19,6 +19,10 @@ const ( ColorBold = "\033[1m" ) +func Bold(txt string) string { + return ColorBold + txt + ColorReset +} + func Red(txt string) string { return ColorRed + txt + ColorReset } diff --git a/pkg/exporters/console_exporter/console_exporter.go b/pkg/exporters/console_exporter/console_exporter.go index e7c228e..927b04d 100644 --- a/pkg/exporters/console_exporter/console_exporter.go +++ b/pkg/exporters/console_exporter/console_exporter.go @@ -3,119 +3,210 @@ package console_exporter import ( "context" "fmt" - "sync" + "slices" + "git.ma-al.com/gora_filip/pkg/attr" "git.ma-al.com/gora_filip/pkg/level" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/trace" ) type TraceFormatter interface { - FormatSpans(spans []trace.ReadOnlySpan, removeFields []attribute.Key, verbosityLevel level.SeverityLevel, addTraceId bool, onlyErrors bool) (string, error) + FormatSpanStart(span trace.ReadOnlySpan, selectedAttrs []attribute.KeyValue, lvl level.SeverityLevel) (string, error) + FormatSpanEnd(span trace.ReadOnlySpan, selectedAttrs []attribute.KeyValue, lvl level.SeverityLevel) (string, error) + FormatEvent(event trace.Event, selectedAttr []attribute.KeyValue, lvl level.SeverityLevel) (string, error) } // Configuration for the exporter. // // Most of options are passed to the formatter. -type ExporterOptions struct { +type ProcessorOptions struct { // Try to parse filters from an environment variable with a name provided by this field. // Result will only by applied to unset options. NOT IMPLEMENTED! FilterFromEnvVar *string // Filter the output based on the [level.SeverityLevel]. - FilterOnLevel *level.SeverityLevel + FilterOnLevel level.SeverityLevel // Fields that should be removed from the output. FilterOutFields []attribute.Key // Print only trace events instead of whole traces. EmitEventsOnly bool - // Add trace id to output - EmitTraceId bool + // Add trace id as an attribute. + AddTraceId bool // Print output only when an error is found - EmitOnlyOnError bool + SkipNonErrors bool // Used only when `EmitEventsOnly` is set to true. - TraceFormatter *TraceFormatter + TraceFormatter *TraceFormatter + SkipEmittingOnSpanStart bool + SkipEmittingOnSpanEnd bool + SkipAttributesOnSpanEnd bool + SkippAttributesOnSpanStart bool } -type Exporter struct { - lvl level.SeverityLevel - removedFields []attribute.Key - addTraceId bool - onlyErrs bool - traceFormatter TraceFormatter - printerMu sync.Mutex - stoppedMu sync.RWMutex - stopped bool +type Processor struct { + lvl level.SeverityLevel + removedFields []attribute.Key + addTraceId bool + onlyErrs bool + onlyEvents bool + traceFormatter TraceFormatter + skipSpanStart bool + skipSpanEnd bool + skipAttrsOnSpanEnd bool + skipAttrsOnSpanStart bool } // NOTE: The configuration might change in future releases -func DefaultConsoleExporter() trace.SpanExporter { - lvl := level.DEBUG - fmt := NewEventsOnlyFormatter() - return NewExporter(ExporterOptions{ - FilterFromEnvVar: nil, - FilterOnLevel: &lvl, - FilterOutFields: []attribute.Key{}, - EmitEventsOnly: false, - EmitTraceId: true, - EmitOnlyOnError: false, - TraceFormatter: &fmt, +func DefaultConsoleExportProcessor() trace.SpanProcessor { + fmt := NewMultilineFormatter() + return NewProcessor(ProcessorOptions{ + FilterFromEnvVar: nil, + FilterOutFields: []attribute.Key{}, + EmitEventsOnly: false, + SkipEmittingOnSpanStart: false, + SkippAttributesOnSpanStart: true, + AddTraceId: false, + TraceFormatter: &fmt, }) } -func NewExporter(opts ExporterOptions) trace.SpanExporter { +func NewProcessor(opts ProcessorOptions) trace.SpanProcessor { var formatter TraceFormatter var lvl level.SeverityLevel if opts.TraceFormatter != nil { formatter = *opts.TraceFormatter } else { - formatter = TraceFormatter(&EventsOnlyFormatter{}) + formatter = TraceFormatter(nil) } - if opts.FilterOnLevel != nil { - lvl = *opts.FilterOnLevel + if opts.FilterOnLevel != 0 { + lvl = opts.FilterOnLevel } else { - lvl = level.TRACE + lvl = level.TRACE + 10 } - return &Exporter{ - traceFormatter: formatter, - removedFields: opts.FilterOutFields, - addTraceId: opts.EmitTraceId, - onlyErrs: opts.EmitOnlyOnError, - lvl: lvl, + return &Processor{ + traceFormatter: formatter, + removedFields: opts.FilterOutFields, + addTraceId: opts.AddTraceId, + onlyEvents: opts.EmitEventsOnly, + onlyErrs: opts.SkipNonErrors, + skipSpanStart: opts.SkipEmittingOnSpanStart, + skipSpanEnd: opts.SkipEmittingOnSpanEnd, + skipAttrsOnSpanEnd: opts.SkipAttributesOnSpanEnd, + lvl: lvl, } } -// Implements [trace.SpanExporter] -func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error { - e.stoppedMu.RLock() - stopped := e.stopped - e.stoppedMu.RUnlock() - if stopped { - return nil +// Implements [trace.SpanProcessor] +func (e *Processor) OnStart(ctx context.Context, span trace.ReadWriteSpan) { + if !e.skipSpanStart && !e.onlyEvents { + attrs := span.Attributes() + filteredAttrs := make([]attribute.KeyValue, 0) + severityLvl := level.TRACE + + if !e.skipAttrsOnSpanStart { + for i := range attrs { + if !slices.Contains(e.removedFields, attrs[i].Key) { + filteredAttrs = append(filteredAttrs, attrs[i]) + } + if attrs[i].Key == attr.SeverityLevelKey { + severityLvl = level.FromString(attrs[i].Value.AsString()) + } + + } + } + if e.addTraceId { + filteredAttrs = append(filteredAttrs, attribute.String("trace_id", span.SpanContext().TraceID().String())) + } + if severityLvl <= e.lvl { + line, err := e.traceFormatter.FormatSpanStart(span, filteredAttrs, severityLvl) + if err != nil { + fmt.Println("FAILED TO FORMAT SPAN START") + } else { + fmt.Printf("%s", line) + } + } } - if len(spans) == 0 { - return nil + return +} + +// Implements [trace.SpanProcessor] +func (e *Processor) OnEnd(span trace.ReadOnlySpan) { + eventsString := "" + spanEndString := "" + + for _, event := range span.Events() { + attrs := event.Attributes + filteredAttrs := make([]attribute.KeyValue, 0) + severityLvl := level.TRACE + for i := range attrs { + if !slices.Contains(e.removedFields, attrs[i].Key) { + filteredAttrs = append(filteredAttrs, attrs[i]) + } + if attrs[i].Key == attr.SeverityLevelKey { + severityLvl = level.FromString(attrs[i].Value.AsString()) + } + } + if e.addTraceId { + filteredAttrs = append(filteredAttrs, attribute.String("trace_id", span.SpanContext().TraceID().String())) + } + if severityLvl <= e.lvl { + eventString, err := e.traceFormatter.FormatEvent(event, filteredAttrs, severityLvl) + if err != nil { + fmt.Println("FAILED TO FORMAT TRACE EVENT") + } else { + eventsString += eventString + } + } } - e.printerMu.Lock() - defer e.printerMu.Unlock() - printLine, err := e.traceFormatter.FormatSpans(spans, e.removedFields, e.lvl, e.addTraceId, e.onlyErrs) - if err != nil { - fmt.Printf("FAILED TO FORMAT A TRACE WITH ERR: %#v\n", err) - } - if len(printLine) > 0 { - fmt.Println(printLine) + if !e.skipSpanEnd && !e.onlyEvents { + attrs := span.Attributes() + filteredAttrs := make([]attribute.KeyValue, len(attrs)) + severityLvl := level.TRACE + + if !e.skipAttrsOnSpanEnd { + for i := range attrs { + if !slices.Contains(e.removedFields, attrs[i].Key) { + filteredAttrs = append(filteredAttrs, attrs[i]) + } + if attrs[i].Key == attr.SeverityLevelKey { + severityLvl = level.FromString(attrs[i].Value.AsString()) + + } + + } + } + if e.addTraceId { + filteredAttrs = append(filteredAttrs, attribute.String("trace_id", span.SpanContext().TraceID().String())) + } + if severityLvl <= e.lvl { + spanString, err := e.traceFormatter.FormatSpanEnd(span, filteredAttrs, severityLvl) + if err != nil { + fmt.Println("FAILED TO FORMAT SPAN END") + } else { + spanEndString += spanString + } + } + } + if e.skipSpanStart { + fmt.Printf("%s", spanEndString+eventsString) + } else { + fmt.Printf("%s", eventsString+spanEndString) + } + + return +} + +// Implements [trace.SpanProcessor] +func (e *Processor) ForceFlush(ctx context.Context) error { return nil } // Implements [trace.SpanExporter] -func (e *Exporter) Shutdown(ctx context.Context) error { - e.stoppedMu.Lock() - e.stopped = true - e.stoppedMu.Unlock() - +func (e *Processor) Shutdown(ctx context.Context) error { select { case <-ctx.Done(): return ctx.Err() diff --git a/pkg/exporters/console_exporter/event_only_formatter.go b/pkg/exporters/console_exporter/event_only_formatter.go deleted file mode 100644 index 34827d4..0000000 --- a/pkg/exporters/console_exporter/event_only_formatter.go +++ /dev/null @@ -1,97 +0,0 @@ -package console_exporter - -import ( - "fmt" - "slices" - - "git.ma-al.com/gora_filip/pkg/attr" - "git.ma-al.com/gora_filip/pkg/code_location" - "git.ma-al.com/gora_filip/pkg/console_fmt" - "git.ma-al.com/gora_filip/pkg/level" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/sdk/trace" - "go.opentelemetry.io/otel/sdk/trace/tracetest" - "go.opentelemetry.io/otel/semconv/v1.25.0" -) - -func NewEventsOnlyFormatter() TraceFormatter { - return &EventsOnlyFormatter{} -} - -// A formatter that will print only events using a multiline format with colors. -// It uses attributes from the [attr] and [semconv] packages. -type EventsOnlyFormatter struct{} - -func (f *EventsOnlyFormatter) FormatSpans(spans []trace.ReadOnlySpan, removeFields []attribute.Key, verbosityLevel level.SeverityLevel, addTraceId bool, onlyOnError bool) (string, error) { - stubs := tracetest.SpanStubsFromReadOnlySpans(spans) - - var formattedSpanString string - - for i := range stubs { - stub := &stubs[i] - for j := range stub.Events { - var attributes map[attribute.Key]string = make(map[attribute.Key]string, 0) - var msg string - var lvl level.SeverityLevel - var isErr bool - var location code_location.CodeLocation - - for _, attrKV := range stub.Attributes { - if _, exists := attributes[attrKV.Key]; !exists { - attributes[attrKV.Key] = attrKV.Value.AsString() - } - } - - for _, attrKV := range stub.Events[j].Attributes { - switch attrKV.Key { - case attr.LogMessageLongKey: - msg = attrKV.Value.AsString() - case attr.LogMessageShortKey: - if len(msg) == 0 { - msg = attrKV.Value.AsString() - } - case attr.SeverityLevelKey: - lvl = level.FromString(attrKV.Value.AsString()) - case semconv.CodeFilepathKey: - location.FilePath = attrKV.Value.AsString() - case semconv.CodeLineNumberKey: - location.LineNumber = int(attrKV.Value.AsInt64()) - case semconv.CodeColumnKey: - location.ColumnNumber = int(attrKV.Value.AsInt64()) - case semconv.ExceptionMessageKey: - attributes[attrKV.Key] = attrKV.Value.AsString() - isErr = true - default: - if !slices.Contains(removeFields, attrKV.Key) && len(attrKV.Key) > 0 { - attributes[attrKV.Key] = attrKV.Value.AsString() - } - } - } - if len(msg) == 0 { - msg = stub.Name - } - if addTraceId { - attributes[attribute.Key("trace_id")] = stub.SpanContext.TraceID().String() - } - if len(location.FilePath) > 0 { - attributes["code.location"] = fmt.Sprintf("%s:%d:%d", location.FilePath, location.LineNumber, location.ColumnNumber) - } - - if !(!isErr && onlyOnError) && lvl <= verbosityLevel { - attrs := "" - for k, v := range attributes { - attrs += fmt.Sprintf("\t%s%s%s = %s\n", console_fmt.ColorBold, k, console_fmt.ColorReset, v) - } - - formattedSpanString += fmt.Sprintf( - "%s %s\n%s", - fmt.Sprintf("%s[%s]", console_fmt.SeverityLevelToColor(lvl), lvl.String()), - fmt.Sprintf("%s%s", msg, console_fmt.ColorReset), - attrs, - ) - } - } - } - - return formattedSpanString, nil -} diff --git a/pkg/exporters/console_exporter/multiline_formatter.go b/pkg/exporters/console_exporter/multiline_formatter.go new file mode 100644 index 0000000..989ab8a --- /dev/null +++ b/pkg/exporters/console_exporter/multiline_formatter.go @@ -0,0 +1,68 @@ +package console_exporter + +import ( + "fmt" + + "git.ma-al.com/gora_filip/pkg/console_fmt" + "git.ma-al.com/gora_filip/pkg/level" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/sdk/trace" +) + +func NewMultilineFormatter() TraceFormatter { + return &MultilineFormatter{} +} + +// A formatter that will print only events using a multiline format with colors. +// It uses attributes from the [attr] and [semconv] packages. +type MultilineFormatter struct{} + +func (f *MultilineFormatter) FormatSpanStart(span trace.ReadOnlySpan, selectedAttrs []attribute.KeyValue, lvl level.SeverityLevel) (string, error) { + attrs := "" + for _, kv := range selectedAttrs { + if len(kv.Key) > 0 { + attrs += fmt.Sprintf("\t%s = %s\n", string(kv.Key), kv.Value.AsString()) + } + } + + formattedSpanString := fmt.Sprintf( + "%s\n%s", + console_fmt.Bold(console_fmt.SeverityLevelToColor(lvl)+fmt.Sprintf("[%s][SpanStart] ", lvl.String())+span.Name()), + attrs, + ) + + return formattedSpanString, nil +} +func (f *MultilineFormatter) FormatSpanEnd(span trace.ReadOnlySpan, selectedAttrs []attribute.KeyValue, lvl level.SeverityLevel) (string, error) { + attrs := "" + for _, kv := range selectedAttrs { + if len(kv.Key) > 0 { + attrs += fmt.Sprintf("\t%s = %s\n", string(kv.Key), kv.Value.AsString()) + } + } + + formattedSpanString := fmt.Sprintf( + "%s\n%s", + console_fmt.Bold(console_fmt.SeverityLevelToColor(lvl)+fmt.Sprintf("[%s][SpanEnd] ", lvl.String())+span.Name()), + attrs, + ) + + return formattedSpanString, nil + +} +func (f *MultilineFormatter) FormatEvent(event trace.Event, selectedAttrs []attribute.KeyValue, lvl level.SeverityLevel) (string, error) { + attrs := "" + for _, kv := range selectedAttrs { + if len(kv.Key) > 0 { + attrs += fmt.Sprintf("\t%s = %s\n", string(kv.Key), kv.Value.AsString()) + } + } + + formattedSpanString := fmt.Sprintf( + "%s\n%s", + console_fmt.Bold(console_fmt.SeverityLevelToColor(lvl)+fmt.Sprintf("[%s][Event] ", lvl.String())+event.Name), + attrs, + ) + + return formattedSpanString, nil +} diff --git a/pkg/exporters/exporters.go b/pkg/exporters/exporters.go index 6fc138d..c337fa0 100644 --- a/pkg/exporters/exporters.go +++ b/pkg/exporters/exporters.go @@ -2,20 +2,40 @@ package exporters import ( "context" - "time" - "git.ma-al.com/gora_filip/pkg/exporters/console_exporter" gelf_exporter "git.ma-al.com/gora_filip/pkg/exporters/gelf_exporter" otlphttp_exporter "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) -func NewWithConfig(exporter sdktrace.SpanExporter) ExporterWithConfig { +// Private type preventing implementation of TraceProcessor by external packages. +type traceProviderOpt sdktrace.TracerProviderOption + +type TraceExporter interface { + IntoTraceProviderOption() traceProviderOpt +} + +func NewFromSpanExporter(exporter sdktrace.SpanExporter) ExporterWithConfig { return ExporterWithConfig{ exporter: exporter, } } +// Sneaky wrapper that makes it so that the TraceExporter can be created from SpanProcessor. +type proc struct { + sdktrace.SpanProcessor +} + +func (p proc) IntoTraceProviderOption() traceProviderOpt { + return sdktrace.WithSpanProcessor(p) +} + +func NewFromSpanProcessor(processor sdktrace.SpanProcessor) TraceExporter { + return TraceExporter(proc{ + SpanProcessor: processor, + }) +} + // Combined exporter with batch processor config type ExporterWithConfig struct { exporter sdktrace.SpanExporter @@ -27,32 +47,30 @@ func (ecfg ExporterWithConfig) Add(opt sdktrace.BatchSpanProcessorOption) Export return ecfg } -func (ecfg ExporterWithConfig) IntoTraceProviderOption() sdktrace.TracerProviderOption { +func (ecfg ExporterWithConfig) IntoTraceProviderOption() traceProviderOpt { return sdktrace.WithBatcher(ecfg.exporter, ecfg.config...) } // An exporter printing to console with very small delay -func DevConsoleExporter(opts ...console_exporter.ExporterOptions) ExporterWithConfig { - batchTimeout := (time.Millisecond * 250) - exportTimeout := (time.Millisecond * 250) - var exporter ExporterWithConfig +func DevConsoleExporter(opts ...console_exporter.ProcessorOptions) TraceExporter { + var exporter TraceExporter if len(opts) > 0 { - exporter = NewWithConfig(console_exporter.NewExporter(opts[0])) + exporter = NewFromSpanProcessor(console_exporter.NewProcessor(opts[0])) } else { - exporter = NewWithConfig(console_exporter.DefaultConsoleExporter()) + exporter = NewFromSpanProcessor(console_exporter.DefaultConsoleExportProcessor()) } - return exporter.Add(sdktrace.WithBatchTimeout(batchTimeout)).Add(sdktrace.WithExportTimeout(exportTimeout)) + return TraceExporter(exporter) } // Default exporter to Graylog. func GelfExporter(opts ...gelf_exporter.Option) (ExporterWithConfig, error) { gelfExp, err := gelf_exporter.New(opts...) - return NewWithConfig(gelfExp), err + return NewFromSpanExporter(gelfExp), err } // Exporter for traces over HTTP. Can be used with Jaeger. // See documentation of [otlhttp_exporter] for details. func OtlpHTTPExporter(opts ...otlphttp_exporter.Option) (ExporterWithConfig, error) { otlpExp, err := otlphttp_exporter.New(context.Background(), opts...) - return NewWithConfig(otlpExp), err + return NewFromSpanExporter(otlpExp), err } diff --git a/pkg/exporters/gelf_exporter/trace.go b/pkg/exporters/gelf_exporter/trace.go index 1b874b2..1c33823 100644 --- a/pkg/exporters/gelf_exporter/trace.go +++ b/pkg/exporters/gelf_exporter/trace.go @@ -78,7 +78,7 @@ func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) ExtraFields: attributes, } for _, attrKV := range event.Attributes { - if attrKV.Key == "long_message" { + if attrKV.Key == attr.LogMessageLongKey { gelf.LongMessage = attrKV.Value.AsString() continue } diff --git a/pkg/fiber_tracing/fiber_tracing.go b/pkg/fiber_tracing/fiber_tracing.go index 177a2d3..96784fc 100644 --- a/pkg/fiber_tracing/fiber_tracing.go +++ b/pkg/fiber_tracing/fiber_tracing.go @@ -25,7 +25,7 @@ type Config struct { Version string // Name of an organization providing the service ServiceProvider string - Exporters []exporters.ExporterWithConfig + Exporters []exporters.TraceExporter } func newResource(config Config) *resource.Resource { @@ -38,6 +38,16 @@ func newResource(config Config) *resource.Resource { return r } +// NOTE: You can use [trace.WithAttributes] as a parameter to opts argument +func Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { + return fiberOpentelemetry.Tracer.Start(ctx, spanName, opts...) +} + +// NOTE: You can use [trace.WithAttributes] as a parameter to opts argument +func FStart(c *fiber.Ctx, opts ...trace.SpanStartOption) (context.Context, trace.Span) { + return fiberOpentelemetry.Tracer.Start(c.UserContext(), c.Method()+" "+c.Path(), opts...) +} + func NewMiddleware(config Config) func(*fiber.Ctx) error { var tracerProviders []trc.TracerProviderOption diff --git a/pkg/level/level.go b/pkg/level/level.go index ab31dab..dc9d532 100644 --- a/pkg/level/level.go +++ b/pkg/level/level.go @@ -8,10 +8,13 @@ import ( type SeverityLevel uint8 const ( + // A magical zero value. + // WARN: DO NOT USE IN LOGS OR BASICALLY EVER + unset SeverityLevel = iota // This event requires an immediate action. If you suspect that occurence of an event may signal that the // data will get lost, corrupted, or that the application will change its behaviour following the event in // an undesired way, select the ALERT level. - ALERT SeverityLevel = iota + ALERT // A critical error has occured. Critical errors are such which can be tough to fix or made the users // experience significantly worse but unlike errors that trigger ALERT they can be fixed at any moment. CRIT @@ -50,6 +53,8 @@ func (l SeverityLevel) String() string { return "INFO" case DEBUG: return "DEBUG" + case TRACE: + return "TRACE" default: return "CRIT" } @@ -69,6 +74,8 @@ func FromString(level string) SeverityLevel { return INFO case "DEBUG": return DEBUG + case "TRACE": + return TRACE default: return CRIT }