From dcc01deec2b6f27a5af3e5e3ecbb7f93f5fb0f8a Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Thu, 4 Feb 2021 16:21:40 -0800 Subject: [PATCH 01/17] added failure scenario when getting container fails --- detectors/aws/ecs/ecs.go | 7 ++++++- detectors/aws/ecs/ecs_test.go | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/detectors/aws/ecs/ecs.go b/detectors/aws/ecs/ecs.go index dcc11955b91..82eb201f142 100644 --- a/detectors/aws/ecs/ecs.go +++ b/detectors/aws/ecs/ecs.go @@ -37,6 +37,7 @@ const ( var ( empty = resource.Empty() errCannotReadContainerID = errors.New("failed to read container ID from cGroupFile") + errCannotReadContainerName = errors.New("failed to read hostname") errCannotReadCGroupFile = errors.New("ECS resource detector failed to read cGroupFile") errNotOnECS = errors.New("process is not on ECS, cannot detect environment variables from ECS") ) @@ -102,5 +103,9 @@ func (ecsUtils ecsDetectorUtils) getContainerID() (string, error) { // returns host name reported by the kernel func (ecsUtils ecsDetectorUtils) getContainerName() (string, error) { - return os.Hostname() + hostName, err := os.Hostname() + if err != nil { + return "", errCannotReadContainerName + } + return hostName, nil } diff --git a/detectors/aws/ecs/ecs_test.go b/detectors/aws/ecs/ecs_test.go index 85cbb131288..7d667c35f3b 100644 --- a/detectors/aws/ecs/ecs_test.go +++ b/detectors/aws/ecs/ecs_test.go @@ -81,6 +81,23 @@ func TestDetectCannotReadContainerID(t *testing.T) { assert.Equal(t, 0, len(resource.Attributes())) } +//returns empty resource when detector cannot read container Name +func TestDetectCannotReadContainerName(t *testing.T) { + os.Clearenv() + os.Setenv(metadataV3EnvVar, "3") + os.Setenv(metadataV4EnvVar, "4") + detectorUtils := new(MockDetectorUtils) + + detectorUtils.On("getContainerName").Return("", errCannotReadContainerName) + detectorUtils.On("getContainerID").Return("0123456789A", nil) + + detector := ResourceDetector{detectorUtils} + resource, err := detector.Detect(context.Background()) + + assert.Equal(t, errCannotReadContainerName, err) + assert.Equal(t, 0, len(resource.Attributes())) +} + //returns empty resource when process is not running ECS func TestReturnsIfNoEnvVars(t *testing.T) { os.Clearenv() From 1dd54d977a8dce0027f0ff4a79afa1aa9c49eaaf Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Thu, 4 Feb 2021 16:57:07 -0800 Subject: [PATCH 02/17] fix test case failure --- detectors/aws/ecs/ecs.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/detectors/aws/ecs/ecs.go b/detectors/aws/ecs/ecs.go index 82eb201f142..1bf477345d1 100644 --- a/detectors/aws/ecs/ecs.go +++ b/detectors/aws/ecs/ecs.go @@ -35,11 +35,11 @@ const ( ) var ( - empty = resource.Empty() - errCannotReadContainerID = errors.New("failed to read container ID from cGroupFile") - errCannotReadContainerName = errors.New("failed to read hostname") - errCannotReadCGroupFile = errors.New("ECS resource detector failed to read cGroupFile") - errNotOnECS = errors.New("process is not on ECS, cannot detect environment variables from ECS") + empty = resource.Empty() + errCannotReadContainerID = errors.New("failed to read container ID from cGroupFile") + errCannotReadContainerName = errors.New("failed to read hostname") + errCannotReadCGroupFile = errors.New("ECS resource detector failed to read cGroupFile") + errNotOnECS = errors.New("process is not on ECS, cannot detect environment variables from ECS") ) // Create interface for methods needing to be mocked From 03f6fb4f99601c371279378a4c005dc4bf78867e Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Fri, 5 Feb 2021 10:45:07 -0800 Subject: [PATCH 03/17] add changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91b685de7d9..39bba122bb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +### Fixed + +- Added failure message for AWS ECS resource detector for better debugging (#568) + ## [0.16.0] - 2021-01-13 ### Fixed From e1ff7d0404815b18be13c39521405cc7d731bfe1 Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Sat, 6 Feb 2021 17:04:11 -0800 Subject: [PATCH 04/17] fix ecs resource detector bug --- detectors/aws/ecs/ecs.go | 18 ++++++------------ detectors/aws/ecs/ecs_test.go | 28 ++++++++++++++-------------- 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/detectors/aws/ecs/ecs.go b/detectors/aws/ecs/ecs.go index 1bf477345d1..02c2718d78a 100644 --- a/detectors/aws/ecs/ecs.go +++ b/detectors/aws/ecs/ecs.go @@ -49,19 +49,13 @@ type detectorUtils interface { } // struct implements detectorUtils interface -type ecsDetectorUtils struct{} +type EcsDetectorUtils struct{} // resource detector collects resource information from Elastic Container Service environment type ResourceDetector struct { - utils detectorUtils + Utils detectorUtils } -// compile time assertion that ecsDetectorUtils implements detectorUtils interface -var _ detectorUtils = (*ecsDetectorUtils)(nil) - -// compile time assertion that resource detector implements the resource.Detector interface. -var _ resource.Detector = (*ResourceDetector)(nil) - // Detect finds associated resources when running on ECS environment. func (detector *ResourceDetector) Detect(ctx context.Context) (*resource.Resource, error) { metadataURIV3 := os.Getenv(metadataV3EnvVar) @@ -70,11 +64,11 @@ func (detector *ResourceDetector) Detect(ctx context.Context) (*resource.Resourc if len(metadataURIV3) == 0 && len(metadataURIV4) == 0 { return empty, errNotOnECS } - hostName, err := detector.utils.getContainerName() + hostName, err := detector.Utils.getContainerName() if err != nil { return empty, err } - containerID, err := detector.utils.getContainerID() + containerID, err := detector.Utils.getContainerID() if err != nil { return empty, err } @@ -87,7 +81,7 @@ func (detector *ResourceDetector) Detect(ctx context.Context) (*resource.Resourc } // returns docker container ID from default c group path -func (ecsUtils ecsDetectorUtils) getContainerID() (string, error) { +func (ecsUtils EcsDetectorUtils) getContainerID() (string, error) { fileData, err := ioutil.ReadFile(defaultCgroupPath) if err != nil { return "", errCannotReadCGroupFile @@ -102,7 +96,7 @@ func (ecsUtils ecsDetectorUtils) getContainerID() (string, error) { } // returns host name reported by the kernel -func (ecsUtils ecsDetectorUtils) getContainerName() (string, error) { +func (ecsUtils EcsDetectorUtils) getContainerName() (string, error) { hostName, err := os.Hostname() if err != nil { return "", errCannotReadContainerName diff --git a/detectors/aws/ecs/ecs_test.go b/detectors/aws/ecs/ecs_test.go index 7d667c35f3b..045648ea035 100644 --- a/detectors/aws/ecs/ecs_test.go +++ b/detectors/aws/ecs/ecs_test.go @@ -45,8 +45,8 @@ func (detectorUtils *MockDetectorUtils) getContainerName() (string, error) { //succesfully return resource when process is running on Amazon ECS environment func TestDetect(t *testing.T) { os.Clearenv() - os.Setenv(metadataV3EnvVar, "3") - os.Setenv(metadataV4EnvVar, "4") + _ = os.Setenv(metadataV3EnvVar, "3") + _ = os.Setenv(metadataV4EnvVar, "4") detectorUtils := new(MockDetectorUtils) @@ -59,51 +59,51 @@ func TestDetect(t *testing.T) { } expectedResource := resource.NewWithAttributes(labels...) detector := ResourceDetector{detectorUtils} - resource, _ := detector.Detect(context.Background()) + res, _ := detector.Detect(context.Background()) - assert.Equal(t, resource, expectedResource, "Resource returned is incorrect") + assert.Equal(t, res, expectedResource, "Resource returned is incorrect") } //returns empty resource when detector cannot read container ID func TestDetectCannotReadContainerID(t *testing.T) { os.Clearenv() - os.Setenv(metadataV3EnvVar, "3") - os.Setenv(metadataV4EnvVar, "4") + _ = os.Setenv(metadataV3EnvVar, "3") + _ = os.Setenv(metadataV4EnvVar, "4") detectorUtils := new(MockDetectorUtils) detectorUtils.On("getContainerName").Return("container-Name", nil) detectorUtils.On("getContainerID").Return("", errCannotReadContainerID) detector := ResourceDetector{detectorUtils} - resource, err := detector.Detect(context.Background()) + res, err := detector.Detect(context.Background()) assert.Equal(t, errCannotReadContainerID, err) - assert.Equal(t, 0, len(resource.Attributes())) + assert.Equal(t, 0, len(res.Attributes())) } //returns empty resource when detector cannot read container Name func TestDetectCannotReadContainerName(t *testing.T) { os.Clearenv() - os.Setenv(metadataV3EnvVar, "3") - os.Setenv(metadataV4EnvVar, "4") + _ = os.Setenv(metadataV3EnvVar, "3") + _ = os.Setenv(metadataV4EnvVar, "4") detectorUtils := new(MockDetectorUtils) detectorUtils.On("getContainerName").Return("", errCannotReadContainerName) detectorUtils.On("getContainerID").Return("0123456789A", nil) detector := ResourceDetector{detectorUtils} - resource, err := detector.Detect(context.Background()) + res, err := detector.Detect(context.Background()) assert.Equal(t, errCannotReadContainerName, err) - assert.Equal(t, 0, len(resource.Attributes())) + assert.Equal(t, 0, len(res.Attributes())) } //returns empty resource when process is not running ECS func TestReturnsIfNoEnvVars(t *testing.T) { os.Clearenv() detector := ResourceDetector{} - resource, err := detector.Detect(context.Background()) + res, err := detector.Detect(context.Background()) assert.Equal(t, errNotOnECS, err) - assert.Equal(t, 0, len(resource.Attributes())) + assert.Equal(t, 0, len(res.Attributes())) } From e12a4b185593413d0d459ffcd5507b20362c4819 Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Sat, 6 Feb 2021 17:17:55 -0800 Subject: [PATCH 05/17] fix struct name as per golint suggestion --- detectors/aws/ecs/ecs.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/detectors/aws/ecs/ecs.go b/detectors/aws/ecs/ecs.go index 02c2718d78a..a319454e72b 100644 --- a/detectors/aws/ecs/ecs.go +++ b/detectors/aws/ecs/ecs.go @@ -43,17 +43,17 @@ var ( ) // Create interface for methods needing to be mocked -type detectorUtils interface { +type detectorUtilsResources interface { getContainerName() (string, error) getContainerID() (string, error) } // struct implements detectorUtils interface -type EcsDetectorUtils struct{} +type DetectorUtils struct{} // resource detector collects resource information from Elastic Container Service environment type ResourceDetector struct { - Utils detectorUtils + Utils detectorUtilsResources } // Detect finds associated resources when running on ECS environment. @@ -81,7 +81,7 @@ func (detector *ResourceDetector) Detect(ctx context.Context) (*resource.Resourc } // returns docker container ID from default c group path -func (ecsUtils EcsDetectorUtils) getContainerID() (string, error) { +func (ecsUtils DetectorUtils) getContainerID() (string, error) { fileData, err := ioutil.ReadFile(defaultCgroupPath) if err != nil { return "", errCannotReadCGroupFile @@ -96,7 +96,7 @@ func (ecsUtils EcsDetectorUtils) getContainerID() (string, error) { } // returns host name reported by the kernel -func (ecsUtils EcsDetectorUtils) getContainerName() (string, error) { +func (ecsUtils DetectorUtils) getContainerName() (string, error) { hostName, err := os.Hostname() if err != nil { return "", errCannotReadContainerName From 86c04d1b71f1fcb56703afac36148503098553ec Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Sat, 6 Feb 2021 17:22:49 -0800 Subject: [PATCH 06/17] minor changes --- detectors/aws/ecs/ecs.go | 2 +- detectors/aws/ecs/ecs_test.go | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/detectors/aws/ecs/ecs.go b/detectors/aws/ecs/ecs.go index a319454e72b..f6237a19f14 100644 --- a/detectors/aws/ecs/ecs.go +++ b/detectors/aws/ecs/ecs.go @@ -48,7 +48,7 @@ type detectorUtilsResources interface { getContainerID() (string, error) } -// struct implements detectorUtils interface +// struct implements detectorUtilsResources interface type DetectorUtils struct{} // resource detector collects resource information from Elastic Container Service environment diff --git a/detectors/aws/ecs/ecs_test.go b/detectors/aws/ecs/ecs_test.go index 86239f61a81..045648ea035 100644 --- a/detectors/aws/ecs/ecs_test.go +++ b/detectors/aws/ecs/ecs_test.go @@ -98,23 +98,6 @@ func TestDetectCannotReadContainerName(t *testing.T) { assert.Equal(t, 0, len(res.Attributes())) } -//returns empty resource when detector cannot read container Name -func TestDetectCannotReadContainerName(t *testing.T) { - os.Clearenv() - os.Setenv(metadataV3EnvVar, "3") - os.Setenv(metadataV4EnvVar, "4") - detectorUtils := new(MockDetectorUtils) - - detectorUtils.On("getContainerName").Return("", errCannotReadContainerName) - detectorUtils.On("getContainerID").Return("0123456789A", nil) - - detector := ResourceDetector{detectorUtils} - resource, err := detector.Detect(context.Background()) - - assert.Equal(t, errCannotReadContainerName, err) - assert.Equal(t, 0, len(resource.Attributes())) -} - //returns empty resource when process is not running ECS func TestReturnsIfNoEnvVars(t *testing.T) { os.Clearenv() From 047f5d0c663a283163d8d9154cff2c292bd76b0f Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Tue, 9 Feb 2021 09:58:45 -0800 Subject: [PATCH 07/17] added NewResourceDetector func and interface assertions --- detectors/aws/ecs/ecs.go | 21 ++++++++++++++++----- detectors/aws/ecs/ecs_test.go | 8 ++++---- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/detectors/aws/ecs/ecs.go b/detectors/aws/ecs/ecs.go index f6237a19f14..5978b1476f7 100644 --- a/detectors/aws/ecs/ecs.go +++ b/detectors/aws/ecs/ecs.go @@ -52,23 +52,34 @@ type detectorUtilsResources interface { type DetectorUtils struct{} // resource detector collects resource information from Elastic Container Service environment -type ResourceDetector struct { - Utils detectorUtilsResources +type resourceDetector struct { + utils detectorUtilsResources +} + +// compile time assertion that ecsDetectorUtils implements detectorUtilsResources interface +var _ detectorUtilsResources = (*DetectorUtils)(nil) + +// compile time assertion that resource detector implements the resource.Detector interface. +var _ resource.Detector = (*resourceDetector)(nil) + +// returns resource detector struct +func NewResourceDetector(detectorUtils detectorUtilsResources) resourceDetector{ + return resourceDetector{utils: detectorUtils} } // Detect finds associated resources when running on ECS environment. -func (detector *ResourceDetector) Detect(ctx context.Context) (*resource.Resource, error) { +func (detector *resourceDetector) Detect(ctx context.Context) (*resource.Resource, error) { metadataURIV3 := os.Getenv(metadataV3EnvVar) metadataURIV4 := os.Getenv(metadataV4EnvVar) if len(metadataURIV3) == 0 && len(metadataURIV4) == 0 { return empty, errNotOnECS } - hostName, err := detector.Utils.getContainerName() + hostName, err := detector.utils.getContainerName() if err != nil { return empty, err } - containerID, err := detector.Utils.getContainerID() + containerID, err := detector.utils.getContainerID() if err != nil { return empty, err } diff --git a/detectors/aws/ecs/ecs_test.go b/detectors/aws/ecs/ecs_test.go index 045648ea035..fda1d4ba210 100644 --- a/detectors/aws/ecs/ecs_test.go +++ b/detectors/aws/ecs/ecs_test.go @@ -58,7 +58,7 @@ func TestDetect(t *testing.T) { semconv.ContainerIDKey.String("0123456789A"), } expectedResource := resource.NewWithAttributes(labels...) - detector := ResourceDetector{detectorUtils} + detector := NewResourceDetector(detectorUtils) res, _ := detector.Detect(context.Background()) assert.Equal(t, res, expectedResource, "Resource returned is incorrect") @@ -74,7 +74,7 @@ func TestDetectCannotReadContainerID(t *testing.T) { detectorUtils.On("getContainerName").Return("container-Name", nil) detectorUtils.On("getContainerID").Return("", errCannotReadContainerID) - detector := ResourceDetector{detectorUtils} + detector := NewResourceDetector(detectorUtils) res, err := detector.Detect(context.Background()) assert.Equal(t, errCannotReadContainerID, err) @@ -91,7 +91,7 @@ func TestDetectCannotReadContainerName(t *testing.T) { detectorUtils.On("getContainerName").Return("", errCannotReadContainerName) detectorUtils.On("getContainerID").Return("0123456789A", nil) - detector := ResourceDetector{detectorUtils} + detector := NewResourceDetector(detectorUtils) res, err := detector.Detect(context.Background()) assert.Equal(t, errCannotReadContainerName, err) @@ -101,7 +101,7 @@ func TestDetectCannotReadContainerName(t *testing.T) { //returns empty resource when process is not running ECS func TestReturnsIfNoEnvVars(t *testing.T) { os.Clearenv() - detector := ResourceDetector{} + detector := NewResourceDetector(nil) res, err := detector.Detect(context.Background()) assert.Equal(t, errNotOnECS, err) From 21db8fabc829a60110299e36658c1f9039b704b7 Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Tue, 9 Feb 2021 14:42:29 -0800 Subject: [PATCH 08/17] fix golint failure --- detectors/aws/ecs/ecs.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/detectors/aws/ecs/ecs.go b/detectors/aws/ecs/ecs.go index 5978b1476f7..57376e876e9 100644 --- a/detectors/aws/ecs/ecs.go +++ b/detectors/aws/ecs/ecs.go @@ -63,8 +63,8 @@ var _ detectorUtilsResources = (*DetectorUtils)(nil) var _ resource.Detector = (*resourceDetector)(nil) // returns resource detector struct -func NewResourceDetector(detectorUtils detectorUtilsResources) resourceDetector{ - return resourceDetector{utils: detectorUtils} +func NewResourceDetector(detectorUtils detectorUtilsResources) resource.Detector { + return &resourceDetector{utils: detectorUtils} } // Detect finds associated resources when running on ECS environment. From 5204d27fd5ab645060c5f07d746404b6b8ca54df Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Tue, 9 Feb 2021 17:24:15 -0800 Subject: [PATCH 09/17] minor changes to address review comments --- detectors/aws/ecs/ecs.go | 22 +++++++++++----------- detectors/aws/ecs/ecs_test.go | 8 ++++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/detectors/aws/ecs/ecs.go b/detectors/aws/ecs/ecs.go index 57376e876e9..2e21bb080b0 100644 --- a/detectors/aws/ecs/ecs.go +++ b/detectors/aws/ecs/ecs.go @@ -43,28 +43,28 @@ var ( ) // Create interface for methods needing to be mocked -type detectorUtilsResources interface { +type detectorUtils interface { getContainerName() (string, error) getContainerID() (string, error) } -// struct implements detectorUtilsResources interface -type DetectorUtils struct{} +// struct implements detectorUtils interface +type ecsDetectorUtils struct{} // resource detector collects resource information from Elastic Container Service environment type resourceDetector struct { - utils detectorUtilsResources + utils detectorUtils } -// compile time assertion that ecsDetectorUtils implements detectorUtilsResources interface -var _ detectorUtilsResources = (*DetectorUtils)(nil) +// compile time assertion that ecsDetectorUtils implements detectorUtils interface +var _ detectorUtils = (*ecsDetectorUtils)(nil) // compile time assertion that resource detector implements the resource.Detector interface. var _ resource.Detector = (*resourceDetector)(nil) -// returns resource detector struct -func NewResourceDetector(detectorUtils detectorUtilsResources) resource.Detector { - return &resourceDetector{utils: detectorUtils} +// NewResourceDetector returns a resource detector that will detect AWS ECS resources. +func NewResourceDetector() resource.Detector { + return &resourceDetector{utils: ecsDetectorUtils{}} } // Detect finds associated resources when running on ECS environment. @@ -92,7 +92,7 @@ func (detector *resourceDetector) Detect(ctx context.Context) (*resource.Resourc } // returns docker container ID from default c group path -func (ecsUtils DetectorUtils) getContainerID() (string, error) { +func (ecsUtils ecsDetectorUtils) getContainerID() (string, error) { fileData, err := ioutil.ReadFile(defaultCgroupPath) if err != nil { return "", errCannotReadCGroupFile @@ -107,7 +107,7 @@ func (ecsUtils DetectorUtils) getContainerID() (string, error) { } // returns host name reported by the kernel -func (ecsUtils DetectorUtils) getContainerName() (string, error) { +func (ecsUtils ecsDetectorUtils) getContainerName() (string, error) { hostName, err := os.Hostname() if err != nil { return "", errCannotReadContainerName diff --git a/detectors/aws/ecs/ecs_test.go b/detectors/aws/ecs/ecs_test.go index fda1d4ba210..c7719102818 100644 --- a/detectors/aws/ecs/ecs_test.go +++ b/detectors/aws/ecs/ecs_test.go @@ -58,7 +58,7 @@ func TestDetect(t *testing.T) { semconv.ContainerIDKey.String("0123456789A"), } expectedResource := resource.NewWithAttributes(labels...) - detector := NewResourceDetector(detectorUtils) + detector := &resourceDetector{utils: detectorUtils} res, _ := detector.Detect(context.Background()) assert.Equal(t, res, expectedResource, "Resource returned is incorrect") @@ -74,7 +74,7 @@ func TestDetectCannotReadContainerID(t *testing.T) { detectorUtils.On("getContainerName").Return("container-Name", nil) detectorUtils.On("getContainerID").Return("", errCannotReadContainerID) - detector := NewResourceDetector(detectorUtils) + detector := &resourceDetector{utils: detectorUtils} res, err := detector.Detect(context.Background()) assert.Equal(t, errCannotReadContainerID, err) @@ -91,7 +91,7 @@ func TestDetectCannotReadContainerName(t *testing.T) { detectorUtils.On("getContainerName").Return("", errCannotReadContainerName) detectorUtils.On("getContainerID").Return("0123456789A", nil) - detector := NewResourceDetector(detectorUtils) + detector := &resourceDetector{utils: detectorUtils} res, err := detector.Detect(context.Background()) assert.Equal(t, errCannotReadContainerName, err) @@ -101,7 +101,7 @@ func TestDetectCannotReadContainerName(t *testing.T) { //returns empty resource when process is not running ECS func TestReturnsIfNoEnvVars(t *testing.T) { os.Clearenv() - detector := NewResourceDetector(nil) + detector := &resourceDetector{utils: nil} res, err := detector.Detect(context.Background()) assert.Equal(t, errNotOnECS, err) From 3470b869566c6429faf7f05233059126bbc56eb5 Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Wed, 3 Nov 2021 16:26:42 -0700 Subject: [PATCH 10/17] added async flusher as an option --- .../aws/aws-lambda-go/otellambda/config.go | 22 ++++++++++++++++++- .../otellambda/xrayconfig/xrayconfig.go | 21 +++++------------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/instrumentation/github.com/aws/aws-lambda-go/otellambda/config.go b/instrumentation/github.com/aws/aws-lambda-go/otellambda/config.go index fc4309379d1..202c981f393 100644 --- a/instrumentation/github.com/aws/aws-lambda-go/otellambda/config.go +++ b/instrumentation/github.com/aws/aws-lambda-go/otellambda/config.go @@ -16,9 +16,9 @@ package otellambda import ( "context" - "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" + "runtime" ) // A Flusher dictates how the instrumentation will attempt to flush @@ -90,6 +90,20 @@ type config struct { // The default value of Propagator the global otel Propagator // returned by otel.GetTextMapPropagator() Propagator propagation.TextMapPropagator + + asyncSafeFlusher asyncSafeFlusher +} + +type asyncSafeFlusher struct {} + +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.ForceFlush(ctx) } func WithTracerProvider(tracerProvider trace.TracerProvider) Option { @@ -115,3 +129,9 @@ func WithPropagator(propagator propagation.TextMapPropagator) Option { c.Propagator = propagator }) } + +func WithAsyncSafeFlusher() Option { + return optionFunc(func(c *config) { + c.asyncSafeFlusher = asyncSafeFlusher{} + }) +} 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..a24f24bef43 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 @@ -18,7 +18,6 @@ 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" @@ -35,20 +34,6 @@ func xrayEventToCarrier([]byte) propagation.TextMapCarrier { 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. @@ -76,7 +61,11 @@ func tracerProviderAndFlusher() ([]otellambda.Option, error) { sdktrace.WithResource(res), ) - return []otellambda.Option{otellambda.WithTracerProvider(tp), otellambda.WithFlusher(asyncSafeFlusher{tp: tp})}, nil + return []otellambda.Option{otellambda.WithTracerProvider(tp), AsyncSafeFlusher()}, nil +} + +func AsyncSafeFlusher() otellambda.Option { + return otellambda.WithAsyncSafeFlusher() } // EventToCarrier returns an otellambda.Option to enable From fbcf1acd91e5ca146e3397aaf293345eba0e9020 Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Thu, 4 Nov 2021 15:07:12 -0700 Subject: [PATCH 11/17] modified AllRecommendedConfig API and fix asyncSafeFlusher option --- .../aws/aws-lambda-go/otellambda/config.go | 15 +++--- .../otellambda/xrayconfig/xrayconfig.go | 53 ++++++++++--------- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/instrumentation/github.com/aws/aws-lambda-go/otellambda/config.go b/instrumentation/github.com/aws/aws-lambda-go/otellambda/config.go index 202c981f393..d7b883fc285 100644 --- a/instrumentation/github.com/aws/aws-lambda-go/otellambda/config.go +++ b/instrumentation/github.com/aws/aws-lambda-go/otellambda/config.go @@ -16,9 +16,10 @@ package otellambda import ( "context" + "runtime" + "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" - "runtime" ) // A Flusher dictates how the instrumentation will attempt to flush @@ -90,11 +91,11 @@ type config struct { // The default value of Propagator the global otel Propagator // returned by otel.GetTextMapPropagator() Propagator propagation.TextMapPropagator - - asyncSafeFlusher asyncSafeFlusher } -type asyncSafeFlusher struct {} +type asyncSafeFlusher struct { + flusher Flusher +} func (f asyncSafeFlusher) ForceFlush(ctx context.Context) error { // yield processor to attempt to ensure all spans have @@ -103,7 +104,7 @@ func (f asyncSafeFlusher) ForceFlush(ctx context.Context) error { // to be removed upon resolution of above issue runtime.Gosched() - return f.ForceFlush(ctx) + return f.flusher.ForceFlush(ctx) } func WithTracerProvider(tracerProvider trace.TracerProvider) Option { @@ -130,8 +131,8 @@ func WithPropagator(propagator propagation.TextMapPropagator) Option { }) } -func WithAsyncSafeFlusher() Option { +func WithAsyncSafeFlusher(f Flusher) Option { return optionFunc(func(c *config) { - c.asyncSafeFlusher = asyncSafeFlusher{} + c.Flusher = asyncSafeFlusher{f} }) } 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 a24f24bef43..996a842b0ea 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 @@ -34,38 +34,43 @@ func xrayEventToCarrier([]byte) propagation.TextMapCarrier { return propagation.HeaderCarrier{"X-Amzn-Trace-Id": []string{xrayTraceID}} } -// 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 +// PrepareTracerProvider returns a TracerProvider configured with exporter, +// id generator and lambda resource detector to send trace data to AWS X-Ray via Collector +func PrepareTracerProvider(ctx context.Context) (*sdktrace.TracerProvider, error) { + log.Println("creating trace exporter") exp, err := otlptracegrpc.New(ctx, otlptracegrpc.WithInsecure()) if err != nil { - return []otellambda.Option{}, err + errorLogger.Println("failed to create exporter: ", err) + return nil, err } detector := lambdadetector.NewResourceDetector() - res, err := detector.Detect(ctx) + resource, err := detector.Detect(ctx) if err != nil { - return []otellambda.Option{}, err + errorLogger.Println("failed to detect lambda resources: ", 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), AsyncSafeFlusher()}, nil + sdktrace.WithResource(resource), + ), nil } -func AsyncSafeFlusher() otellambda.Option { - return otellambda.WithAsyncSafeFlusher() +// 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(ctx context.Context) ([]otellambda.Option, *sdktrace.TracerProvider, error) { + tp, err := PrepareTracerProvider(ctx) + if err != nil { + errorLogger.Println("failed to prepare tracer provider: ", err) + return nil, nil, err + } + + return []otellambda.Option{otellambda.WithTracerProvider(tp), otellambda.WithAsyncSafeFlusher(tp)}, tp, nil } // EventToCarrier returns an otellambda.Option to enable @@ -84,12 +89,12 @@ func Propagator() otellambda.Option { // AllRecommendedOptions returns a list of all otellambda.Option(s) // recommended for the otellambda package when using AWS XRay -func AllRecommendedOptions() []otellambda.Option { - options, err := tracerProviderAndFlusher() +func AllRecommendedOptions(ctx context.Context) ([]otellambda.Option, *sdktrace.TracerProvider) { + options, tp, err := tracerProviderAndFlusher(ctx) 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 []otellambda.Option{}, nil } - return append(options, []otellambda.Option{EventToCarrier(), Propagator()}...) + return append(options, []otellambda.Option{EventToCarrier(), Propagator()}...), tp } From f03fca4d2304346542ca9f3df482d2fb8a1ea519 Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Thu, 4 Nov 2021 15:58:47 -0700 Subject: [PATCH 12/17] minor enhancements to improve AllRecommendedOptions further --- .../otellambda/xrayconfig/xrayconfig.go | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) 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 996a842b0ea..9b85b0bb77e 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 @@ -63,14 +63,8 @@ func PrepareTracerProvider(ctx context.Context) (*sdktrace.TracerProvider, error // 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(ctx context.Context) ([]otellambda.Option, *sdktrace.TracerProvider, error) { - tp, err := PrepareTracerProvider(ctx) - if err != nil { - errorLogger.Println("failed to prepare tracer provider: ", err) - return nil, nil, err - } - - return []otellambda.Option{otellambda.WithTracerProvider(tp), otellambda.WithAsyncSafeFlusher(tp)}, tp, nil +func tracerProviderAndFlusher(tp *sdktrace.TracerProvider) ([]otellambda.Option, error) { + return []otellambda.Option{otellambda.WithTracerProvider(tp), otellambda.WithAsyncSafeFlusher(tp)}, nil } // EventToCarrier returns an otellambda.Option to enable @@ -83,18 +77,17 @@ func EventToCarrier() otellambda.Option { // Propagator returns an otellambda.Option to enable the xray.Propagator func Propagator() otellambda.Option { - return otellambda.WithPropagator(xray.Propagator{}) } // AllRecommendedOptions returns a list of all otellambda.Option(s) // recommended for the otellambda package when using AWS XRay -func AllRecommendedOptions(ctx context.Context) ([]otellambda.Option, *sdktrace.TracerProvider) { - options, tp, err := tracerProviderAndFlusher(ctx) +func AllRecommendedOptions(tp *sdktrace.TracerProvider) ([]otellambda.Option) { + options, err := tracerProviderAndFlusher(tp) 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{}, nil + return []otellambda.Option{} } - return append(options, []otellambda.Option{EventToCarrier(), Propagator()}...), tp + return append(options, []otellambda.Option{EventToCarrier(), Propagator()}...) } From 4a3ea70d913045db74999e02f809298e0b0d162c Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Thu, 4 Nov 2021 16:30:12 -0700 Subject: [PATCH 13/17] ran makeprecommit for lint --- .../aws/aws-lambda-go/otellambda/xrayconfig/xrayconfig.go | 2 +- .../aws-lambda-go/otellambda/xrayconfig/xrayconfig_test.go | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) 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 9b85b0bb77e..f87cc43a40a 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 @@ -82,7 +82,7 @@ func Propagator() otellambda.Option { // AllRecommendedOptions returns a list of all otellambda.Option(s) // recommended for the otellambda package when using AWS XRay -func AllRecommendedOptions(tp *sdktrace.TracerProvider) ([]otellambda.Option) { +func AllRecommendedOptions(tp *sdktrace.TracerProvider) []otellambda.Option { options, err := tracerProviderAndFlusher(tp) if err != nil { // should we fail to create the TracerProvider, do not alter otellambda's default configuration 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..367478f3176 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, _ := PrepareTracerProvider(ctx) + 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, AllRecommendedOptions(tp)...) wrappedCallable := reflect.ValueOf(wrapped) resp := wrappedCallable.Call([]reflect.Value{reflect.ValueOf(mockContext)}) assert.Len(t, resp, 2) From 0a908300ddda9f598a91eebdd2a3ec1695edf503 Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Thu, 4 Nov 2021 16:57:57 -0700 Subject: [PATCH 14/17] README changes --- .../otellambda/xrayconfig/README.md | 47 ++++++++++++++----- 1 file changed, 36 insertions(+), 11 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..179d4545ff7 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 @@ -21,32 +21,57 @@ package main import ( "context" "fmt" + "github.com/aws/aws-lambda-go/lambda" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" ) -type MyEvent struct { - Name string `json:"name"` -} - -func HandleRequest(ctx context.Context, name MyEvent) (string, error) { - return fmt.Sprintf("Hello %s!", name.Name ), nil +func HandleRequest(ctx context.Context) (error) { + fmt.Println("Hello World!" ) + return nil } func main() { - lambda.Start(otellambda.WrapHandlerFunction(HandleRequest)) + ctx := context.Background() + lambda.Start(otellambda.InstrumentHandler(HandleRequest(ctx))) } ``` Now configure the instrumentation with the provided options to export traces to AWS X-Ray via [the OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) running as a Lambda Extension. Instructions for running the OTel Collector as a Lambda Extension can be found in the [AWS OpenTelemetry Documentation](https://aws-otel.github.io/docs/getting-started/lambda). ```go -// Add import -import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig" +// Add imports +import ( + "context" + "fmt" + + "github.com/aws/aws-lambda-go/lambda" + "go.opentelemetry.io/contrib/propagators/aws/xray" + "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" + "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig" + "go.opentelemetry.io/otel" +) // add options to WrapHandlerFunction call func main() { - lambda.Start(otellambda.WrapHandlerFunction(HandleRequest, xrayconfig.AllRecommendedOptions()...)) + ctx := context.Background() + + tp, err := xrayconfig.PrepareTracerProvider(ctx) + if err != nil { + fmt.Printf("error creating tracer provider: %v", err) + } + + defer func(ctx context.Context) { + err := tp.Shutdown(ctx) + if err != nil { + fmt.Printf("error shutting down tracer provider: %v", err) + } + }(ctx) + + otel.SetTracerProvider(tp) + otel.SetTextMapPropagator(xray.Propagator{}) + + lambda.Start(otellambda.InstrumentHandler(HandleRequest(ctx), xrayconfig.AllRecommendedOptions(tp)...)) } ``` ## Recommended AWS Lambda Instrumentation Options @@ -56,7 +81,7 @@ func main() { | `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()` +| `WithPropagator` | An `xray.propagator` | Individually exported as `Propagator()`, also included in `AllRecommendedOptions()` ## Useful links From b9fede879baa007686a4b491b87a66168c2e5c35 Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Thu, 4 Nov 2021 17:04:03 -0700 Subject: [PATCH 15/17] README changes: part 2 --- .../aws/aws-lambda-go/otellambda/README.md | 92 ++++++++----------- .../otellambda/xrayconfig/README.md | 63 ------------- 2 files changed, 40 insertions(+), 115 deletions(-) diff --git a/instrumentation/github.com/aws/aws-lambda-go/otellambda/README.md b/instrumentation/github.com/aws/aws-lambda-go/otellambda/README.md index 8cb985b9e34..d88eeab3400 100644 --- a/instrumentation/github.com/aws/aws-lambda-go/otellambda/README.md +++ b/instrumentation/github.com/aws/aws-lambda-go/otellambda/README.md @@ -16,7 +16,7 @@ See [./example](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/ ## Usage -Create a sample Lambda Go application such as below. +Create a sample Lambda Go application instrumented by the `otellambda` package such as below. ```go package main @@ -24,30 +24,57 @@ package main import ( "context" "fmt" + "github.com/aws/aws-lambda-go/lambda" + "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" ) -type MyEvent struct { - Name string `json:"name"` -} - -func HandleRequest(ctx context.Context, name MyEvent) (string, error) { - return fmt.Sprintf("Hello %s!", name.Name ), nil +func HandleRequest(ctx context.Context) (error) { + fmt.Println("Hello World!" ) + return nil } func main() { - lambda.Start(HandleRequest) + ctx := context.Background() + lambda.Start(otellambda.InstrumentHandler(HandleRequest(ctx))) } ``` -Now use the provided wrapper to instrument your basic Lambda function: +Now configure the instrumentation with the provided options to export traces to AWS X-Ray via [the OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) running as a Lambda Extension. Instructions for running the OTel Collector as a Lambda Extension can be found in the [AWS OpenTelemetry Documentation](https://aws-otel.github.io/docs/getting-started/lambda). + ```go -// Add import -import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" +// Add imports +import ( + "context" + "fmt" + + "github.com/aws/aws-lambda-go/lambda" + "go.opentelemetry.io/contrib/propagators/aws/xray" + "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" + "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig" + "go.opentelemetry.io/otel" +) -// wrap lambda handler function +// add options to WrapHandlerFunction call func main() { - lambda.Start(otellambda.InstrumentHandler(HandleRequest)) + ctx := context.Background() + + tp, err := xrayconfig.PrepareTracerProvider(ctx) + if err != nil { + fmt.Printf("error creating tracer provider: %v", err) + } + + defer func(ctx context.Context) { + err := tp.Shutdown(ctx) + if err != nil { + fmt.Printf("error shutting down tracer provider: %v", err) + } + }(ctx) + + otel.SetTracerProvider(tp) + otel.SetTextMapPropagator(xray.Propagator{}) + + lambda.Start(otellambda.InstrumentHandler(HandleRequest(ctx), xrayconfig.AllRecommendedOptions(tp)...)) } ``` @@ -60,45 +87,6 @@ func main() { | `WithEventToCarrier` | `func(eventJSON []byte) propagation.TextMapCarrier{}` | Function for providing custom logic to support retrieving trace header from different event types that are handled by AWS Lambda (e.g., SQS, CloudWatch, Kinesis, API Gateway) and returning them in a `propagation.TextMapCarrier` which a Propagator can use to extract the trace header into the context. | Function which returns an empty `TextMapCarrier` - new spans will be part of a new Trace and have no parent past Lambda instrumentation span | `WithPropagator` | `propagation.Propagator` | The `Propagator` the instrumentation will use to extract trace information into the context. | `otel.GetTextMapPropagator()` | -### Usage With Options Example - -```go -var someHeaderKey = "Key" // used by propagator and EventToCarrier function to identify trace header - -type mockHTTPRequest struct { - Headers map[string][]string - Body string -} - -func mockEventToCarrier(eventJSON []byte) propagation.TextMapCarrier{ - var request mockHTTPRequest - _ = json.unmarshal(eventJSON, &request) - return propogation.HeaderCarrier{someHeaderKey: []string{request.Headers[someHeaderKey]}} -} - -type mockPropagator struct{} -// Extract - read from `someHeaderKey` -// Inject -// Fields - -func HandleRequest(ctx context.Context, request mockHTTPRequest) error { - return fmt.Sprintf("Hello %s!", request.Body ), nil -} - -func main() { - exp, _ := stdouttrace.New() - - tp := sdktrace.NewTracerProvider( - sdktrace.WithBatcher(exp)) - - lambda.Start(otellambda.InstrumentHandler(HandleRequest, - otellambda.WithTracerProvider(tp), - otellambda.WithFlusher(tp), - otellambda.WithEventToCarrier(mockEventToCarrier), - otellambda.WithPropagator(mockPropagator{}))) -} -``` - ## Useful links - For more information on OpenTelemetry, visit: 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 179d4545ff7..b53a47e8aa5 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 @@ -11,69 +11,6 @@ This module provides recommended configuration options for [`AWS Lambda Instrume go get -u go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig ``` -## Usage - -Create a sample Lambda Go application instrumented by the `otellambda` package such as below. - -```go -package main - -import ( - "context" - "fmt" - - "github.com/aws/aws-lambda-go/lambda" - "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" -) - -func HandleRequest(ctx context.Context) (error) { - fmt.Println("Hello World!" ) - return nil -} - -func main() { - ctx := context.Background() - lambda.Start(otellambda.InstrumentHandler(HandleRequest(ctx))) -} -``` - -Now configure the instrumentation with the provided options to export traces to AWS X-Ray via [the OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) running as a Lambda Extension. Instructions for running the OTel Collector as a Lambda Extension can be found in the [AWS OpenTelemetry Documentation](https://aws-otel.github.io/docs/getting-started/lambda). - -```go -// Add imports -import ( - "context" - "fmt" - - "github.com/aws/aws-lambda-go/lambda" - "go.opentelemetry.io/contrib/propagators/aws/xray" - "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" - "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig" - "go.opentelemetry.io/otel" -) - -// add options to WrapHandlerFunction call -func main() { - ctx := context.Background() - - tp, err := xrayconfig.PrepareTracerProvider(ctx) - if err != nil { - fmt.Printf("error creating tracer provider: %v", err) - } - - defer func(ctx context.Context) { - err := tp.Shutdown(ctx) - if err != nil { - fmt.Printf("error shutting down tracer provider: %v", err) - } - }(ctx) - - otel.SetTracerProvider(tp) - otel.SetTextMapPropagator(xray.Propagator{}) - - lambda.Start(otellambda.InstrumentHandler(HandleRequest(ctx), xrayconfig.AllRecommendedOptions(tp)...)) -} -``` ## Recommended AWS Lambda Instrumentation Options | Instrumentation Option | Recommended Value | Exported As | From 38663b0d63dad62cc5242724822cabc64011b586 Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Fri, 5 Nov 2021 11:38:50 -0700 Subject: [PATCH 16/17] restore README changes --- .../aws/aws-lambda-go/otellambda/README.md | 96 +++++++++++-------- .../otellambda/xrayconfig/README.md | 40 +++++++- 2 files changed, 93 insertions(+), 43 deletions(-) diff --git a/instrumentation/github.com/aws/aws-lambda-go/otellambda/README.md b/instrumentation/github.com/aws/aws-lambda-go/otellambda/README.md index d88eeab3400..14acd49b99e 100644 --- a/instrumentation/github.com/aws/aws-lambda-go/otellambda/README.md +++ b/instrumentation/github.com/aws/aws-lambda-go/otellambda/README.md @@ -16,7 +16,7 @@ See [./example](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/ ## Usage -Create a sample Lambda Go application instrumented by the `otellambda` package such as below. +Create a sample Lambda Go application such as below. ```go package main @@ -24,57 +24,30 @@ package main import ( "context" "fmt" - "github.com/aws/aws-lambda-go/lambda" - "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" ) -func HandleRequest(ctx context.Context) (error) { - fmt.Println("Hello World!" ) - return nil +type MyEvent struct { + Name string `json:"name"` +} + +func HandleRequest(ctx context.Context, name MyEvent) (string, error) { + return fmt.Sprintf("Hello %s!", name.Name ), nil } func main() { - ctx := context.Background() - lambda.Start(otellambda.InstrumentHandler(HandleRequest(ctx))) + lambda.Start(HandleRequest) } ``` -Now configure the instrumentation with the provided options to export traces to AWS X-Ray via [the OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) running as a Lambda Extension. Instructions for running the OTel Collector as a Lambda Extension can be found in the [AWS OpenTelemetry Documentation](https://aws-otel.github.io/docs/getting-started/lambda). - +Now use the provided wrapper to instrument your basic Lambda function: ```go -// Add imports -import ( - "context" - "fmt" - - "github.com/aws/aws-lambda-go/lambda" - "go.opentelemetry.io/contrib/propagators/aws/xray" - "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" - "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig" - "go.opentelemetry.io/otel" -) +// Add import +import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" -// add options to WrapHandlerFunction call +// wrap lambda handler function func main() { - ctx := context.Background() - - tp, err := xrayconfig.PrepareTracerProvider(ctx) - if err != nil { - fmt.Printf("error creating tracer provider: %v", err) - } - - defer func(ctx context.Context) { - err := tp.Shutdown(ctx) - if err != nil { - fmt.Printf("error shutting down tracer provider: %v", err) - } - }(ctx) - - otel.SetTracerProvider(tp) - otel.SetTextMapPropagator(xray.Propagator{}) - - lambda.Start(otellambda.InstrumentHandler(HandleRequest(ctx), xrayconfig.AllRecommendedOptions(tp)...)) + lambda.Start(otellambda.InstrumentHandler(HandleRequest)) } ``` @@ -87,11 +60,50 @@ func main() { | `WithEventToCarrier` | `func(eventJSON []byte) propagation.TextMapCarrier{}` | Function for providing custom logic to support retrieving trace header from different event types that are handled by AWS Lambda (e.g., SQS, CloudWatch, Kinesis, API Gateway) and returning them in a `propagation.TextMapCarrier` which a Propagator can use to extract the trace header into the context. | Function which returns an empty `TextMapCarrier` - new spans will be part of a new Trace and have no parent past Lambda instrumentation span | `WithPropagator` | `propagation.Propagator` | The `Propagator` the instrumentation will use to extract trace information into the context. | `otel.GetTextMapPropagator()` | +### Usage With Options Example + +```go +var someHeaderKey = "Key" // used by propagator and EventToCarrier function to identify trace header + +type mockHTTPRequest struct { +Headers map[string][]string +Body string +} + +func mockEventToCarrier(eventJSON []byte) propagation.TextMapCarrier{ +var request mockHTTPRequest +_ = json.unmarshal(eventJSON, &request) +return propogation.HeaderCarrier{someHeaderKey: []string{request.Headers[someHeaderKey]}} +} + +type mockPropagator struct{} +// Extract - read from `someHeaderKey` +// Inject +// Fields + +func HandleRequest(ctx context.Context, request mockHTTPRequest) error { +return fmt.Sprintf("Hello %s!", request.Body ), nil +} + +func main() { +exp, _ := stdouttrace.New() + +tp := sdktrace.NewTracerProvider( +sdktrace.WithBatcher(exp)) + +lambda.Start(otellambda.InstrumentHandler(HandleRequest, +otellambda.WithTracerProvider(tp), +otellambda.WithFlusher(tp), +otellambda.WithEventToCarrier(mockEventToCarrier), +otellambda.WithPropagator(mockPropagator{}))) +} +``` + ## Useful links - For more information on OpenTelemetry, visit: - For more about OpenTelemetry Go: -- For help or feedback on this project, join us in [GitHub Discussions][discussions-url] +- For help or feedback on this project, join us in [GitHub Discussions][discussions-url] ## License @@ -102,4 +114,4 @@ Apache 2.0 - See [LICENSE][license-url] for more information. [goref-image]: https://pkg.go.dev/badge/go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda.svg [goref-url]: https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda [discussions-url]: https://github.com/open-telemetry/opentelemetry-go/discussions -[lambda-detector-url]: https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/detectors/aws/lambda +[lambda-detector-url]: https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/detectors/aws/lambda \ No newline at end of file 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 b53a47e8aa5..7ec58e6b03d 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 @@ -11,6 +11,44 @@ This module provides recommended configuration options for [`AWS Lambda Instrume go get -u go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig ``` +## Usage + +Create a sample Lambda Go application instrumented by the `otellambda` package such as below. + +```go +package main + +import ( + "context" + "fmt" + "github.com/aws/aws-lambda-go/lambda" + "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" +) + +type MyEvent struct { + Name string `json:"name"` +} + +func HandleRequest(ctx context.Context, name MyEvent) (string, error) { + return fmt.Sprintf("Hello %s!", name.Name ), nil +} + +func main() { + lambda.Start(otellambda.InstrumentHandler(HandleRequest)) +} +``` + +Now configure the instrumentation with the provided options to export traces to AWS X-Ray via [the OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) running as a Lambda Extension. Instructions for running the OTel Collector as a Lambda Extension can be found in the [AWS OpenTelemetry Documentation](https://aws-otel.github.io/docs/getting-started/lambda). + +```go +// Add import +import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig" + +// add options to WrapHandlerFunction call +func main() { + lambda.Start(otellambda.InstrumentHandler(HandleRequest, xrayconfig.AllRecommendedOptions()...)) +} +``` ## Recommended AWS Lambda Instrumentation Options | Instrumentation Option | Recommended Value | Exported As | @@ -36,4 +74,4 @@ Apache 2.0 - See [LICENSE][license-url] for more information. [license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat [goref-image]: https://pkg.go.dev/badge/go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig.svg [goref-url]: https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig -[discussions-url]: https://github.com/open-telemetry/opentelemetry-go/discussions +[discussions-url]: https://github.com/open-telemetry/opentelemetry-go/discussions \ No newline at end of file From 9d2d7370c25e01b4a4d744f1f03207c60606d862 Mon Sep 17 00:00:00 2001 From: bhautikpip Date: Fri, 5 Nov 2021 11:42:53 -0700 Subject: [PATCH 17/17] restore README changes: 2 --- .../aws/aws-lambda-go/otellambda/README.md | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/instrumentation/github.com/aws/aws-lambda-go/otellambda/README.md b/instrumentation/github.com/aws/aws-lambda-go/otellambda/README.md index 14acd49b99e..71b8771525a 100644 --- a/instrumentation/github.com/aws/aws-lambda-go/otellambda/README.md +++ b/instrumentation/github.com/aws/aws-lambda-go/otellambda/README.md @@ -66,14 +66,14 @@ func main() { var someHeaderKey = "Key" // used by propagator and EventToCarrier function to identify trace header type mockHTTPRequest struct { -Headers map[string][]string -Body string + Headers map[string][]string + Body string } func mockEventToCarrier(eventJSON []byte) propagation.TextMapCarrier{ -var request mockHTTPRequest -_ = json.unmarshal(eventJSON, &request) -return propogation.HeaderCarrier{someHeaderKey: []string{request.Headers[someHeaderKey]}} + var request mockHTTPRequest + _ = json.unmarshal(eventJSON, &request) + return propogation.HeaderCarrier{someHeaderKey: []string{request.Headers[someHeaderKey]}} } type mockPropagator struct{} @@ -82,20 +82,20 @@ type mockPropagator struct{} // Fields func HandleRequest(ctx context.Context, request mockHTTPRequest) error { -return fmt.Sprintf("Hello %s!", request.Body ), nil + return fmt.Sprintf("Hello %s!", request.Body ), nil } func main() { -exp, _ := stdouttrace.New() + exp, _ := stdouttrace.New() -tp := sdktrace.NewTracerProvider( -sdktrace.WithBatcher(exp)) + tp := sdktrace.NewTracerProvider( + sdktrace.WithBatcher(exp)) -lambda.Start(otellambda.InstrumentHandler(HandleRequest, -otellambda.WithTracerProvider(tp), -otellambda.WithFlusher(tp), -otellambda.WithEventToCarrier(mockEventToCarrier), -otellambda.WithPropagator(mockPropagator{}))) + lambda.Start(otellambda.InstrumentHandler(HandleRequest, + otellambda.WithTracerProvider(tp), + otellambda.WithFlusher(tp), + otellambda.WithEventToCarrier(mockEventToCarrier), + otellambda.WithPropagator(mockPropagator{}))) } ```