Skip to content

Commit

Permalink
Merge pull request #3344 from aws/muhamoth/DOTNET-7517-Observability-…
Browse files Browse the repository at this point in the history
…Add-Observability-APIs-to-the-SDK

Add Observability APIs to the SDK and add telemetry provider reference to AWSConfigs and ClientConfig
  • Loading branch information
muhammad-othman authored Jun 20, 2024
2 parents 39f95d3 + c31588a commit a692e9e
Show file tree
Hide file tree
Showing 30 changed files with 1,401 additions and 0 deletions.
15 changes: 15 additions & 0 deletions sdk/src/Core/AWSConfigs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
using Amazon.Util.Internal;
using System.Collections.Generic;
using Amazon.Runtime;
using Amazon.Runtime.Telemetry;

namespace Amazon
{
Expand Down Expand Up @@ -90,6 +91,7 @@ public static partial class AWSConfigs
// for reading from awsconfigs.xml
private static object _lock = new object();
private static List<string> standardConfigs = new List<string>() { "region", "logging", "correctForClockSkew" };
private static TelemetryProvider _telemetryProvider = new DefaultTelemetryProvider();

#pragma warning disable 414
private static bool configPresent = true;
Expand Down Expand Up @@ -474,6 +476,19 @@ public static bool UseAlternateUserAgentHeader
set { _rootConfig.UseAlternateUserAgentHeader = value; }
}

/// <summary>
/// Gets or sets the global <see cref="TelemetryProvider"/> instance.
/// <para>
/// This global telemetry provider is used to collect and report telemetry data
/// (such as traces and metrics) for all AWS SDK operations.
/// </para>
/// </summary>
public static TelemetryProvider TelemetryProvider
{
get { return _telemetryProvider; }
set { _telemetryProvider = value; }
}

/// <summary>
/// Configuration for the region endpoint section of AWS configuration.
/// Changes may not take effect until a new client is constructed.
Expand Down
17 changes: 17 additions & 0 deletions sdk/src/Core/Amazon.Runtime/ClientConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
using System.ComponentModel.Design;
using Amazon.Runtime.CredentialManagement;
using Amazon.Runtime.Internal.Settings;
using Amazon.Runtime.Telemetry;

#if NETSTANDARD
using System.Runtime.InteropServices;
Expand Down Expand Up @@ -93,6 +94,7 @@ public abstract partial class ClientConfig : IClientConfig
private const long DefaultMinCompressionSizeBytes = 10240;
private bool didProcessServiceURL = false;
private IAWSTokenProvider _awsTokenProvider = new DefaultAWSTokenProviderChain();
private TelemetryProvider telemetryProvider = AWSConfigs.TelemetryProvider;

private CredentialProfileStoreChain credentialProfileStoreChain;
#if BCL
Expand Down Expand Up @@ -1239,5 +1241,20 @@ public TimeSpan? ReadWriteTimeout
/// but can be changed to use custom user supplied EndpointProvider.
/// </summary>
public IEndpointProvider EndpointProvider { get; set; }

/// <summary>
/// Gets or sets the <see cref="TelemetryProvider"/> instance for this client configuration.
/// <para>
/// This telemetry provider is used to collect and report telemetry data
/// (such as traces and metrics) for operations performed by this specific client.
/// If this property is not explicitly set, it will default to the global
/// <see cref="AWSConfigs.TelemetryProvider"/>.
/// </para>
/// </summary>
public TelemetryProvider TelemetryProvider
{
get { return this.telemetryProvider; }
set { this.telemetryProvider = value; }
}
}
}
11 changes: 11 additions & 0 deletions sdk/src/Core/Amazon.Runtime/IClientConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using Amazon.Runtime.Endpoints;
using Amazon.Runtime.Internal.Auth;
using Amazon.Util;
using Amazon.Runtime.Telemetry;
#if NETSTANDARD
using System.Net.Http;
#endif
Expand Down Expand Up @@ -369,6 +370,16 @@ public partial interface IClientConfig
/// which doesn't allow to specify the User-Agent header.
/// </summary>
bool UseAlternateUserAgentHeader { get; }

/// <summary>
/// <para>
/// This telemetry provider is used to collect and report telemetry data
/// (such as traces and metrics) for operations performed by this specific client.
/// If this property is not explicitly set, it will default to the global
/// <see cref="AWSConfigs.TelemetryProvider"/>.
/// </para>
/// </summary>
TelemetryProvider TelemetryProvider { get; }
#if BCL
/// <summary>
/// Gets the TCP keep-alive values to use for service requests. Enabling TCP keep-alive sends periodic TCP keep-alive probe packets, to prevent disconnection due to
Expand Down
93 changes: 93 additions & 0 deletions sdk/src/Core/Amazon.Runtime/Telemetry/Attributes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

using System.Collections.Generic;

namespace Amazon.Runtime.Telemetry
{
/// <summary>
/// Represents a collection of attributes used for telemetry purposes.
/// Attributes are key-value pairs where the key is a string and the value is an object.
/// These attributes provide additional information for spans and metrics in telemetry data.
/// </summary>
public class Attributes
{
private readonly Dictionary<string, object> _attributes;

/// <summary>
/// Initializes a new instance of the <see cref="Attributes"/> class.
/// </summary>
public Attributes()
{
_attributes = new Dictionary<string, object>();
}

/// <summary>
/// Initializes a new instance of the <see cref="Attributes"/> class.
/// If duplicate keys are present in the provided collection, the value of the last occurrence of the key will be used.
/// </summary>
/// <param name="attributes">An optional initial set of attributes to populate the collection.
/// If duplicate keys are found, the last value will override previous ones.</param>
public Attributes(IEnumerable<KeyValuePair<string, object>> attributes)
{
_attributes = new Dictionary<string, object>();

foreach (var kvp in attributes)
{
_attributes[kvp.Key] = kvp.Value;
}
}

/// <summary>
/// Sets the value for the given attribute key.
/// If the key already exists, the value is updated.
/// </summary>
/// <param name="key">The key of the attribute.</param>
/// <param name="value">The value of the attribute.</param>
public void Set(string key, object value)
{
_attributes[key] = value;
}

/// <summary>
/// Gets the value for the given attribute key.
/// </summary>
/// <param name="key">The attribute key.</param>
/// <returns>The attribute value, or null if the key does not exist.</returns>
public object Get(string key)
{
_attributes.TryGetValue(key, out var value);
return value;
}

/// <summary>
/// Removes the attribute with the specified key.
/// </summary>
/// <param name="key">The attribute key.</param>
/// <returns>True if the attribute was successfully removed; otherwise, false.</returns>
public bool Remove(string key)
{
return _attributes.Remove(key);
}

/// <summary>
/// Gets the collection of all the attributes.
/// </summary>
public IEnumerable<KeyValuePair<string, object>> AllAttributes
{
get { return _attributes; }
}
}
}
73 changes: 73 additions & 0 deletions sdk/src/Core/Amazon.Runtime/Telemetry/DefaultTelemetryProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

using Amazon.Runtime.Telemetry.Metrics;
using Amazon.Runtime.Telemetry.Metrics.NoOp;
using Amazon.Runtime.Telemetry.Tracing;
using Amazon.Runtime.Telemetry.Tracing.NoOp;

namespace Amazon.Runtime.Telemetry
{
/// <summary>
/// Default implementation of <see cref="TelemetryProvider"/> that uses no-op providers by default.
/// </summary>
public class DefaultTelemetryProvider : TelemetryProvider
{
/// <summary>
/// Initializes a new instance of the <see cref="DefaultTelemetryProvider"/> class with no-op providers.
/// This setup prevents any telemetry actions from being performed unless explicitly registered using the
/// registration methods.
/// </summary>
public DefaultTelemetryProvider()
{
TracerProvider = new NoOpTracerProvider();
MeterProvider = new NoOpMeterProvider();
}

/// <summary>
/// Gets the <see cref="TracerProvider"/> used to create new tracers.
/// This property is initialized with a no-op implementation by default.
/// </summary>
public override TracerProvider TracerProvider { get; protected set; }

/// <summary>
/// Gets the <see cref="MeterProvider"/> used to create new metrics.
/// This property is initialized with a no-op implementation by default.
/// </summary>
public override MeterProvider MeterProvider { get; protected set; }

/// <summary>
/// Registers a new <see cref="TracerProvider"/>.
/// This method sets a custom tracer provider to replace the default no-op provider,
/// enabling the collection of tracing data.
/// </summary>
/// <param name="tracerProvider">The tracer provider to register.</param>
public override void RegisterTracerProvider(TracerProvider tracerProvider)
{
TracerProvider = tracerProvider;
}

/// <summary>
/// Registers a new <see cref="MeterProvider"/>.
/// This method sets a custom meter provider to replace the default no-op provider,
/// enabling the collection of metrics data.
/// </summary>
/// <param name="meterProvider">The meter provider to register.</param>
public override void RegisterMeterProvider(MeterProvider meterProvider)
{
MeterProvider = meterProvider;
}
}
}
34 changes: 34 additions & 0 deletions sdk/src/Core/Amazon.Runtime/Telemetry/Metrics/AsyncMeasurement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

namespace Amazon.Runtime.Telemetry.Metrics
{
/// <summary>
/// Represents an async measurement.
/// An async measurement records values, such as periodically or based on events.
/// The generic type parameter T specifies the type of value being recorded, such as int, long, etc.
/// </summary>
/// <typeparam name="T">The type of value being measured.</typeparam>
public abstract class AsyncMeasurement<T> where T : struct
{
/// <summary>
/// Records a value.
/// This method is called to record a measurement value.
/// </summary>
/// <param name="value">The value to be recorded. This value is of type T.</param>
/// <param name="attributes">Optional attributes associated with the measurement.</param>
public abstract void Record(T value, Attributes attributes = null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

namespace Amazon.Runtime.Telemetry.Metrics
{
/// <summary>
/// Represents a handle for async measurements.
/// The handle is used to manage and stop the async recording of measurements.
/// </summary>
/// <typeparam name="T">The type of value being measured.</typeparam>
public abstract class AsyncMeasurementHandle<T> where T : struct
{
/// <summary>
/// Gets the meter that created this handle.
/// </summary>
public Meter Meter { get; protected set; }

/// <summary>
/// Initializes a new instance of the <see cref="AsyncMeasurementHandle{T}"/> class.
/// </summary>
/// <param name="meter">The meter that created this handle.</param>
protected AsyncMeasurementHandle(Meter meter)
{
Meter = meter;
}
}
}
33 changes: 33 additions & 0 deletions sdk/src/Core/Amazon.Runtime/Telemetry/Metrics/Histogram.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

namespace Amazon.Runtime.Telemetry.Metrics
{
/// <summary>
/// Abstract class representing a histogram used to record values of a specified type.
/// A histogram is a type of metric instrument that tracks the distribution of values.
/// </summary>
/// <typeparam name="T">The type of the histogram value. Must be a struct.</typeparam>
public abstract class Histogram<T> where T : struct
{
/// <summary>
/// Records a value in the histogram.
/// </summary>
/// <param name="value">The value to record. This represents a measurement or observation.</param>
/// <param name="attributes">Optional attributes associated with the measurement. These can be used to
/// provide additional context or dimensions to the recorded value.</param>
public abstract void Record(T value, Attributes attributes = null);
}
}
Loading

0 comments on commit a692e9e

Please sign in to comment.