Skip to content
Merged
3 changes: 2 additions & 1 deletion build/Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ Copyright The OpenTelemetry Authors under Apache License Version 2.0
DotNetBuild(s => s
.SetProjectFile(project)
.SetNoRestore(true)
.SetConfiguration(this.configuration));
.SetConfiguration(this.configuration)
.SetProperty("TreatWarningsAsErrors", "true"));
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
<PropertyGroup>
<TargetFramework>netcoreapp8.0</TargetFramework>
<RootNamespace>integration_test_app</RootNamespace>
<!-- Suppress StyleCop rules for test applications:
SA0001: XML comment analysis disabled (test apps don't need XML documentation)
SA1300: Element naming (test namespace uses underscores by convention) -->
<NoWarn>$(NoWarn);SA0001;SA1300</NoWarn>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AWSSDK.S3" Version="3.7.304" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<Nullable>enable</Nullable>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../../buildtools/awsoteldotnet.snk</AssemblyOriginatorKeyFile>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net462'">
Expand All @@ -33,7 +34,7 @@
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.11.1" />
<PackageReference Include="OpenTelemetry.Sampler.AWS" Version="0.1.0-alpha.3" />
<PackageReference Include="OpenTelemetry.SemanticConventions" Version="1.0.0-rc9.9" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ internal AWSOpenTelemetryOptions(IConfiguration configuration)
{
// custom implementation of initializing exporter settings / instrumentations / Service Name etc.
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace AWS.Distro.OpenTelemetry.AutoInstrumentation;
[EventSource(Name = "OpenTelemetry-AWS-XRay")]
internal class AWSXRayEventSource : EventSource
{
internal static readonly AWSXRayEventSource Log = new ();
internal static readonly AWSXRayEventSource Log = new();

[NonEvent]
public void ActivityContextExtractException(string format, Exception ex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
namespace AWS.Distro.OpenTelemetry.AutoInstrumentation;

/// <summary>
/// This sampler will return the sampling result of the provided {@link #rootSampler}, unless the
/// This sampler will return the sampling result of the provided rootSampler, unless the
/// sampling result contains the sampling decision <see cref="SamplingDecision.Drop"/>, in which case, a
/// new sampling result will be returned that is functionally equivalent to the original, except that
/// it contains the sampling decision <see cref="SamplingDecision.RecordOnly"/>. This ensures that all
/// spans are recorded, with no change to sampling.
///
/// <p>The intended use case of this sampler is to provide a means of sending all spans to a
/// The intended use case of this sampler is to provide a means of sending all spans to a
/// processor without having an impact on the sampling rate. This may be desirable if a user wishes
/// to count or otherwise measure all spans produced in a service, without incurring the cost of 100%
/// sampling.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,20 @@ private AttributePropagatingSpanProcessorBuilder()
{
}

/// <summary>
/// Creates a new AttributePropagatingSpanProcessorBuilder instance.
/// </summary>
/// <returns>A new builder instance.</returns>
public static AttributePropagatingSpanProcessorBuilder Create()
{
return new AttributePropagatingSpanProcessorBuilder();
}

/// <summary>
/// Sets the propagation data extractor function.
/// </summary>
/// <param name="propagationDataExtractor">Function to extract propagation data from activity.</param>
/// <returns>This builder instance.</returns>
public AttributePropagatingSpanProcessorBuilder SetPropagationDataExtractor(Func<Activity, string> propagationDataExtractor)
{
if (propagationDataExtractor == null)
Expand All @@ -41,6 +50,11 @@ public AttributePropagatingSpanProcessorBuilder SetPropagationDataExtractor(Func
return this;
}

/// <summary>
/// Sets the propagation data key.
/// </summary>
/// <param name="propagationDataKey">The key for propagation data.</param>
/// <returns>This builder instance.</returns>
public AttributePropagatingSpanProcessorBuilder SetPropagationDataKey(string propagationDataKey)
{
if (propagationDataKey == null)
Expand All @@ -52,6 +66,11 @@ public AttributePropagatingSpanProcessorBuilder SetPropagationDataKey(string pro
return this;
}

/// <summary>
/// Sets the attribute keys to propagate.
/// </summary>
/// <param name="attributesKeysToPropagate">List of attribute keys to propagate.</param>
/// <returns>This builder instance.</returns>
public AttributePropagatingSpanProcessorBuilder SetAttributesKeysToPropagate(List<string> attributesKeysToPropagate)
{
if (attributesKeysToPropagate == null)
Expand All @@ -64,6 +83,10 @@ public AttributePropagatingSpanProcessorBuilder SetAttributesKeysToPropagate(Lis
return this;
}

/// <summary>
/// Builds the AttributePropagatingSpanProcessor.
/// </summary>
/// <returns>The configured processor.</returns>
public AttributePropagatingSpanProcessor Build()
{
return AttributePropagatingSpanProcessor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ public override void OnEnd(Activity data)
this.OnExport(data);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ namespace AWS.Distro.OpenTelemetry.AutoInstrumentation;
/// <summary>
/// AwsMetricAttributeGenerator generates very specific metric attributes based on low-cardinality
/// span and resource attributes. If such attributes are not present, we fallback to default values.
/// <p>The goal of these particular metric attributes is to get metrics for incoming and outgoing
/// The goal of these particular metric attributes is to get metrics for incoming and outgoing
/// traffic for a service. Namely, <see cref="SpanKind.Server"/> and <see cref="SpanKind.Consumer"/> spans
/// represent "incoming" traffic, {<see cref="SpanKind.Client"/> and <see cref="SpanKind.Producer"/> spans
/// represent "incoming" traffic, <see cref="SpanKind.Client"/> and <see cref="SpanKind.Producer"/> spans
/// represent "outgoing" traffic, and <see cref="SpanKind.Internal"/> spans are ignored.
/// </summary>
internal class AwsMetricAttributeGenerator : IMetricAttributeGenerator
Expand Down Expand Up @@ -169,28 +169,28 @@ private static void SetEgressOperation(Activity span, ActivityTagsCollection att
/// instrumented span attributes, and are clear indications of customer intent. If AWS Remote
/// attributes are not present, the next highest priority span attribute is Peer Service, which is
/// also a reliable indicator of customer intent. If this is set, it will override
/// AWS_REMOTE_SERVICE identified from any other span attribute, other than AWS Remote attributes.
/// AWS_REMOTE_SERVICE identified from any other span attribute, other than AWS Remote attributes.</p>
///
/// <p>After this, we look for the following low-cardinality span attributes that can be used to
/// determine the remote metric attributes:
/// determine the remote metric attributes:</p>
///
/// <ul>
/// <li>RPC
/// <li>DB
/// <li>FAAS
/// <li>Messaging
/// <li>RPC</li>
/// <li>DB</li>
/// <li>FAAS</li>
/// <li>Messaging</li>
/// <li>GraphQL - Special case, if <see cref="AttributeGraphqlOperationType"/> is present,
/// we use it for RemoteOperation and set RemoteService to <see cref="GraphQL"/>.
/// we use it for RemoteOperation and set RemoteService to <see cref="GraphQL"/>.</li>
/// </ul>
///
/// <p>In each case, these span attributes were selected from the OpenTelemetry trace semantic
/// convention specifications as they adhere to the three following criteria:
/// convention specifications as they adhere to the three following criteria:</p>
///
/// <ul>
/// <li>Attributes are meaningfully indicative of remote service/operation names.
/// <li>Attributes are meaningfully indicative of remote service/operation names.</li>
/// <li>Attributes are defined in the specification to be low cardinality, usually with a low-
/// cardinality list of values.
/// <li>Attributes are confirmed to have low-cardinality values, based on code analysis.
/// cardinality list of values.</li>
/// <li>Attributes are confirmed to have low-cardinality values, based on code analysis.</li>
/// </ul>
///
/// if the selected attributes are still producing the UnknownRemoteService or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,18 @@ private static Activity WrapSpanWithAttributes(Activity span, ActivityTagsCollec
return span;
}

/// <summary>
/// If the map has no items, no modifications are required. If there is one item, it means the
/// span either produces Service or Dependency metric attributes, and in either case we want to
/// modify the span with them. If there are two items, the span produces both Service and
/// Dependency metric attributes indicating the span is a local dependency root. The Service
/// Attributes must be a subset of the Dependency, with the exception of AttributeAWSSpanKind. The
/// knowledge that the span is a local root is more important that knowing that it is a
/// Dependency metric, so we take all the Dependency metrics but replace AttributeAWSSpanKind with
/// <see cref="AwsSpanProcessingUtil.LocalRoot"/>.
/// </summary>
private Activity AddMetricAttributes(Activity span)
{
/// If the map has no items, no modifications are required. If there is one item, it means the
/// span either produces Service or Dependency metric attributes, and in either case we want to
/// modify the span with them. If there are two items, the span produces both Service and
/// Dependency metric attributes indicating the span is a local dependency root. The Service
/// Attributes must be a subset of the Dependency, with the exception of AttributeAWSSpanKind. The
/// knowledge that the span is a local root is more important that knowing that it is a
/// Dependency metric, so we take all the Dependency metrics but replace AttributeAWSSpanKind with
/// <see cref="AwsSpanProcessingUtil.LocalRoot"/>.
Dictionary<string, ActivityTagsCollection> attributeMap =
this.generator.GenerateMetricAttributeMapFromSpan(span, this.resource);
ActivityTagsCollection attributes = new ActivityTagsCollection();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ private static bool IsSqsReceiveMessageConsumerSpan(Activity span)
string? serviceName = (string?)span.GetTagItem(AttributeAWSServiceName);

return !string.IsNullOrEmpty(serviceName)
&& serviceName.Equals(SQSService)
&& SQSService.Equals(serviceName)
&& ActivityKind.Consumer.Equals(spanKind)
&& spanActivitySource != null
&& spanActivitySource.Name.StartsWith(ActivitySourceName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace AWS.Distro.OpenTelemetry.AutoInstrumentation;
/// <summary>
/// Metric attribute generator defines an interface for classes that can generate specific attributes
/// to be used by an <see cref="AwsSpanMetricsProcessor"/> to produce metrics and by
/// <see cref="AwsMetricAttributesSpanExporter"/> to wrap the original span.
/// AwsMetricAttributesSpanExporter to wrap the original span.
/// </summary>
public interface IMetricAttributeGenerator
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ static LambdaWrapper()
/// The following are assumptions made about the lambda handler function parameters.
/// * Maximum Parameters: A .NET Lambda handler function can have up to two parameters.
/// * Parameter Order: If both parameters are used, the event input parameter must come first, followed by the ILambdaContext.
/// * Return Types: The handler can return void, a specific type, or a Task/Task<T> for asynchronous methods.
/// * Return Types: The handler can return void, a specific type, or a Task/Task[T] for asynchronous methods.
/// </summary>
/// <param name="input"></param>
/// <param name="context"></param>
/// <returns></returns>
/// <param name="input">Input JObject to be converted to the correct object type.</param>
/// <param name="context">Lambda context for the function execution.</param>
/// <returns>Task containing the result object from the original handler.</returns>
/// <exception cref="Exception">Multiple exceptions that act as safe gaurds in case any of the
/// assumptions are wrong or if for any reason reflection is failing to get the original function and it's info.</exception>
private async Task<object?> FunctionHandler(JObject input, ILambdaContext context)
Expand Down Expand Up @@ -154,7 +154,7 @@ static LambdaWrapper()
}
}

private (MethodInfo, object) ExtractOriginalHandler()
private (MethodInfo HandlerMethod, object HandlerInstance) ExtractOriginalHandler()
{
string? originalHandler = Environment.GetEnvironmentVariable("OTEL_INSTRUMENTATION_AWS_LAMBDA_HANDLER");
if (string.IsNullOrEmpty(originalHandler))
Expand Down Expand Up @@ -188,4 +188,4 @@ static LambdaWrapper()
return (handlerMethod, handlerInstance);
}
}
#endif
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -359,11 +359,11 @@ public void ConfigureTracesOptions(HttpClientTraceInstrumentationOptions options
#endif
}

#if !NETFRAMEWORK
/// <summary>
/// Used to call ShouldSampleParent function
/// </summary>
/// <param name="options"><see cref="AspNetCoreTraceInstrumentationOptions"/> options to configure</param>
#if !NETFRAMEWORK
public void ConfigureTracesOptions(AspNetCoreTraceInstrumentationOptions options)
{
options.EnrichWithHttpRequest = (activity, request) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,46 @@

namespace AWS.Distro.OpenTelemetry.AutoInstrumentation;

/// <summary>
/// Parser for AWS regional resource ARNs.
/// </summary>
public class RegionalResourceArnParser
{
/// <summary>
/// Gets the account ID from an AWS ARN.
/// </summary>
/// <param name="arn">The ARN to parse.</param>
/// <returns>The account ID or null if not found.</returns>
public static string? GetAccountId(string? arn) => ParseArn(arn)?[4];

/// <summary>
/// Gets the region from an AWS ARN.
/// </summary>
/// <param name="arn">The ARN to parse.</param>
/// <returns>The region or null if not found.</returns>
public static string? GetRegion(string? arn) => ParseArn(arn)?[3];

/// <summary>
/// Extracts the Kinesis stream name from an ARN.
/// </summary>
/// <param name="arn">The Kinesis stream ARN.</param>
/// <returns>The stream name or null if not found.</returns>
public static string? ExtractKinesisStreamNameFromArn(string? arn) =>
ExtractResourceNameFromArn(arn)?.Replace("stream/", string.Empty);

/// <summary>
/// Extracts the DynamoDB table name from an ARN.
/// </summary>
/// <param name="arn">The DynamoDB table ARN.</param>
/// <returns>The table name or null if not found.</returns>
public static string? ExtractDynamoDbTableNameFromArn(string? arn) =>
ExtractResourceNameFromArn(arn)?.Replace("table/", string.Empty);

/// <summary>
/// Extracts the resource name from an AWS ARN.
/// </summary>
/// <param name="arn">The ARN to parse.</param>
/// <returns>The resource name or null if not found.</returns>
public static string? ExtractResourceNameFromArn(string? arn) =>
ParseArn(arn) is var parts && parts != null ? parts[parts.Length - 1] : null;

Expand All @@ -23,7 +51,7 @@ public class RegionalResourceArnParser
/// arn:partition:service:region:account-id:resource-type/resource-id or
/// arn:partition:service:region:account-id:resource-type:resource-id
/// </summary>
private static string[] ? ParseArn(string? arn)
private static string[]? ParseArn(string? arn)
{
if (arn == null || !arn.StartsWith("arn:"))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,26 @@ public class SqsUrlParser
return null;
}

public static string? GetAccountId(string? url) => ParseUrl(url).accountId;
/// <summary>
/// Gets the account ID from an SQS URL.
/// </summary>
/// <param name="url">The SQS URL to parse.</param>
/// <returns>The account ID or null if not found.</returns>
public static string? GetAccountId(string? url) => ParseUrl(url).AccountId;

public static string? GetRegion(string? url) => ParseUrl(url).region;
/// <summary>
/// Gets the region from an SQS URL.
/// </summary>
/// <param name="url">The SQS URL to parse.</param>
/// <returns>The region or null if not found.</returns>
public static string? GetRegion(string? url) => ParseUrl(url).Region;

/// <summary>
/// Parses new SQS URLs https://sqs.region.amazonaws.com/accountI/queueName;
/// </summary>
/// <param name="url">SQS URL to parse</param>
/// <returns>Tuple containing queue name, account ID, and region</returns>
public static (string? QueueName, string? accountId, string? region) ParseUrl(string? url)
public static (string? QueueName, string? AccountId, string? Region) ParseUrl(string? url)
{
if (url == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@
<AssemblyOriginatorKeyFile>../../buildtools/awsoteldotnet.snk</AssemblyOriginatorKeyFile>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<!-- Suppress warnings for test projects:
CS8002: Unsigned assembly references (test projects can reference unsigned packages)
SA0001: XML comment analysis disabled (test projects don't need XML documentation)
SA1204: Element ordering (test helper classes can appear in any order)
SA1300: Element naming (test namespace uses underscores by convention)
SA1402: Multiple types per file (test helper classes are acceptable) -->
<NoWarn>$(NoWarn);CS8002;SA0001;SA1204;SA1300;SA1402</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand All @@ -27,7 +34,7 @@
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.11.2" />
<PackageReference Include="OpenTelemetry.SemanticConventions" Version="1.0.0-rc9.9" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,4 @@ public void CheckThatUnSampledActivityIsProcessed()
Assert.Equal(0, (long)droppedCount);
}
}
}
}
Loading
Loading