get.porter.sh/porter@v1.3.0/pkg/tracing/tracing.go (about)

     1  package tracing
     2  
     3  import (
     4  	"context"
     5  
     6  	"go.opentelemetry.io/otel/attribute"
     7  	"go.opentelemetry.io/otel/trace"
     8  	"go.opentelemetry.io/otel/trace/noop"
     9  	"go.uber.org/zap"
    10  	"go.uber.org/zap/zapcore"
    11  )
    12  
    13  // custom type for looking up values from context.Context
    14  type contextKey string
    15  
    16  // key for retrieving the TraceLogger stored on the context
    17  const contextKeyTraceLogger = contextKey("porter.traceLogger")
    18  
    19  // stores data in context.Context to recreate a TraceLogger
    20  type traceLoggerContext struct {
    21  	logger *zap.Logger
    22  	tracer trace.Tracer
    23  }
    24  
    25  // LoggerFromContext retrieves a logger from the specified context.
    26  // When the context is missing a logger/tracer, no-op implementations are provided.
    27  func LoggerFromContext(ctx context.Context) TraceLogger {
    28  	span := trace.SpanFromContext(ctx)
    29  
    30  	var logger *zap.Logger
    31  	var tracer trace.Tracer
    32  	if tl, ok := ctx.Value(contextKeyTraceLogger).(traceLoggerContext); ok {
    33  		logger = tl.logger
    34  		tracer = tl.tracer
    35  	} else {
    36  		// default to no-op
    37  		logger = zap.NewNop()
    38  		tracer = noop.NewTracerProvider().Tracer("noop")
    39  	}
    40  
    41  	return newTraceLogger(ctx, span, logger, NewTracer(tracer, nil))
    42  }
    43  
    44  // StartSpan retrieves a logger from the current context and starts a new span
    45  // named after the current function.
    46  func StartSpan(ctx context.Context, attrs ...attribute.KeyValue) (context.Context, TraceLogger) {
    47  	log := LoggerFromContext(ctx)
    48  	return log.StartSpan(attrs...)
    49  }
    50  
    51  // StartSpanWithName retrieves a logger from the current context and starts a span with
    52  // the specified name.
    53  func StartSpanWithName(ctx context.Context, op string, attrs ...attribute.KeyValue) (context.Context, TraceLogger) {
    54  	log := LoggerFromContext(ctx)
    55  	return log.StartSpanWithName(op, attrs...)
    56  }
    57  
    58  func convertAttributesToFields(attrs []attribute.KeyValue) []zap.Field {
    59  	fields := make([]zap.Field, len(attrs))
    60  	for i, attr := range attrs {
    61  		fields[i] = convertAttributeToField(attr)
    62  	}
    63  	return fields
    64  }
    65  
    66  func convertAttributeToField(attr attribute.KeyValue) zapcore.Field {
    67  	key := string(attr.Key)
    68  
    69  	switch attr.Value.Type() {
    70  
    71  	case attribute.BOOL:
    72  		return zap.Bool(key, attr.Value.AsBool())
    73  	case attribute.BOOLSLICE:
    74  		return zap.Bools(key, attr.Value.AsBoolSlice())
    75  	case attribute.FLOAT64:
    76  		return zap.Float64(key, attr.Value.AsFloat64())
    77  	case attribute.FLOAT64SLICE:
    78  		return zap.Float64s(key, attr.Value.AsFloat64Slice())
    79  	case attribute.INT64:
    80  		return zap.Int64(key, attr.Value.AsInt64())
    81  	case attribute.INT64SLICE:
    82  		return zap.Int64s(key, attr.Value.AsInt64Slice())
    83  	case attribute.STRING:
    84  		return zap.String(key, attr.Value.AsString())
    85  	case attribute.STRINGSLICE:
    86  		return zap.Strings(key, attr.Value.AsStringSlice())
    87  	default:
    88  		// Give up and do our best
    89  		b, _ := attr.Value.MarshalJSON()
    90  		return zap.String(key, string(b))
    91  	}
    92  }