-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improved ECS attribute and origin translation in awsxrayexporter #1428
Changes from 3 commits
dc73a66
d2bfc7e
ed27d55
f03b0df
8923b17
c31c6bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ | |
package translator | ||
|
||
import ( | ||
"bytes" | ||
"strconv" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
|
@@ -27,6 +28,7 @@ import ( | |
func makeAws(attributes map[string]string, resource pdata.Resource) (map[string]string, *awsxray.AWSData) { | ||
var ( | ||
cloud string | ||
service string | ||
account string | ||
zone string | ||
hostID string | ||
|
@@ -49,6 +51,14 @@ func makeAws(attributes map[string]string, resource pdata.Resource) (map[string] | |
containerID string | ||
clusterName string | ||
podUID string | ||
clusterArn string | ||
containerArn string | ||
taskArn string | ||
taskFamily string | ||
launchType string | ||
logGroups pdata.AnyValueArray | ||
logGroupArns pdata.AnyValueArray | ||
cwl []awsxray.LogGroupMetadata | ||
ec2 *awsxray.EC2Metadata | ||
ecs *awsxray.ECSMetadata | ||
ebs *awsxray.BeanstalkMetadata | ||
|
@@ -61,6 +71,8 @@ func makeAws(attributes map[string]string, resource pdata.Resource) (map[string] | |
switch key { | ||
case semconventions.AttributeCloudProvider: | ||
cloud = value.StringVal() | ||
case "cloud.infrastructure_service": | ||
service = value.StringVal() | ||
case semconventions.AttributeCloudAccount: | ||
account = value.StringVal() | ||
case semconventions.AttributeCloudZone: | ||
|
@@ -95,6 +107,20 @@ func makeAws(attributes map[string]string, resource pdata.Resource) (map[string] | |
containerID = value.StringVal() | ||
case semconventions.AttributeK8sCluster: | ||
clusterName = value.StringVal() | ||
case "aws.ecs.cluster.arn": | ||
clusterArn = value.StringVal() | ||
case "aws.ecs.container.arn": | ||
containerArn = value.StringVal() | ||
case "aws.ecs.task.arn": | ||
taskArn = value.StringVal() | ||
case "aws.ecs.task.family": | ||
taskFamily = value.StringVal() | ||
case "aws.ecs.launchtype": | ||
launchType = value.StringVal() | ||
case "aws.log.group.names": | ||
logGroups = value.ArrayVal() | ||
case "aws.log.group.arns": | ||
logGroupArns = value.ArrayVal() | ||
} | ||
}) | ||
} | ||
|
@@ -128,22 +154,29 @@ func makeAws(attributes map[string]string, resource pdata.Resource) (map[string] | |
if cloud != "aws" && cloud != "" { | ||
return filtered, nil // not AWS so return nil | ||
} | ||
// progress from least specific to most specific origin so most specific ends up as origin | ||
// as per X-Ray docs | ||
if hostID != "" { | ||
|
||
if service == "EC2" || hostID != "" { | ||
ec2 = &awsxray.EC2Metadata{ | ||
InstanceID: awsxray.String(hostID), | ||
AvailabilityZone: awsxray.String(zone), | ||
InstanceSize: awsxray.String(hostType), | ||
AmiID: awsxray.String(amiID), | ||
} | ||
} | ||
if container != "" { | ||
if service == "ECS" || container != "" { | ||
ecs = &awsxray.ECSMetadata{ | ||
ContainerName: awsxray.String(container), | ||
ContainerID: awsxray.String(containerID), | ||
ContainerName: awsxray.String(container), | ||
ContainerID: awsxray.String(containerID), | ||
AvailabilityZone: awsxray.String(zone), | ||
ContainerArn: awsxray.String(containerArn), | ||
ClusterArn: awsxray.String(clusterArn), | ||
TaskArn: awsxray.String(taskArn), | ||
TaskFamily: awsxray.String(taskFamily), | ||
LaunchType: awsxray.String(launchType), | ||
} | ||
} | ||
|
||
// TODO(willarmiros): Add infrastructure_service checks once their resource detectors are implemented | ||
if deployID != "" { | ||
deployNum, err := strconv.ParseInt(deployID, 10, 64) | ||
if err != nil { | ||
|
@@ -163,6 +196,14 @@ func makeAws(attributes map[string]string, resource pdata.Resource) (map[string] | |
} | ||
} | ||
|
||
// Since we must couple log group ARNs and Log Group Names in the same CWLogs object, we first try to derive the | ||
// names from the ARN, then fall back to just recording the names | ||
if logGroupArns != (pdata.AnyValueArray{}) && logGroupArns.Len() > 0 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I initially didn't have it and it turns out the |
||
cwl = getLogGroupMetadata(logGroupArns, true) | ||
} else if logGroups != (pdata.AnyValueArray{}) && logGroups.Len() > 0 { | ||
cwl = getLogGroupMetadata(logGroups, false) | ||
} | ||
|
||
if sdkName != "" && sdkLanguage != "" { | ||
// Convention for SDK name for xray SDK information is e.g., `X-Ray SDK for Java`, `X-Ray for Go`. | ||
// We fill in with e.g, `opentelemetry for java` by using the conventions | ||
|
@@ -180,6 +221,7 @@ func makeAws(attributes map[string]string, resource pdata.Resource) (map[string] | |
awsData := &awsxray.AWSData{ | ||
AccountID: awsxray.String(account), | ||
Beanstalk: ebs, | ||
CWLogs: cwl, | ||
ECS: ecs, | ||
EC2: ec2, | ||
EKS: eks, | ||
|
@@ -192,3 +234,32 @@ func makeAws(attributes map[string]string, resource pdata.Resource) (map[string] | |
} | ||
return filtered, awsData | ||
} | ||
|
||
// Given an array of log group ARNs, create a corresponding amount of LogGroupMetadata objects with log_group and arn | ||
// populated, or given an array of just log group names, create the LogGroupMetadata objects with arn omitted | ||
func getLogGroupMetadata(logGroups pdata.AnyValueArray, isArn bool) []awsxray.LogGroupMetadata { | ||
var lgm []awsxray.LogGroupMetadata | ||
for i := 0; i < logGroups.Len(); i++ { | ||
if isArn { | ||
lgm = append(lgm, awsxray.LogGroupMetadata{ | ||
Arn: awsxray.String(logGroups.At(i).StringVal()), | ||
LogGroup: awsxray.String(parseLogGroup(logGroups.At(i).StringVal())), | ||
}) | ||
} else { | ||
lgm = append(lgm, awsxray.LogGroupMetadata{ | ||
LogGroup: awsxray.String(logGroups.At(i).StringVal()), | ||
}) | ||
} | ||
} | ||
|
||
return lgm | ||
} | ||
|
||
func parseLogGroup(arn string) string { | ||
i := bytes.LastIndexByte([]byte(arn), byte(':')) | ||
if i != -1 { | ||
return arn[i+1:] | ||
} | ||
|
||
return arn | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,10 +34,12 @@ import ( | |
|
||
// AWS X-Ray acceptable values for origin field. | ||
const ( | ||
OriginEC2 = "AWS::EC2::Instance" | ||
OriginECS = "AWS::ECS::Container" | ||
OriginEB = "AWS::ElasticBeanstalk::Environment" | ||
OriginEKS = "AWS::EKS::Container" | ||
OriginEC2 = "AWS::EC2::Instance" | ||
OriginECS = "AWS::ECS::Container" | ||
OriginECSEC2 = "AWS::ECS::EC2" | ||
OriginECSFargate = "AWS::ECS::Fargate" | ||
OriginEB = "AWS::ElasticBeanstalk::Environment" | ||
OriginEKS = "AWS::EKS::Container" | ||
) | ||
|
||
var ( | ||
|
@@ -235,6 +237,38 @@ func determineAwsOrigin(resource pdata.Resource) string { | |
return "" | ||
} | ||
} | ||
|
||
// TODO(willarmiros): Only use infrastructure_service for origin resolution once detectors for all AWS environments are | ||
// implemented for robustness | ||
is, present := resource.Attributes().Get("cloud.infrastructure_service") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can inline, e.g., |
||
if present { | ||
switch is.StringVal() { | ||
case "EKS": | ||
return OriginEKS | ||
case "ElasticBeanstalk": | ||
return OriginEB | ||
case "ECS": | ||
lt, present := resource.Attributes().Get("aws.ecs.launchtype") | ||
if !present { | ||
return OriginECS | ||
} | ||
switch lt.StringVal() { | ||
case "ec2": | ||
return OriginECSEC2 | ||
case "fargate": | ||
return OriginECSFargate | ||
default: | ||
return OriginECS | ||
} | ||
case "EC2": | ||
return OriginEC2 | ||
|
||
// If infrastructure_service is defined with a non-AWS value, we should not assign it an AWS origin | ||
default: | ||
return "" | ||
} | ||
} | ||
|
||
// EKS > EB > ECS > EC2 | ||
_, eks := resource.Attributes().Get(semconventions.AttributeK8sCluster) | ||
if eks { | ||
|
@@ -248,7 +282,11 @@ func determineAwsOrigin(resource pdata.Resource) string { | |
if ecs { | ||
return OriginECS | ||
} | ||
return OriginEC2 | ||
_, ec2 := resource.Attributes().Get(semconventions.AttributeHostID) | ||
if ec2 { | ||
return OriginEC2 | ||
} | ||
return "" | ||
} | ||
|
||
// convertToAmazonTraceID converts a trace ID to the Amazon format. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As these are destined to be replaced by constants anyways, I'd go ahead and have private constants like
AttributeCloudInfrastructureService
defined in this fileThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair, will replace