Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ internal static CallTargetState OnMethodBegin<TTarget, TExecutionContext>(TTarge
if (scope?.Span.Tags is AwsSdkTags tags)
{
tags.Region = executionContext.RequestContext?.ClientConfig?.RegionEndpoint?.SystemName;
bool isOutbound = (tags.SpanKind == SpanKinds.Client) || (tags.SpanKind == SpanKinds.Producer);
if (isOutbound)
{
tags = PeerServiceHelpers.DerivePeerService(tags);
}

Tracer.Instance.CurrentTraceSettings.Schema.RemapPeerService(tags);
}

return new CallTargetState(scope, state: executionContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ internal static CallTargetState OnMethodBegin<TTarget, TExecutionContext>(TTarge
if (scope?.Span.Tags is AwsSdkTags tags)
{
tags.Region = executionContext.RequestContext?.ClientConfig?.RegionEndpoint?.SystemName;
bool isOutbound = (tags.SpanKind == SpanKinds.Client) || (tags.SpanKind == SpanKinds.Producer);
if (isOutbound)
{
tags = PeerServiceHelpers.DerivePeerService(tags);
}

Tracer.Instance.CurrentTraceSettings.Schema.RemapPeerService(tags);
}

return new CallTargetState(scope, state: executionContext);
Expand Down
134 changes: 134 additions & 0 deletions tracer/src/Datadog.Trace/Util/PeerServiceHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// <copyright file="PeerServiceHelpers.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>

#nullable enable

using Datadog.Trace.Tagging;

namespace Datadog.Trace.Util
{
/// <summary>
/// Helper to set peer.service and peer.service.source tags
/// </summary>
internal static class PeerServiceHelpers
{
/// <summary>
/// Sets peer.service tag for AwsSdk spans based on the service, environment, and region
/// </summary>
/// <param name="tags">AwsSdkTags for the current span</param>
public static AwsSdkTags DerivePeerService(AwsSdkTags tags)
{
var service = tags.AwsService;
var region = tags.Region;
var isAwsLambda = EnvironmentHelpers.IsAwsLambda();
if (isAwsLambda && tags.Region != null)
{
switch (service)
{
case "DynamoDB":
tags.PeerService = "dynamodb." + region + ".amazonaws.com";
break;
case "EventBridge":
tags.PeerService = "events." + region + ".amazonaws.com";
break;
case "Kinesis":
tags.PeerService = "kinesis." + region + ".amazonaws.com";
break;
case "S3":
var s3Tags = (AwsS3Tags)tags;
if (s3Tags.BucketName != null)
{
tags.PeerService = s3Tags.BucketName + ".s3." + region + ".amazonaws.com";
}
else
{
tags.PeerService = "s3." + region + ".amazonaws.com";
}

break;
case "SNS":
tags.PeerService = "sns." + region + ".amazonaws.com";
break;
case "SQS":
tags.PeerService = "sqs." + region + ".amazonaws.com";
break;
}

tags.PeerServiceSource = "peer.service";
}
else if (!isAwsLambda)
{
switch (service)
{
case "DynamoDB":
if (tags is AwsDynamoDbTags)
{
var dbTags = (AwsDynamoDbTags)tags;
tags.PeerService = dbTags.TableName;
tags.PeerServiceSource = Trace.Tags.TableName;
}

break;
case "EventBridge":
if (tags is AwsEventBridgeTags)
{
var eventTags = (AwsEventBridgeTags)tags;
tags.PeerService = eventTags.RuleName;
tags.PeerServiceSource = Trace.Tags.RuleName;
}

break;
case "Kinesis":
if (tags is AwsKinesisTags)
{
var kinesisTags = (AwsKinesisTags)tags;
tags.PeerService = kinesisTags.StreamName;
tags.PeerServiceSource = Trace.Tags.StreamName;
}

break;
case "S3":
if (tags is AwsS3Tags)
{
var s3Tags = (AwsS3Tags)tags;
tags.PeerService = s3Tags.BucketName;
tags.PeerServiceSource = Trace.Tags.BucketName;
}

break;
case "SNS":
if (tags is AwsSnsTags)
{
var snsTags = (AwsSnsTags)tags;
tags.PeerService = snsTags.TopicName;
tags.PeerServiceSource = Trace.Tags.TopicName;
}

break;
case "SQS":
if (tags is AwsSqsTags)
{
var sqsTags = (AwsSqsTags)tags;
tags.PeerService = sqsTags.QueueName;
tags.PeerServiceSource = Trace.Tags.QueueName;
}

break;
case "StepFunctions":
if (tags is AwsStepFunctionsTags)
{
var stepTags = (AwsStepFunctionsTags)tags;
tags.PeerService = stepTags.StateMachineName;
tags.PeerServiceSource = Trace.Tags.StateMachineName;
}

break;
}
}

return tags;
}
}
}
18 changes: 9 additions & 9 deletions tracer/test/Datadog.Trace.TestHelpers/SpanMetadataAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,23 +66,23 @@ public static Result IsAspNetCoreMvc(this MockSpan span, string metadataSchemaVe

public static Result IsAwsS3Request(this MockSpan span) => span.IsAwsS3RequestV0();

public static Result IsAwsSqsInbound(this MockSpan span) => span.IsAwsSqsRequestV0();
public static Result IsAwsSqsInbound(this MockSpan span) => span.IsAwsSqsInboundV0();

public static Result IsAwsSqsOutbound(this MockSpan span) => span.IsAwsSqsRequestV0();
public static Result IsAwsSqsOutbound(this MockSpan span) => span.IsAwsSqsOutboundV0();

public static Result IsAwsSqsRequest(this MockSpan span) => span.IsAwsSqsRequestV0();
public static Result IsAwsSqsRequest(this MockSpan span) => span.IsAwsSqsOutboundV0();

public static Result IsAwsSnsInbound(this MockSpan span) => span.IsAwsSnsRequestV0();
public static Result IsAwsSnsInbound(this MockSpan span) => span.IsAwsSnsInboundV0();

public static Result IsAwsSnsOutbound(this MockSpan span) => span.IsAwsSnsRequestV0();
public static Result IsAwsSnsOutbound(this MockSpan span) => span.IsAwsSnsOutboundV0();

public static Result IsAwsSnsRequest(this MockSpan span) => span.IsAwsSnsRequestV0();
public static Result IsAwsSnsRequest(this MockSpan span) => span.IsAwsSnsOutboundV0();

public static Result IsAwsEventBridgeInbound(this MockSpan span) => span.IsAwsEventBridgeRequestV0();
public static Result IsAwsEventBridgeInbound(this MockSpan span) => span.IsAwsEventBridgeInboundV0();

public static Result IsAwsEventBridgeOutbound(this MockSpan span) => span.IsAwsEventBridgeRequestV0();
public static Result IsAwsEventBridgeOutbound(this MockSpan span) => span.IsAwsEventBridgeOutboundV0();

public static Result IsAwsEventBridgeRequest(this MockSpan span) => span.IsAwsEventBridgeRequestV0();
public static Result IsAwsEventBridgeRequest(this MockSpan span) => span.IsAwsEventBridgeOutboundV0();

public static Result IsAwsStepFunctionsInbound(this MockSpan span) => span.IsAwsStepFunctionsRequestV0();

Expand Down
86 changes: 82 additions & 4 deletions tracer/test/Datadog.Trace.TestHelpers/SpanMetadataV0Rules.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ public static Result IsAwsDynamoDbV0(this MockSpan span) => Result.FromSpan(span
.IsPresent("http.method")
.IsPresent("http.status_code")
.IsPresent("http.url")
.IsPresent("peer.service")
.IsPresent("_dd.peer.service.source")
.Matches("component", "aws-sdk")
.IsOptional("_dd.base_service")
.Matches("span.kind", "client"));
Expand All @@ -167,6 +169,8 @@ public static Result IsAwsKinesisOutboundV0(this MockSpan span) => Result.FromSp
.IsPresent("http.method")
.IsPresent("http.status_code")
.IsPresent("http.url")
.IsPresent("peer.service")
.IsPresent("_dd.peer.service.source")
.Matches("component", "aws-sdk")
.IsOptional("_dd.base_service")
.Matches("span.kind", "producer"));
Expand All @@ -188,11 +192,13 @@ public static Result IsAwsS3RequestV0(this MockSpan span) => Result.FromSpan(spa
.IsPresent("http.method")
.IsPresent("http.status_code")
.IsPresent("http.url")
.IsPresent("peer.service")
.IsPresent("_dd.peer.service.source")
.IsOptional("_dd.base_service")
.Matches("component", "aws-sdk")
.Matches("span.kind", "client"));

public static Result IsAwsSqsRequestV0(this MockSpan span) => Result.FromSpan(span)
public static Result IsAwsSqsInboundV0(this MockSpan span) => Result.FromSpan(span)
.Properties(s => s
.Matches(Name, "sqs.request")
.Matches(Type, "http"))
Expand All @@ -212,9 +218,33 @@ public static Result IsAwsSqsRequestV0(this MockSpan span) => Result.FromSpan(sp
.IsPresent("http.url")
.IsOptional("_dd.base_service")
.Matches("component", "aws-sdk")
.MatchesOneOf("span.kind", "producer", "client", "consumer"));
.Matches("span.kind", "consumer"));

public static Result IsAwsSnsRequestV0(this MockSpan span) => Result.FromSpan(span)
public static Result IsAwsSqsOutboundV0(this MockSpan span) => Result.FromSpan(span)
.Properties(s => s
.Matches(Name, "sqs.request")
.Matches(Type, "http"))
.Tags(s => s
.Matches("aws.agent", "dotnet-aws-sdk")
.IsPresent("aws.operation")
.IsOptional("aws.region")
.IsOptional("region")
.IsPresent("aws.requestId")
.Matches("aws.service", "SQS")
.Matches("aws_service", "SQS")
.IsPresent("aws.queue.name")
.IsPresent("queuename")
.IsOptional("aws.queue.url")
.IsPresent("http.method")
.IsPresent("http.status_code")
.IsPresent("http.url")
.IsPresent("peer.service")
.IsPresent("_dd.peer.service.source")
.IsOptional("_dd.base_service")
.Matches("component", "aws-sdk")
.MatchesOneOf("span.kind", "producer", "client"));

public static Result IsAwsSnsInboundV0(this MockSpan span) => Result.FromSpan(span)
.Properties(s => s
.Matches(Name, "sns.request")
.Matches(Type, "http"))
Expand All @@ -234,9 +264,53 @@ public static Result IsAwsSnsRequestV0(this MockSpan span) => Result.FromSpan(sp
.IsPresent("http.url")
.IsOptional("_dd.base_service")
.Matches("component", "aws-sdk")
.Matches("span.kind", "consumer"));

public static Result IsAwsSnsOutboundV0(this MockSpan span) => Result.FromSpan(span)
.Properties(s => s
.Matches(Name, "sns.request")
.Matches(Type, "http"))
.Tags(s => s
.Matches("aws.agent", "dotnet-aws-sdk")
.IsPresent("aws.operation")
.IsOptional("aws.region")
.IsOptional("region")
.IsPresent("aws.requestId")
.Matches("aws.service", "SNS")
.Matches("aws_service", "SNS")
.IsPresent("aws.topic.name")
.IsPresent("topicname")
.IsOptional("aws.topic.arn")
.IsPresent("http.method")
.IsPresent("http.status_code")
.IsPresent("http.url")
.IsPresent("peer.service")
.IsPresent("_dd.peer.service.source")
.IsOptional("_dd.base_service")
.Matches("component", "aws-sdk")
.MatchesOneOf("span.kind", "producer", "client"));

public static Result IsAwsEventBridgeRequestV0(this MockSpan span) => Result.FromSpan(span)
public static Result IsAwsEventBridgeInboundV0(this MockSpan span) => Result.FromSpan(span)
.Properties(s => s
.Matches(Name, "eventbridge.request")
.Matches(Type, "http"))
.Tags(s => s
.Matches("aws.agent", "dotnet-aws-sdk")
.IsPresent("aws.operation")
.IsOptional("aws.region")
.IsOptional("region")
.IsPresent("aws.requestId")
.Matches("aws.service", "EventBridge")
.Matches("aws_service", "EventBridge")
.IsPresent("rulename")
.IsPresent("http.method")
.IsPresent("http.status_code")
.IsPresent("http.url")
.IsOptional("_dd.base_service")
.Matches("component", "aws-sdk")
.Matches("span.kind", "consumer"));

public static Result IsAwsEventBridgeOutboundV0(this MockSpan span) => Result.FromSpan(span)
.Properties(s => s
.Matches(Name, "eventbridge.request")
.Matches(Type, "http"))
Expand All @@ -252,6 +326,8 @@ public static Result IsAwsEventBridgeRequestV0(this MockSpan span) => Result.Fro
.IsPresent("http.method")
.IsPresent("http.status_code")
.IsPresent("http.url")
.IsPresent("peer.service")
.IsPresent("_dd.peer.service.source")
.IsOptional("_dd.base_service")
.Matches("component", "aws-sdk")
.MatchesOneOf("span.kind", "producer", "client"));
Expand All @@ -272,6 +348,8 @@ public static Result IsAwsStepFunctionsRequestV0(this MockSpan span) => Result.F
.IsPresent("http.method")
.IsPresent("http.status_code")
.IsPresent("http.url")
.IsOptional("peer.service")
.IsOptional("_dd.peer.service.source")
.IsOptional("_dd.base_service")
.Matches("component", "aws-sdk")
.Matches("span.kind", "producer"));
Expand Down
Loading
Loading