Repository: open-telemetry/opentelemetry-go-contrib
Pull request #3148 (2023-01-13 11:24:31)

Add missing recommended resource attributes to AWS Lambda detector
Adds missing resource attributes in accordance with the FaaS specification (https://opentelemetry.io/docs/reference/specification/resource/semantic_conventions/faas/), in particular `faas.instance` and `faas.max_memory`.

Adjusts relevant tests as well.

codecov[bot]: # [Codecov](https://codecov.io/gh/open-telemetry/opentelemetry-go-contrib/pull/3148?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-telemetry) Report
> Merging [#3148](https://codecov.io/gh/open-telemetry/opentelemetry-go-contrib/pull/3148?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-telemetry) (5c51af3) into [main](https://codecov.io/gh/open-telemetry/opentelemetry-go-contrib/commit/537f38a110f0437a68eaa021c88e47c68f2ed211?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-telemetry) (537f38a) will **increase** coverage by `0.0%`.
> The diff coverage is `100.0%`.

> :exclamation: Current head 5c51af3 differs from pull request most recent head 02a2709. Consider uploading reports for the commit 02a2709 to get more accurate results

<details><summary>Additional details and impacted files</summary>


[![Impacted file tree graph](https://codecov.io/gh/open-telemetry/opentelemetry-go-contrib/pull/3148/graphs/tree.svg?width=650&height=150&src=pr&token=P6F3W9WA7Q&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-telemetry)](https://codecov.io/gh/open-telemetry/opentelemetry-go-contrib/pull/3148?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-telemetry)

```diff
@@          Coverage Diff          @@
##            main   #3148   +/-   ##
=====================================
  Coverage   69.2%   69.3%           
=====================================
  Files        147     147           
  Lines       6884    6893    +9     
=====================================
+ Hits        4768    4777    +9     
  Misses      2000    2000           
  Partials     116     116           
```


| [Impacted Files](https://codecov.io/gh/open-telemetry/opentelemetry-go-contrib/pull/3148?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-telemetry) | Coverage Δ | |
|---|---|---|
| [detectors/aws/lambda/detector.go](https://codecov.io/gh/open-telemetry/opentelemetry-go-contrib/pull/3148?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-telemetry#diff-ZGV0ZWN0b3JzL2F3cy9sYW1iZGEvZGV0ZWN0b3IuZ28=) | `92.8% <100.0%> (+3.3%)` | :arrow_up: |

</details>
MrAlias: Please update this branch with `main` so this PR can be merged.
matej-g: @MrAlias done, thank you 🙇 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0c17288ba..d3abf6817 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
 
 - Add the new `go.opentelemetry.io/contrib/instrgen` package to provide auto-generated source code instrumentation. (#3068)
 - `otelmux`: Add new `WithSpanNameFormatter` option to `go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux` to allow customizing span names. (#3041)
+- Add missing recommended AWS Lambda resource attributes `faas.instance` and `faas.max_memory` in `go.opentelemetry.io/contrib/detectors/aws/lambda`. (#3148)
 - Improve documentation for `samplers/jaegerremote` by providing examples of sampling endpoints. (#3147)
 
 ## [1.12.0/0.37.0/0.6.0]
diff --git a/detectors/aws/lambda/README.md b/detectors/aws/lambda/README.md
index 0f8f1bbe2..505b9f8f8 100644
--- a/detectors/aws/lambda/README.md
+++ b/detectors/aws/lambda/README.md
@@ -46,6 +46,8 @@ Now your `TracerProvider` will have the following resource attributes and attach
 |`cloud.region` | us-east-1 
 |`faas.name` | MyLambdaFunction 
 |`faas.version` | $LATEST
+|`faas.instance` | 2021/06/28/[$LATEST]2f399eb14537447da05ab2a2e39309de
+|`faas.max_memory`| 128
 
 Of note, `faas.id` and `cloud.account.id` are not set by the Lambda resource detector because they are not available outside a Lambda invocation. For this reason, when using the AWS Lambda Instrumentation these attributes are set as additional span attributes.
 
diff --git a/detectors/aws/lambda/detector.go b/detectors/aws/lambda/detector.go
index ff60db88b..07cea8f57 100644
--- a/detectors/aws/lambda/detector.go
+++ b/detectors/aws/lambda/detector.go
@@ -18,6 +18,7 @@ import (
 	"context"
 	"errors"
 	"os"
+	"strconv"
 
 	"go.opentelemetry.io/otel/attribute"
 	"go.opentelemetry.io/otel/sdk/resource"
@@ -30,6 +31,8 @@ const (
 	lambdaFunctionNameEnvVar    = "AWS_LAMBDA_FUNCTION_NAME"
 	awsRegionEnvVar             = "AWS_REGION"
 	lambdaFunctionVersionEnvVar = "AWS_LAMBDA_FUNCTION_VERSION"
+	lambdaLogStreamNameEnvVar   = "AWS_LAMBDA_LOG_STREAM_NAME"
+	lambdaMemoryLimitEnvVar     = "AWS_LAMBDA_FUNCTION_MEMORY_SIZE"
 )
 
 var (
@@ -57,13 +60,23 @@ func (detector *resourceDetector) Detect(context.Context) (*resource.Resource, e
 	}
 	awsRegion := os.Getenv(awsRegionEnvVar)
 	functionVersion := os.Getenv(lambdaFunctionVersionEnvVar)
+	// The instance attributes corresponds to the log stream name for AWS lambda,
+	// see the FaaS resource specification for more details.
+	instance := os.Getenv(lambdaLogStreamNameEnvVar)
 
 	attrs := []attribute.KeyValue{
 		semconv.CloudProviderAWS,
 		semconv.CloudRegionKey.String(awsRegion),
+		semconv.FaaSInstanceKey.String(instance),
 		semconv.FaaSNameKey.String(lambdaName),
 		semconv.FaaSVersionKey.String(functionVersion),
 	}
 
+	maxMemoryStr := os.Getenv(lambdaMemoryLimitEnvVar)
+	maxMemory, err := strconv.Atoi(maxMemoryStr)
+	if err == nil {
+		attrs = append(attrs, semconv.FaaSMaxMemoryKey.Int(maxMemory))
+	}
+
 	return resource.NewWithAttributes(semconv.SchemaURL, attrs...), nil
 }


Test patch:
diff --git a/detectors/aws/lambda/detector_test.go b/detectors/aws/lambda/detector_test.go
index 9c6c65d30..311362d8c 100644
--- a/detectors/aws/lambda/detector_test.go
+++ b/detectors/aws/lambda/detector_test.go
@@ -32,12 +32,16 @@ func TestDetectSuccess(t *testing.T) {
 	_ = os.Setenv(lambdaFunctionNameEnvVar, "testFunction")
 	_ = os.Setenv(awsRegionEnvVar, "us-texas-1")
 	_ = os.Setenv(lambdaFunctionVersionEnvVar, "$LATEST")
+	_ = os.Setenv(lambdaLogStreamNameEnvVar, "2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc")
+	_ = os.Setenv(lambdaMemoryLimitEnvVar, "128")
 
 	attributes := []attribute.KeyValue{
 		semconv.CloudProviderAWS,
 		semconv.CloudRegionKey.String("us-texas-1"),
 		semconv.FaaSNameKey.String("testFunction"),
 		semconv.FaaSVersionKey.String("$LATEST"),
+		semconv.FaaSInstanceKey.String("2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc"),
+		semconv.FaaSMaxMemoryKey.Int(128),
 	}
 	expectedResource := resource.NewWithAttributes(semconv.SchemaURL, attributes...)
 	detector := resourceDetector{}
diff --git a/instrumentation/github.com/aws/aws-lambda-go/otellambda/lambda_test.go b/instrumentation/github.com/aws/aws-lambda-go/otellambda/lambda_test.go
index caa823ce8..537b3d757 100644
--- a/instrumentation/github.com/aws/aws-lambda-go/otellambda/lambda_test.go
+++ b/instrumentation/github.com/aws/aws-lambda-go/otellambda/lambda_test.go
@@ -54,6 +54,8 @@ func setEnvVars() {
 	_ = os.Setenv("AWS_LAMBDA_FUNCTION_NAME", "testFunction")
 	_ = os.Setenv("AWS_REGION", "us-texas-1")
 	_ = os.Setenv("AWS_LAMBDA_FUNCTION_VERSION", "$LATEST")
+	_ = os.Setenv("AWS_LAMBDA_LOG_STREAM_NAME", "2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc")
+	_ = os.Setenv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "128")
 	_ = os.Setenv("_X_AMZN_TRACE_ID", "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1")
 }
 
diff --git a/instrumentation/github.com/aws/aws-lambda-go/otellambda/test/lambda_test.go b/instrumentation/github.com/aws/aws-lambda-go/otellambda/test/lambda_test.go
index edc73b9ad..87b246f24 100644
--- a/instrumentation/github.com/aws/aws-lambda-go/otellambda/test/lambda_test.go
+++ b/instrumentation/github.com/aws/aws-lambda-go/otellambda/test/lambda_test.go
@@ -102,6 +102,8 @@ func setEnvVars() {
 	_ = os.Setenv("AWS_LAMBDA_FUNCTION_NAME", "testFunction")
 	_ = os.Setenv("AWS_REGION", "us-texas-1")
 	_ = os.Setenv("AWS_LAMBDA_FUNCTION_VERSION", "$LATEST")
+	_ = os.Setenv("AWS_LAMBDA_LOG_STREAM_NAME", "2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc")
+	_ = os.Setenv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "128")
 	_ = os.Setenv("_X_AMZN_TRACE_ID", "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1")
 }
 
@@ -148,7 +150,9 @@ var (
 			attribute.String("cloud.provider", "aws"),
 			attribute.String("cloud.region", "us-texas-1"),
 			attribute.String("faas.name", "testFunction"),
-			attribute.String("faas.version", "$LATEST")),
+			attribute.String("faas.version", "$LATEST"),
+			attribute.String("faas.instance", "2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc"),
+			attribute.Int("faas.max_memory", 128)),
 		InstrumentationLibrary: instrumentation.Library{Name: "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda", Version: otellambda.SemVersion()},
 	}
 )
@@ -336,7 +340,9 @@ var (
 			attribute.String("cloud.provider", "aws"),
 			attribute.String("cloud.region", "us-texas-1"),
 			attribute.String("faas.name", "testFunction"),
-			attribute.String("faas.version", "$LATEST")),
+			attribute.String("faas.version", "$LATEST"),
+			attribute.String("faas.instance", "2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc"),
+			attribute.Int("faas.max_memory", 128)),
 		InstrumentationLibrary: instrumentation.Library{Name: "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda", Version: otellambda.SemVersion()},
 	}
 )
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 df27ea651..89c03dcea 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
@@ -67,6 +67,8 @@ func setEnvVars() {
 	_ = os.Setenv("AWS_LAMBDA_FUNCTION_NAME", "testFunction")
 	_ = os.Setenv("AWS_REGION", "us-texas-1")
 	_ = os.Setenv("AWS_LAMBDA_FUNCTION_VERSION", "$LATEST")
+	_ = os.Setenv("AWS_LAMBDA_LOG_STREAM_NAME", "2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc")
+	_ = os.Setenv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "128")
 	_ = os.Setenv("_X_AMZN_TRACE_ID", "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1")
 
 	// fix issue: "The requested service provider could not be loaded or initialized."
@@ -116,6 +118,8 @@ var (
 	expectedSpanResource = v1resource.Resource{
 		Attributes: []*v1common.KeyValue{{Key: "cloud.provider", Value: &v1common.AnyValue{Value: &v1common.AnyValue_StringValue{StringValue: "aws"}}},
 			{Key: "cloud.region", Value: &v1common.AnyValue{Value: &v1common.AnyValue_StringValue{StringValue: "us-texas-1"}}},
+			{Key: "faas.instance", Value: &v1common.AnyValue{Value: &v1common.AnyValue_StringValue{StringValue: "2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc"}}},
+			{Key: "faas.max_memory", Value: &v1common.AnyValue{Value: &v1common.AnyValue_IntValue{IntValue: 128}}},
 			{Key: "faas.name", Value: &v1common.AnyValue{Value: &v1common.AnyValue_StringValue{StringValue: "testFunction"}}},
 			{Key: "faas.version", Value: &v1common.AnyValue{Value: &v1common.AnyValue_StringValue{StringValue: "$LATEST"}}}},
 		DroppedAttributesCount: 0,
@@ -129,11 +133,13 @@ var (
 )
 
 func assertResourceEquals(t *testing.T, expected *v1resource.Resource, actual *v1resource.Resource) {
-	assert.Len(t, actual.Attributes, 4)
+	assert.Len(t, actual.Attributes, 6)
 	assert.Equal(t, expected.Attributes[0].String(), actual.Attributes[0].String())
 	assert.Equal(t, expected.Attributes[1].String(), actual.Attributes[1].String())
 	assert.Equal(t, expected.Attributes[2].String(), actual.Attributes[2].String())
 	assert.Equal(t, expected.Attributes[3].String(), actual.Attributes[3].String())
+	assert.Equal(t, expected.Attributes[4].String(), actual.Attributes[4].String())
+	assert.Equal(t, expected.Attributes[5].String(), actual.Attributes[5].String())
 	assert.Equal(t, expected.DroppedAttributesCount, actual.DroppedAttributesCount)
 }