Skip to content

Commit

Permalink
Add aws.logs.* support, remove spurious /aws prefix from log group
Browse files Browse the repository at this point in the history
  • Loading branch information
Michele Mancioppi committed Aug 12, 2022
1 parent 08ebda3 commit f32f201
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 12 deletions.
59 changes: 53 additions & 6 deletions detectors/aws/ecs/ecs.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"io/ioutil"
"net/http"
"os"
"regexp"
"strings"

ecsmetadata "github.com/brunoscheufler/aws-ecs-metadata-go"
Expand All @@ -40,12 +41,16 @@ 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")
errCannotRetrieveMetadataV4 = errors.New("ECS resource detector failed to retrieve metadata from the ECS Metada v4 container endpoint")
errCannotRetrieveMetadataV4Task = errors.New("ECS resource detector failed to retrieve metadata from the ECS Metada v4 task endpoint")
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")
errCannotRetrieveMetadataV4 = errors.New("ECS resource detector failed to retrieve metadata from the ECS Metadata v4 container endpoint")
errCannotRetrieveMetadataV4Task = errors.New("ECS resource detector failed to retrieve metadata from the ECS Metadata v4 task endpoint")
errCannotRetrieveLogsGroupMetadataV4 = errors.New("The ECS Metadata v4 did not return a AwsLogGroup name")
errCannotRetrieveLogsStreamMetadataV4 = errors.New("The ECS Metadata v4 did not return a AwsLogStream name")
errCannotParseAwsRegionMetadataV4 = errors.New("Cannot parse the AWS region our of the Container ARN returned by the ECS Metadata v4 container endpoint")
errCannotParseAwsAccountMetadataV4 = errors.New("Cannot parse the AWS account our of the Container ARN returned by the ECS Metadata v4 container endpoint")
)

// Create interface for methods needing to be mocked.
Expand Down Expand Up @@ -119,6 +124,15 @@ func (detector *resourceDetector) Detect(ctx context.Context) (*resource.Resourc
clusterArn = fmt.Sprintf("%s:cluster/%s", baseArn, clusterArn)
}

logAttributes, err := detector.getLogsAttributes(containerMetadata)
if err != nil {
return empty, err
}

if len(logAttributes) > 0 {
attributes = append(attributes, logAttributes...)
}

attributes = append(
attributes,
semconv.AWSECSClusterARNKey.String(clusterArn),
Expand All @@ -132,6 +146,39 @@ func (detector *resourceDetector) Detect(ctx context.Context) (*resource.Resourc
return resource.NewWithAttributes(semconv.SchemaURL, attributes...), nil
}

func (detector *resourceDetector) getLogsAttributes(metadata *ecsmetadata.ContainerMetadataV4) ([]attribute.KeyValue, error) {
if metadata.LogDriver != "awslogs" {
return []attribute.KeyValue{}, nil
}

logsOptions := metadata.LogOptions

if len(logsOptions.AwsLogsGroup) < 1 {
return nil, errCannotRetrieveLogsGroupMetadataV4
}

if len(logsOptions.AwsLogsStream) < 1 {
return nil, errCannotRetrieveLogsStreamMetadataV4
}

containerArn := metadata.ContainerARN
logsRegion := logsOptions.AwsRegion
if len(logsRegion) < 1 {
r := regexp.MustCompile(`arn:aws:ecs:([^:]+):.*`)
logsRegion = r.FindStringSubmatch(containerArn)[1]
}

r := regexp.MustCompile(`arn:aws:ecs:[^:]+:([^:]+):.*`)
awsAccount := r.FindStringSubmatch(containerArn)[1]

return []attribute.KeyValue{
semconv.AWSLogGroupNamesKey.String(logsOptions.AwsLogsGroup),
semconv.AWSLogGroupARNsKey.String(fmt.Sprintf("arn:aws:logs:%s:%s:log-group:%s:*", logsRegion, awsAccount, logsOptions.AwsLogsGroup)),
semconv.AWSLogStreamNamesKey.String(logsOptions.AwsLogsStream),
semconv.AWSLogStreamARNsKey.String(fmt.Sprintf("arn:aws:logs:%s:%s:log-group:%s:log-stream:%s", logsRegion, awsAccount, logsOptions.AwsLogsGroup, logsOptions.AwsLogsStream)),
}, nil
}

// returns docker container ID from default c group path.
func (ecsUtils ecsDetectorUtils) getContainerID() (string, error) {
fileData, err := ioutil.ReadFile(defaultCgroupPath)
Expand Down
16 changes: 15 additions & 1 deletion detectors/aws/ecs/ecs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package ecs

import (
"context"
"encoding/json"
http "net/http"
"net/http/httptest"
"os"
Expand All @@ -25,6 +26,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"

ecsmetadata "github.com/brunoscheufler/aws-ecs-metadata-go"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
Expand Down Expand Up @@ -107,11 +109,16 @@ func TestDetectV4(t *testing.T) {
semconv.AWSECSTaskARNKey.String("arn:aws:ecs:us-west-2:111122223333:task/default/158d1c8083dd49d6b527399fd6414f5c"),
semconv.AWSECSTaskFamilyKey.String("curltest"),
semconv.AWSECSTaskRevisionKey.String("26"),
semconv.AWSLogGroupNamesKey.String("/ecs/metadata"),
semconv.AWSLogGroupARNsKey.String("arn:aws:logs:us-west-2:111122223333:log-group:/ecs/metadata:*"),
semconv.AWSLogStreamNamesKey.String("ecs/curl/8f03e41243824aea923aca126495f665"),
semconv.AWSLogStreamARNsKey.String("arn:aws:logs:us-west-2:111122223333:log-group:/ecs/metadata:log-stream:ecs/curl/8f03e41243824aea923aca126495f665"),
}
expectedResource := resource.NewWithAttributes(semconv.SchemaURL, attributes...)
detector := &resourceDetector{utils: detectorUtils}
res, _ := detector.Detect(context.Background())
res, err := detector.Detect(context.Background())

assert.Equal(t, err, nil, "Detector should not file")
assert.Equal(t, expectedResource, res, "Resource returned is incorrect")
}

Expand Down Expand Up @@ -149,6 +156,13 @@ func TestDetectCannotReadContainerName(t *testing.T) {
assert.Equal(t, 0, len(res.Attributes()))
}

func TestDetectV4Parse(t *testing.T) {
content, _ := os.ReadFile("testdata/metadatav4-response-task.json")

taskMetadata := &ecsmetadata.TaskMetadataV4{}
json.Unmarshal(content, taskMetadata)
}

//returns empty resource when process is not running ECS.
func TestReturnsIfNoEnvVars(t *testing.T) {
os.Clearenv()
Expand Down
4 changes: 2 additions & 2 deletions detectors/aws/ecs/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ module go.opentelemetry.io/contrib/detectors/aws/ecs
go 1.17

require (
github.com/brunoscheufler/aws-ecs-metadata-go v0.0.0-20220806202253-1e93a1d357d6
github.com/stretchr/testify v1.8.0
go.opentelemetry.io/otel v1.9.0
go.opentelemetry.io/otel/sdk v1.9.0
)

require (
github.com/brunoscheufler/aws-ecs-metadata-go v0.0.0-20220812150832-b6b31c6eeeaf // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.4.0 // indirect
go.opentelemetry.io/otel/trace v1.9.0 // indirect
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 // indirect
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
10 changes: 7 additions & 3 deletions detectors/aws/ecs/go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
github.com/brunoscheufler/aws-ecs-metadata-go v0.0.0-20220806202253-1e93a1d357d6 h1:Izqf3e8tWDmFCnSRdmtej33tKPWlPYIvPPXqcI9qimM=
github.com/brunoscheufler/aws-ecs-metadata-go v0.0.0-20220806202253-1e93a1d357d6/go.mod h1:5BBxNAuQFkDjY3l9UHlJ8NnnM6NEi0bocZR2xc3xGxU=
github.com/brunoscheufler/aws-ecs-metadata-go v0.0.0-20220809142905-71ffda5b3a7b h1:sDlCP3q7DzAycTPuhV2U08iCoOwSO6SV4qOBlm012Vs=
github.com/brunoscheufler/aws-ecs-metadata-go v0.0.0-20220809142905-71ffda5b3a7b/go.mod h1:5BBxNAuQFkDjY3l9UHlJ8NnnM6NEi0bocZR2xc3xGxU=
github.com/brunoscheufler/aws-ecs-metadata-go v0.0.0-20220812150832-b6b31c6eeeaf h1:WCnJxXZXx9c8gwz598wvdqmu+YTzB9wx2X1OovK3Le8=
github.com/brunoscheufler/aws-ecs-metadata-go v0.0.0-20220812150832-b6b31c6eeeaf/go.mod h1:CeKhh8xSs3WZAc50xABMxu+FlfAAd5PNumo7NfOv7EE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -9,6 +11,7 @@ github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand All @@ -23,8 +26,9 @@ go.opentelemetry.io/otel/sdk v1.9.0 h1:LNXp1vrr83fNXTHgU8eO89mhzxb/bbWAsHG6fNf3q
go.opentelemetry.io/otel/sdk v1.9.0/go.mod h1:AEZc8nt5bd2F7BC24J5R0mrjYnpEgYHyTcM/vrSple4=
go.opentelemetry.io/otel/trace v1.9.0 h1:oZaCNJUjWcg60VXWee8lJKlqhPbXAPB51URuR47pQYc=
go.opentelemetry.io/otel/trace v1.9.0/go.mod h1:2737Q0MuG8q1uILYm2YYVkAyLtOofiTNGg6VODnOiPo=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 h1:v1W7bwXHsnLLloWYTVEdvGvA7BHMeBYsPcF0GLDxIRs=
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down

0 comments on commit f32f201

Please sign in to comment.