From 0df2cf8085c54c72beaa21d5540cb1118d2883fb Mon Sep 17 00:00:00 2001 From: Bhautik Pipaliya <56270044+bhautikpip@users.noreply.github.com> Date: Fri, 12 Nov 2021 11:44:11 -0800 Subject: [PATCH] Go lambda instrumentation enhancements (#1413) * added failure scenario when getting container fails * fix test case failure * add changelog * fix ecs resource detector bug * fix struct name as per golint suggestion * minor changes * added NewResourceDetector func and interface assertions * fix golint failure * minor changes to address review comments * lambda go instrumentation enhancements * minor changes to address review comments * update go.mod * Revert "update go.mod" This reverts commit 2696b3508575282848c4c36de8939ce993f0de40. * remove depending on SDK package * renaming the public API for xrayconfig package * fix README review suggestions * remove logger and minor changes * Update instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig/xrayconfig_test.go Co-authored-by: Anthony Mirabella Co-authored-by: Tyler Yahn --- .../otellambda/xrayconfig/README.md | 14 ++-- .../otellambda/xrayconfig/xrayconfig.go | 67 +++++-------------- .../otellambda/xrayconfig/xrayconfig_test.go | 6 +- 3 files changed, 29 insertions(+), 58 deletions(-) diff --git a/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig/README.md b/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig/README.md index 83b06212cc7..18ae68d3322 100644 --- a/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig/README.md +++ b/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig/README.md @@ -34,7 +34,7 @@ func HandleRequest(ctx context.Context, name MyEvent) (string, error) { } func main() { - lambda.Start(otellambda.WrapHandlerFunction(HandleRequest)) + lambda.Start(otellambda.InstrumentHandler(HandleRequest)) } ``` @@ -44,19 +44,19 @@ Now configure the instrumentation with the provided options to export traces to // Add import import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig" -// add options to WrapHandlerFunction call +// add options to InstrumentHandler call func main() { - lambda.Start(otellambda.WrapHandlerFunction(HandleRequest, xrayconfig.AllRecommendedOptions()...)) + lambda.Start(otellambda.InstrumentHandler(HandleRequest, xrayconfig.WithRecommendedOptions()...)) } ``` ## Recommended AWS Lambda Instrumentation Options | Instrumentation Option | Recommended Value | Exported As | | --- | --- | --- | -| `WithTracerProvider` | An `sdktrace.TracerProvider` configured to export in batches to an OTel Collector running locally in Lambda | Not individually exported. Can only be used via `AllRecommendedOptions()` -| `WithFlusher` | An `otellambda.Flusher` which yields before calling ForceFlush on the configured `sdktrace.TracerProvider`. Yielding mitigates data delays caused by asynchronous nature of batching TracerProvider when in Lambda | Not individually exported. Can only be used via `AllRecommendedOptions()` -| `WithEventToCarrier` | Function which reads X-Ray TraceID from Lambda environment and inserts it into a `propagtation.TextMapCarrier` | Individually exported as `EventToCarrier()`, also included in `AllRecommendedOptions()` -| `WithPropagator` | An `xray.propagator` | Individually exported as `EventToCarrier()`, also included in `AllRecommendedOptions()` +| `WithTracerProvider` | An `sdktrace.TracerProvider` configured to export in batches to an OTel Collector running locally in Lambda | Not individually exported. Can only be used via `WithRecommendedOptions()` +| `WithFlusher` | An `otellambda.Flusher` which yields before calling ForceFlush on the configured `sdktrace.TracerProvider`. Yielding mitigates data delays caused by asynchronous nature of batching TracerProvider when in Lambda | Not individually exported. Can only be used via `WithRecommendedOptions()` +| `WithEventToCarrier` | Function which reads X-Ray TraceID from Lambda environment and inserts it into a `propagtation.TextMapCarrier` | Individually exported as `WithEventToCarrier()`, also included in `WithRecommendedOptions()` +| `WithPropagator` | An `xray.propagator` | Individually exported as `WithPropagator()`, also included in `WithRecommendedOptions()` ## Useful links diff --git a/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig/xrayconfig.go b/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig/xrayconfig.go index ad80eacfc64..0ed24977b9e 100644 --- a/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig/xrayconfig.go +++ b/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig/xrayconfig.go @@ -16,9 +16,7 @@ package xrayconfig import ( "context" - "log" "os" - "runtime" lambdadetector "go.opentelemetry.io/contrib/detectors/aws/lambda" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" @@ -28,79 +26,48 @@ import ( sdktrace "go.opentelemetry.io/otel/sdk/trace" ) -var errorLogger = log.New(log.Writer(), "OTel Lambda XRay Configuration Error: ", 0) - func xrayEventToCarrier([]byte) propagation.TextMapCarrier { xrayTraceID := os.Getenv("_X_AMZN_TRACE_ID") return propagation.HeaderCarrier{"X-Amzn-Trace-Id": []string{xrayTraceID}} } -type asyncSafeFlusher struct { - tp *sdktrace.TracerProvider -} - -func (f asyncSafeFlusher) ForceFlush(ctx context.Context) error { - // yield processor to attempt to ensure all spans have - // been consumed and are ready to be flushed - // - see https://github.com/open-telemetry/opentelemetry-go/issues/2080 - // to be removed upon resolution of above issue - runtime.Gosched() - - return f.tp.ForceFlush(ctx) -} - -// tracerProviderAndFlusher returns a list of otellambda.Option(s) to -// enable using a TracerProvider configured for AWS XRay via a collector -// and an otellambda.Flusher to flush this TracerProvider. -// tracerProviderAndFlusher is not exported because it should not be used -// without the provided EventToCarrier function and XRay Propagator -func tracerProviderAndFlusher() ([]otellambda.Option, error) { - ctx := context.Background() - - // Do not need transport security in Lambda because collector - // runs locally in Lambda execution environment +// NewTracerProvider returns a TracerProvider configured with an exporter, +// ID generator, and lambda resource detector to send trace data to AWS X-Ray +// via a Collector instance listening on localhost +func NewTracerProvider(ctx context.Context) (*sdktrace.TracerProvider, error) { exp, err := otlptracegrpc.New(ctx, otlptracegrpc.WithInsecure()) if err != nil { - return []otellambda.Option{}, err + return nil, err } detector := lambdadetector.NewResourceDetector() - res, err := detector.Detect(ctx) + resource, err := detector.Detect(ctx) if err != nil { - return []otellambda.Option{}, err + return nil, err } - tp := sdktrace.NewTracerProvider( + return sdktrace.NewTracerProvider( sdktrace.WithBatcher(exp), sdktrace.WithIDGenerator(xray.NewIDGenerator()), - sdktrace.WithResource(res), - ) - - return []otellambda.Option{otellambda.WithTracerProvider(tp), otellambda.WithFlusher(asyncSafeFlusher{tp: tp})}, nil + sdktrace.WithResource(resource), + ), nil } -// EventToCarrier returns an otellambda.Option to enable +// WithEventToCarrier returns an otellambda.Option to enable // an otellambda.EventToCarrier function which reads the XRay trace // information from the environment and returns this information in // a propagation.HeaderCarrier -func EventToCarrier() otellambda.Option { +func WithEventToCarrier() otellambda.Option { return otellambda.WithEventToCarrier(xrayEventToCarrier) } -// Propagator returns an otellambda.Option to enable the xray.Propagator -func Propagator() otellambda.Option { - +// WithPropagator returns an otellambda.Option to enable the xray.Propagator +func WithPropagator() otellambda.Option { return otellambda.WithPropagator(xray.Propagator{}) } -// AllRecommendedOptions returns a list of all otellambda.Option(s) +// WithRecommendedOptions returns a list of all otellambda.Option(s) // recommended for the otellambda package when using AWS XRay -func AllRecommendedOptions() []otellambda.Option { - options, err := tracerProviderAndFlusher() - if err != nil { - // should we fail to create the TracerProvider, do not alter otellambda's default configuration - errorLogger.Println("failed to create recommended configuration: ", err) - return []otellambda.Option{} - } - return append(options, []otellambda.Option{EventToCarrier(), Propagator()}...) +func WithRecommendedOptions(tp *sdktrace.TracerProvider) []otellambda.Option { + return []otellambda.Option{WithEventToCarrier(), WithPropagator(), otellambda.WithTracerProvider(tp), otellambda.WithFlusher(tp)} } diff --git a/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig/xrayconfig_test.go b/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig/xrayconfig_test.go index 1a5d4e446bf..a0a3ea74c77 100644 --- a/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig/xrayconfig_test.go +++ b/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig/xrayconfig_test.go @@ -154,6 +154,10 @@ func assertSpanEqualsIgnoreTimeAndSpanID(t *testing.T, expected *v1trace.Resourc func TestWrapEndToEnd(t *testing.T) { setEnvVars() + ctx := context.Background() + tp, err := NewTracerProvider(ctx) + assert.NoError(t, err) + customerHandler := func() (string, error) { return "hello world", nil } @@ -163,7 +167,7 @@ func TestWrapEndToEnd(t *testing.T) { }() <-time.After(5 * time.Millisecond) - wrapped := otellambda.InstrumentHandler(customerHandler, AllRecommendedOptions()...) + wrapped := otellambda.InstrumentHandler(customerHandler, WithRecommendedOptions(tp)...) wrappedCallable := reflect.ValueOf(wrapped) resp := wrappedCallable.Call([]reflect.Value{reflect.ValueOf(mockContext)}) assert.Len(t, resp, 2)