[repo] Cleanup shared code (#5622)

This commit is contained in:
Piotr Kiełkowicz 2024-05-17 21:17:13 +02:00 committed by GitHub
parent 1e065cbdaa
commit b444464d0f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 10 additions and 750 deletions

View File

@ -242,7 +242,6 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}"
ProjectSection(SolutionItems) = preProject
src\Shared\ActivityHelperExtensions.cs = src\Shared\ActivityHelperExtensions.cs
src\Shared\ActivityInstrumentationHelper.cs = src\Shared\ActivityInstrumentationHelper.cs
src\Shared\AssemblyVersionExtensions.cs = src\Shared\AssemblyVersionExtensions.cs
src\Shared\DiagnosticDefinitions.cs = src\Shared\DiagnosticDefinitions.cs
src\Shared\ExceptionExtensions.cs = src\Shared\ExceptionExtensions.cs
@ -251,7 +250,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A49299
src\Shared\PeerServiceResolver.cs = src\Shared\PeerServiceResolver.cs
src\Shared\PeriodicExportingMetricReaderHelper.cs = src\Shared\PeriodicExportingMetricReaderHelper.cs
src\Shared\PooledList.cs = src\Shared\PooledList.cs
src\Shared\RedactionHelper.cs = src\Shared\RedactionHelper.cs
src\Shared\ResourceSemanticConventions.cs = src\Shared\ResourceSemanticConventions.cs
src\Shared\SemanticConventions.cs = src\Shared\SemanticConventions.cs
src\Shared\SpanAttributeConstants.cs = src\Shared\SpanAttributeConstants.cs
@ -259,11 +257,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A49299
src\Shared\ThreadSafeRandom.cs = src\Shared\ThreadSafeRandom.cs
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DiagnosticSourceInstrumentation", "DiagnosticSourceInstrumentation", "{28F3EC79-660C-4659-8B73-F90DC1173316}"
ProjectSection(SolutionItems) = preProject
src\Shared\DiagnosticSourceInstrumentation\PropertyFetcher.cs = src\Shared\DiagnosticSourceInstrumentation\PropertyFetcher.cs
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EnvironmentVariables", "EnvironmentVariables", "{6D4B4FB2-0A8A-4044-948B-C063FD340439}"
ProjectSection(SolutionItems) = preProject
src\Shared\EnvironmentVariables\EnvironmentVariablesConfigurationProvider.cs = src\Shared\EnvironmentVariables\EnvironmentVariablesConfigurationProvider.cs
@ -640,7 +633,6 @@ Global
{800DB925-6014-4136-AC01-3356CF7CADD3} = {5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818}
{9C99621C-343E-479C-A943-332DB6129B71} = {5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818}
{62AF4BD3-DCAE-4D44-AA5B-991C1071166B} = {5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818}
{28F3EC79-660C-4659-8B73-F90DC1173316} = {A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}
{6D4B4FB2-0A8A-4044-948B-C063FD340439} = {A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}
{494902DD-C63F-48E0-BED3-B58EFB4051C8} = {A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}
{A0CB9A10-F22D-4E66-A449-74B3D0361A9C} = {A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}

View File

@ -1,24 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
namespace OpenTelemetry.Instrumentation;
internal static class ActivityInstrumentationHelper
{
internal static readonly Action<Activity, ActivityKind> SetKindProperty = CreateActivityKindSetter();
internal static readonly Action<Activity, ActivitySource> SetActivitySourceProperty = CreateActivitySourceSetter();
private static Action<Activity, ActivitySource> CreateActivitySourceSetter()
{
return (Action<Activity, ActivitySource>)typeof(Activity).GetProperty("Source")
.SetMethod.CreateDelegate(typeof(Action<Activity, ActivitySource>));
}
private static Action<Activity, ActivityKind> CreateActivityKindSetter()
{
return (Action<Activity, ActivityKind>)typeof(Activity).GetProperty("Kind")
.SetMethod.CreateDelegate(typeof(Action<Activity, ActivityKind>));
}
}

View File

@ -1,218 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#nullable enable
#if NETSTANDARD2_1_0_OR_GREATER || NET6_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
#endif
using System.Reflection;
namespace OpenTelemetry.Instrumentation;
/// <summary>
/// PropertyFetcher fetches a property from an object.
/// </summary>
/// <typeparam name="T">The type of the property being fetched.</typeparam>
internal sealed class PropertyFetcher<T>
{
#if NET6_0_OR_GREATER
private const string TrimCompatibilityMessage = "PropertyFetcher is used to access properties on objects dynamically by design and cannot be made trim compatible.";
#endif
private readonly string propertyName;
private PropertyFetch? innerFetcher;
/// <summary>
/// Initializes a new instance of the <see cref="PropertyFetcher{T}"/> class.
/// </summary>
/// <param name="propertyName">Property name to fetch.</param>
public PropertyFetcher(string propertyName)
{
this.propertyName = propertyName;
}
public int NumberOfInnerFetchers => this.innerFetcher == null
? 0
: 1 + this.innerFetcher.NumberOfInnerFetchers;
/// <summary>
/// Try to fetch the property from the object.
/// </summary>
/// <param name="obj">Object to be fetched.</param>
/// <param name="value">Fetched value.</param>
/// <returns><see langword= "true"/> if the property was fetched.</returns>
#if NET6_0_OR_GREATER
[RequiresUnreferencedCode(TrimCompatibilityMessage)]
#endif
public bool TryFetch(
#if NETSTANDARD2_1_0_OR_GREATER || NET6_0_OR_GREATER
[NotNullWhen(true)]
#endif
object? obj,
out T? value)
{
var innerFetcher = this.innerFetcher;
if (innerFetcher is null)
{
return TryFetchRare(obj, this.propertyName, ref this.innerFetcher, out value);
}
return innerFetcher.TryFetch(obj, out value);
}
#if NET6_0_OR_GREATER
[RequiresUnreferencedCode(TrimCompatibilityMessage)]
#endif
private static bool TryFetchRare(object? obj, string propertyName, ref PropertyFetch? destination, out T? value)
{
if (obj is null)
{
value = default;
return false;
}
var fetcher = PropertyFetch.Create(obj.GetType().GetTypeInfo(), propertyName);
if (fetcher is null)
{
value = default;
return false;
}
destination = fetcher;
return fetcher.TryFetch(obj, out value);
}
// see https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagnosticSourceEventSource.cs
#if NET6_0_OR_GREATER
[RequiresUnreferencedCode(TrimCompatibilityMessage)]
#endif
private abstract class PropertyFetch
{
public abstract int NumberOfInnerFetchers { get; }
public static PropertyFetch? Create(TypeInfo type, string propertyName)
{
var property = type.DeclaredProperties.FirstOrDefault(p => string.Equals(p.Name, propertyName, StringComparison.OrdinalIgnoreCase)) ?? type.GetProperty(propertyName);
return CreateFetcherForProperty(property);
static PropertyFetch? CreateFetcherForProperty(PropertyInfo? propertyInfo)
{
if (propertyInfo == null || !typeof(T).IsAssignableFrom(propertyInfo.PropertyType))
{
// returns null and wait for a valid payload to arrive.
return null;
}
var declaringType = propertyInfo.DeclaringType;
if (declaringType!.IsValueType)
{
throw new NotSupportedException(
$"Type: {declaringType.FullName} is a value type. PropertyFetcher can only operate on reference payload types.");
}
if (declaringType == typeof(object))
{
// TODO: REMOVE this if branch when .NET 7 is out of support.
// This branch is never executed and is only needed for .NET 7 AOT-compiler at trimming stage; i.e.,
// this is not needed in .NET 8, because the compiler is improved and call into MakeGenericMethod will be AOT-compatible.
// It is used to force the AOT compiler to create an instantiation of the method with a reference type.
// The code for that instantiation can then be reused at runtime to create instantiation over any other reference.
return CreateInstantiated<object>(propertyInfo);
}
else
{
return DynamicInstantiationHelper(declaringType, propertyInfo);
}
// Separated as a local function to be able to target the suppression to just this call.
// IL3050 was generated here because of the call to MakeGenericType, which is problematic in AOT if one of the type parameters is a value type;
// because the compiler might need to generate code specific to that type.
// If the type parameter is a reference type, there will be no problem; because the generated code can be shared among all reference type instantiations.
#if NET6_0_OR_GREATER
[UnconditionalSuppressMessage("AOT", "IL3050", Justification = "The code guarantees that all the generic parameters are reference types.")]
#endif
static PropertyFetch? DynamicInstantiationHelper(Type declaringType, PropertyInfo propertyInfo)
{
return (PropertyFetch?)typeof(PropertyFetch)
.GetMethod(nameof(CreateInstantiated), BindingFlags.NonPublic | BindingFlags.Static)!
.MakeGenericMethod(declaringType) // This is validated in the earlier call chain to be a reference type.
.Invoke(null, new object[] { propertyInfo })!;
}
}
}
public abstract bool TryFetch(
#if NETSTANDARD2_1_0_OR_GREATER || NET6_0_OR_GREATER
[NotNullWhen(true)]
#endif
object? obj,
out T? value);
// Goal: make PropertyFetcher AOT-compatible.
// AOT compiler can't guarantee correctness when call into MakeGenericType or MakeGenericMethod
// if one of the generic parameters is a value type (reference types are OK.)
// For PropertyFetcher, the decision was made to only support reference type payloads, i.e.:
// the object from which to get the property value MUST be a reference type.
// Create generics with the declared object type as a generic parameter is OK, but we need the return type
// of the property to be a value type (on top of reference types.)
// Normally, we would have a helper class like `PropertyFetchInstantiated` that takes 2 generic parameters,
// the declared object type, and the type of the property value.
// But that would mean calling MakeGenericType, with value type parameters which AOT won't support.
//
// As a workaround, Generic instantiation was split into:
// 1. The object type comes from the PropertyFetcher generic parameter.
// Compiler supports it even if it is a value type; the type is known statically during compilation
// since PropertyFetcher is used with it.
// 2. Then, the declared object type is passed as a generic parameter to a generic method on PropertyFetcher<T> (or nested type.)
// Therefore, calling into MakeGenericMethod will only require specifying one parameter - the declared object type.
// The declared object type is guaranteed to be a reference type (throw on value type.) Thus, MakeGenericMethod is AOT compatible.
private static PropertyFetch CreateInstantiated<TDeclaredObject>(PropertyInfo propertyInfo)
where TDeclaredObject : class
=> new PropertyFetchInstantiated<TDeclaredObject>(propertyInfo);
#if NET6_0_OR_GREATER
[RequiresUnreferencedCode(TrimCompatibilityMessage)]
#endif
private sealed class PropertyFetchInstantiated<TDeclaredObject> : PropertyFetch
where TDeclaredObject : class
{
private readonly string propertyName;
private readonly Func<TDeclaredObject, T> propertyFetch;
private PropertyFetch? innerFetcher;
public PropertyFetchInstantiated(PropertyInfo property)
{
this.propertyName = property.Name;
this.propertyFetch = (Func<TDeclaredObject, T>)property.GetMethod!.CreateDelegate(typeof(Func<TDeclaredObject, T>));
}
public override int NumberOfInnerFetchers => this.innerFetcher == null
? 0
: 1 + this.innerFetcher.NumberOfInnerFetchers;
public override bool TryFetch(
#if NETSTANDARD2_1_0_OR_GREATER || NET6_0_OR_GREATER
[NotNullWhen(true)]
#endif
object? obj,
out T? value)
{
if (obj is TDeclaredObject o)
{
value = this.propertyFetch(o);
return true;
}
var innerFetcher = this.innerFetcher;
if (innerFetcher is null)
{
return TryFetchRare(obj, this.propertyName, ref this.innerFetcher, out value);
}
return innerFetcher.TryFetch(obj, out value);
}
}
}
}

View File

@ -1,59 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#nullable enable
using System.Text;
namespace OpenTelemetry.Internal;
internal class RedactionHelper
{
private static readonly string RedactedText = "Redacted";
public static string? GetRedactedQueryString(string query)
{
int length = query.Length;
int index = 0;
// Preallocate some size to avoid re-sizing multiple times.
// Since the size will increase, allocating twice as much.
// TODO: Check to see if we can borrow from https://github.com/dotnet/runtime/blob/main/src/libraries/Common/src/System/Text/ValueStringBuilder.cs
// to improve perf.
StringBuilder queryBuilder = new(2 * length);
while (index < query.Length)
{
// Check if the character is = for redacting value.
if (query[index] == '=')
{
// Append =
queryBuilder.Append('=');
index++;
// Append redactedText in place of original value.
queryBuilder.Append(RedactedText);
// Move until end of this key/value pair.
while (index < length && query[index] != '&')
{
index++;
}
// End of key/value.
if (index < length && query[index] == '&')
{
queryBuilder.Append(query[index]);
}
}
else
{
// Keep adding to the result
queryBuilder.Append(query[index]);
}
index++;
}
return queryBuilder.ToString();
}
}

View File

@ -15,47 +15,4 @@ internal static class ResourceSemanticConventions
public const string AttributeTelemetrySdkName = "telemetry.sdk.name";
public const string AttributeTelemetrySdkLanguage = "telemetry.sdk.language";
public const string AttributeTelemetrySdkVersion = "telemetry.sdk.version";
public const string AttributeContainerName = "container.name";
public const string AttributeContainerImage = "container.image.name";
public const string AttributeContainerTag = "container.image.tag";
public const string AttributeFaasName = "faas.name";
public const string AttributeFaasId = "faas.id";
public const string AttributeFaasVersion = "faas.version";
public const string AttributeFaasInstance = "faas.instance";
public const string AttributeK8sCluster = "k8s.cluster.name";
public const string AttributeK8sNamespace = "k8s.namespace.name";
public const string AttributeK8sPod = "k8s.pod.name";
public const string AttributeK8sDeployment = "k8s.deployment.name";
public const string AttributeHostHostname = "host.hostname";
public const string AttributeHostId = "host.id";
public const string AttributeHostName = "host.name";
public const string AttributeHostType = "host.type";
public const string AttributeHostImageName = "host.image.name";
public const string AttributeHostImageId = "host.image.id";
public const string AttributeHostImageVersion = "host.image.version";
public const string AttributeProcessId = "process.id";
public const string AttributeProcessExecutableName = "process.executable.name";
public const string AttributeProcessExecutablePath = "process.executable.path";
public const string AttributeProcessCommand = "process.command";
public const string AttributeProcessCommandLine = "process.command_line";
public const string AttributeProcessUsername = "process.username";
public const string AttributeCloudAccount = "cloud.account.id";
public const string AttributeCloudPlatform = "cloud.platform";
public const string AttributeCloudProvider = "cloud.provider";
public const string AttributeCloudRegion = "cloud.region";
public const string AttributeCloudResourceId = "cloud.resource_id";
public const string AttributeCloudZone = "cloud.zone";
public const string AttributeComponent = "component";
public const string AttributeOsType = "os.type";
public const string AttributeOsVersion = "os.version";
public const string AttributeDeploymentEnvironment = "deployment.environment";
}

View File

@ -7,116 +7,23 @@ namespace OpenTelemetry.Trace;
/// <summary>
/// Constants for semantic attribute names outlined by the OpenTelemetry specifications.
/// <see href="https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/trace.md"/> and
/// <see href="https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/metrics.md"/>.
/// </summary>
internal static class SemanticConventions
{
// The set of constants matches the specification as of this commit.
// https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/trace.md
// https://github.com/open-telemetry/semantic-conventions/blob/main/docs/exceptions/exceptions-spans.md
public const string AttributeNetTransport = "net.transport";
public const string AttributeNetPeerIp = "net.peer.ip";
public const string AttributeNetPeerPort = "net.peer.port";
public const string AttributeNetPeerName = "net.peer.name";
public const string AttributeNetHostIp = "net.host.ip";
public const string AttributeNetHostPort = "net.host.port";
public const string AttributeNetHostName = "net.host.name";
public const string AttributeEnduserId = "enduser.id";
public const string AttributeEnduserRole = "enduser.role";
public const string AttributeEnduserScope = "enduser.scope";
public const string AttributePeerService = "peer.service";
public const string AttributeHttpMethod = "http.method";
public const string AttributeHttpUrl = "http.url";
public const string AttributeHttpTarget = "http.target";
public const string AttributeHttpHost = "http.host";
public const string AttributeHttpScheme = "http.scheme";
public const string AttributeHttpStatusCode = "http.status_code";
public const string AttributeHttpStatusText = "http.status_text";
public const string AttributeHttpFlavor = "http.flavor";
public const string AttributeHttpServerName = "http.server_name";
public const string AttributeHttpRoute = "http.route";
public const string AttributeHttpClientIP = "http.client_ip";
public const string AttributeHttpUserAgent = "http.user_agent";
public const string AttributeHttpRequestContentLength = "http.request_content_length";
public const string AttributeHttpRequestContentLengthUncompressed = "http.request_content_length_uncompressed";
public const string AttributeHttpResponseContentLength = "http.response_content_length";
public const string AttributeHttpResponseContentLengthUncompressed = "http.response_content_length_uncompressed";
public const string AttributeDbSystem = "db.system";
public const string AttributeDbConnectionString = "db.connection_string";
public const string AttributeDbUser = "db.user";
public const string AttributeDbMsSqlInstanceName = "db.mssql.instance_name";
public const string AttributeDbJdbcDriverClassName = "db.jdbc.driver_classname";
public const string AttributeDbName = "db.name";
public const string AttributeDbStatement = "db.statement";
public const string AttributeDbOperation = "db.operation";
public const string AttributeDbInstance = "db.instance";
public const string AttributeDbUrl = "db.url";
public const string AttributeDbCassandraKeyspace = "db.cassandra.keyspace";
public const string AttributeDbHBaseNamespace = "db.hbase.namespace";
public const string AttributeDbRedisDatabaseIndex = "db.redis.database_index";
public const string AttributeDbMongoDbCollection = "db.mongodb.collection";
public const string AttributeRpcSystem = "rpc.system";
public const string AttributeRpcService = "rpc.service";
public const string AttributeRpcMethod = "rpc.method";
public const string AttributeRpcGrpcStatusCode = "rpc.grpc.status_code";
public const string AttributeMessageType = "message.type";
public const string AttributeMessageId = "message.id";
public const string AttributeMessageCompressedSize = "message.compressed_size";
public const string AttributeMessageUncompressedSize = "message.uncompressed_size";
public const string AttributeFaasTrigger = "faas.trigger";
public const string AttributeFaasExecution = "faas.execution";
public const string AttributeFaasDocumentCollection = "faas.document.collection";
public const string AttributeFaasDocumentOperation = "faas.document.operation";
public const string AttributeFaasDocumentTime = "faas.document.time";
public const string AttributeFaasDocumentName = "faas.document.name";
public const string AttributeFaasTime = "faas.time";
public const string AttributeFaasCron = "faas.cron";
public const string AttributeMessagingSystem = "messaging.system";
public const string AttributeMessagingDestination = "messaging.destination";
public const string AttributeMessagingDestinationKind = "messaging.destination_kind";
public const string AttributeMessagingTempDestination = "messaging.temp_destination";
public const string AttributeMessagingProtocol = "messaging.protocol";
public const string AttributeMessagingProtocolVersion = "messaging.protocol_version";
public const string AttributeMessagingUrl = "messaging.url";
public const string AttributeMessagingMessageId = "messaging.message_id";
public const string AttributeMessagingConversationId = "messaging.conversation_id";
public const string AttributeMessagingPayloadSize = "messaging.message_payload_size_bytes";
public const string AttributeMessagingPayloadCompressedSize = "messaging.message_payload_compressed_size_bytes";
public const string AttributeMessagingOperation = "messaging.operation";
public const string AttributeExceptionEventName = "exception";
public const string AttributeExceptionType = "exception.type";
public const string AttributeExceptionMessage = "exception.message";
public const string AttributeExceptionStacktrace = "exception.stacktrace";
public const string AttributeErrorType = "error.type";
// v1.21.0
// https://github.com/open-telemetry/semantic-conventions/blob/v1.21.0/docs/database/database-spans.md
public const string AttributeServerSocketAddress = "server.socket.address"; // replaces: "net.peer.ip" (AttributeNetPeerIp)
// v1.23.0
// https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/http/http-spans.md
public const string AttributeClientAddress = "client.address";
public const string AttributeClientPort = "client.port";
public const string AttributeHttpRequestMethod = "http.request.method"; // replaces: "http.method" (AttributeHttpMethod)
public const string AttributeHttpRequestMethodOriginal = "http.request.method_original";
public const string AttributeHttpResponseStatusCode = "http.response.status_code"; // replaces: "http.status_code" (AttributeHttpStatusCode)
public const string AttributeNetworkProtocolVersion = "network.protocol.version"; // replaces: "http.flavor" (AttributeHttpFlavor)
public const string AttributeNetworkProtocolName = "network.protocol.name";
public const string AttributeServerAddress = "server.address"; // replaces: "net.host.name" (AttributeNetHostName) and "net.peer.name" (AttributeNetPeerName)
public const string AttributeServerPort = "server.port"; // replaces: "net.host.port" (AttributeNetHostPort) and "net.peer.port" (AttributeNetPeerPort)
public const string AttributeUrlFull = "url.full"; // replaces: "http.url" (AttributeHttpUrl)
public const string AttributeUrlPath = "url.path"; // replaces: "http.target" (AttributeHttpTarget)
public const string AttributeUrlQuery = "url.query";
public const string AttributeUrlScheme = "url.scheme"; // replaces: "http.scheme" (AttributeHttpScheme)
public const string AttributeUserAgentOriginal = "user_agent.original"; // replaces: "http.user_agent" (AttributeHttpUserAgent)
}

View File

@ -8,10 +8,6 @@
<SelfContained>true</SelfContained>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(RepoRoot)\src\Shared\DiagnosticSourceInstrumentation\PropertyFetcher.cs" Link="Includes\PropertyFetcher.cs" />
</ItemGroup>
<ItemGroup>
<TrimmerRootAssembly Include="OpenTelemetry.Api.ProviderBuilderExtensions" />
<TrimmerRootAssembly Include="OpenTelemetry.Api" />

View File

@ -1,17 +1,4 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
using OpenTelemetry.AotCompatibility.TestApp;
try
{
PropertyFetcherAotTest.Test();
}
catch (Exception ex)
{
Console.WriteLine(ex);
return -1;
}
Console.WriteLine("Passed.");
return 0;

View File

@ -1,56 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics.CodeAnalysis;
using OpenTelemetry.Instrumentation;
namespace OpenTelemetry.AotCompatibility.TestApp;
internal class PropertyFetcherAotTest
{
[UnconditionalSuppressMessage("", "IL2026", Justification = "Property presence guaranteed by explicit hints.")]
public static void Test()
{
var fetcher = new PropertyFetcher<BaseType>("Property");
GuaranteeProperties<PayloadTypeWithBaseType>();
var r = fetcher.TryFetch(new PayloadTypeWithBaseType(), out var value);
Assert(r, "TryFetch base did not return true.");
Assert(value!.GetType() == typeof(DerivedType), "TryFetch base value is not a derived type.");
GuaranteeProperties<PayloadTypeWithDerivedType>();
r = fetcher.TryFetch(new PayloadTypeWithDerivedType(), out value);
Assert(r, "TryFetch derived did not return true.");
Assert(value!.GetType() == typeof(DerivedType), "TryFetch derived value is not a derived type.");
}
private static void GuaranteeProperties<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>()
{
}
private static void Assert(bool condition, string message)
{
if (!condition)
{
throw new InvalidOperationException(message);
}
}
private class BaseType
{
}
private class DerivedType : BaseType
{
}
private class PayloadTypeWithBaseType
{
public BaseType Property { get; set; } = new DerivedType();
}
private class PayloadTypeWithDerivedType
{
public DerivedType Property { get; set; } = new DerivedType();
}
}

View File

@ -1,39 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using Xunit;
namespace OpenTelemetry.Instrumentation.Tests;
public class ActivityInstrumentationHelperTest
{
[Theory]
[InlineData("TestActivitySource", null)]
[InlineData("TestActivitySource", "1.0.0")]
public void SetActivitySource(string name, string version)
{
using var activity = new Activity("Test");
using var activitySource = new ActivitySource(name, version);
activity.Start();
ActivityInstrumentationHelper.SetActivitySourceProperty(activity, activitySource);
Assert.Equal(activitySource.Name, activity.Source.Name);
Assert.Equal(activitySource.Version, activity.Source.Version);
activity.Stop();
}
[Theory]
[InlineData(ActivityKind.Client)]
[InlineData(ActivityKind.Consumer)]
[InlineData(ActivityKind.Internal)]
[InlineData(ActivityKind.Producer)]
[InlineData(ActivityKind.Server)]
public void SetActivityKind(ActivityKind activityKind)
{
using var activity = new Activity("Test");
activity.Start();
ActivityInstrumentationHelper.SetKindProperty(activity, activityKind);
Assert.Equal(activityKind, activity.Kind);
}
}

View File

@ -1,155 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using Xunit;
namespace OpenTelemetry.Instrumentation.Tests;
public class PropertyFetcherTest
{
[Fact]
public void FetchValidProperty()
{
using var activity = new Activity("test");
var fetch = new PropertyFetcher<string>("DisplayName");
Assert.Equal(0, fetch.NumberOfInnerFetchers);
Assert.True(fetch.TryFetch(activity, out string result));
Assert.Equal(activity.DisplayName, result);
Assert.Equal(1, fetch.NumberOfInnerFetchers);
Assert.True(fetch.TryFetch(activity, out result));
Assert.Equal(activity.DisplayName, result);
Assert.Equal(1, fetch.NumberOfInnerFetchers);
}
[Fact]
public void FetchInvalidProperty()
{
using var activity = new Activity("test");
var fetch = new PropertyFetcher<string>("DisplayName2");
Assert.False(fetch.TryFetch(activity, out string result));
var fetchInt = new PropertyFetcher<int>("DisplayName2");
Assert.False(fetchInt.TryFetch(activity, out int resultInt));
Assert.Equal(default, result);
Assert.Equal(default, resultInt);
}
[Fact]
public void FetchNullProperty()
{
var fetch = new PropertyFetcher<string>("null");
Assert.False(fetch.TryFetch(null, out _));
}
[Fact]
public void FetchPropertyMultiplePayloadTypes()
{
var fetch = new PropertyFetcher<string>("Property");
Assert.Equal(0, fetch.NumberOfInnerFetchers);
Assert.True(fetch.TryFetch(new PayloadTypeA(), out string propertyValue));
Assert.Equal("A", propertyValue);
Assert.Equal(1, fetch.NumberOfInnerFetchers);
Assert.True(fetch.TryFetch(new PayloadTypeB(), out propertyValue));
Assert.Equal("B", propertyValue);
Assert.Equal(2, fetch.NumberOfInnerFetchers);
Assert.False(fetch.TryFetch(new PayloadTypeC(), out _));
Assert.Equal(2, fetch.NumberOfInnerFetchers);
Assert.False(fetch.TryFetch(null, out _));
Assert.Equal(2, fetch.NumberOfInnerFetchers);
}
[Fact]
public void FetchPropertyMultiplePayloadTypes_IgnoreTypesWithoutExpectedPropertyName()
{
var fetch = new PropertyFetcher<string>("Property");
Assert.False(fetch.TryFetch(new PayloadTypeC(), out _));
Assert.True(fetch.TryFetch(new PayloadTypeA(), out string propertyValue));
Assert.Equal("A", propertyValue);
}
[Fact]
public void FetchPropertyWithDerivedInstanceType()
{
var fetch = new PropertyFetcher<BaseType>("Property");
Assert.True(fetch.TryFetch(new PayloadTypeWithBaseType(), out BaseType value));
Assert.IsType<DerivedType>(value);
}
[Fact]
public void FetchPropertyWithDerivedDeclaredType()
{
var fetch = new PropertyFetcher<BaseType>("Property");
Assert.True(fetch.TryFetch(new PayloadTypeWithDerivedType(), out BaseType value));
Assert.IsType<DerivedType>(value);
}
[Fact]
public void FetchPropertyWhenPayloadIsValueType()
{
var fetch = new PropertyFetcher<BaseType>("Property");
var ex = Assert.Throws<NotSupportedException>(() => fetch.TryFetch(new PayloadTypeIsValueType(), out BaseType value));
Assert.Contains("PropertyFetcher can only operate on reference payload types.", ex.Message);
}
private struct PayloadTypeIsValueType
{
public PayloadTypeIsValueType()
{
}
public DerivedType Property { get; set; } = new DerivedType();
}
private class PayloadTypeA
{
public string Property { get; set; } = "A";
}
private class PayloadTypeB
{
public string Property { get; set; } = "B";
}
private class PayloadTypeC
{
}
private class BaseType
{
}
private class DerivedType : BaseType
{
}
private class PayloadTypeWithBaseType
{
public BaseType Property { get; set; } = new DerivedType();
}
private class PayloadTypeWithDerivedType
{
public DerivedType Property { get; set; } = new DerivedType();
}
}

View File

@ -1,32 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
using OpenTelemetry.Internal;
using Xunit;
namespace OpenTelemetry.Tests.Internal;
public class RedactionHelperTest
{
[Theory]
[InlineData("?a", "?a")]
[InlineData("?a=b", "?a=Redacted")]
[InlineData("?a=b&", "?a=Redacted&")]
[InlineData("?c=b&", "?c=Redacted&")]
[InlineData("?c=a", "?c=Redacted")]
[InlineData("?a=b&c", "?a=Redacted&c")]
[InlineData("?a=b&c=1&", "?a=Redacted&c=Redacted&")]
[InlineData("?a=b&c=1&a1", "?a=Redacted&c=Redacted&a1")]
[InlineData("?a=b&c=1&a1=", "?a=Redacted&c=Redacted&a1=Redacted")]
[InlineData("?a=b&c=11&a1=&", "?a=Redacted&c=Redacted&a1=Redacted&")]
[InlineData("?c&c&c&", "?c&c&c&")]
[InlineData("?a&a&a&a", "?a&a&a&a")]
[InlineData("?&&&&&&&", "?&&&&&&&")]
[InlineData("?c", "?c")]
[InlineData("?=c", "?=Redacted")]
[InlineData("?=c&=", "?=Redacted&=Redacted")]
public void QueryStringIsRedacted(string input, string expected)
{
Assert.Equal(expected, RedactionHelper.GetRedactedQueryString(input));
}
}

View File

@ -19,11 +19,8 @@
</ItemGroup>
<ItemGroup>
<Compile Include="$(RepoRoot)\src\Shared\ActivityInstrumentationHelper.cs" Link="Includes\ActivityInstrumentationHelper.cs" />
<Compile Include="$(RepoRoot)\src\Shared\DiagnosticSourceInstrumentation\PropertyFetcher.cs" Link="Includes\PropertyFetcher.cs" />
<Compile Include="$(RepoRoot)\src\Shared\Metrics\Base2ExponentialBucketHistogramHelper.cs" Link="Includes\Metrics\Base2ExponentialBucketHistogramHelper.cs" />
<Compile Include="$(RepoRoot)\src\Shared\PeriodicExportingMetricReaderHelper.cs" Link="Includes\PeriodicExportingMetricReaderHelper.cs" />
<Compile Include="$(RepoRoot)\src\Shared\RedactionHelper.cs" Link="Includes\RedactionHelper.cs" />
<Compile Include="$(RepoRoot)\src\Shared\PooledList.cs" Link="Includes\PooledList.cs" />
<Compile Include="$(RepoRoot)\src\Shared\TagWriter\*.cs" Link="Includes\TagWriter\%(Filename).cs" />
</ItemGroup>

View File

@ -4,7 +4,6 @@
using System.Diagnostics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Instrumentation;
using OpenTelemetry.Resources;
using OpenTelemetry.Resources.Tests;
using OpenTelemetry.Tests;
@ -14,6 +13,8 @@ namespace OpenTelemetry.Trace.Tests;
public class TracerProviderSdkTest : IDisposable
{
private static readonly Action<Activity, ActivitySource> SetActivitySourceProperty = CreateActivitySourceSetter();
public TracerProviderSdkTest()
{
Activity.DefaultIdFormat = ActivityIdFormat.W3C;
@ -639,7 +640,7 @@ public class TracerProviderSdkTest : IDisposable
using var activity = new Activity(operationNameForLegacyActivity);
activity.Start();
ActivityInstrumentationHelper.SetActivitySourceProperty(activity, activitySourceForLegacyActivity);
SetActivitySourceProperty(activity, activitySourceForLegacyActivity);
activity.Stop();
Assert.True(startCalled); // Processor.OnStart is called since we provided the legacy OperationName
@ -690,7 +691,7 @@ public class TracerProviderSdkTest : IDisposable
using var activity = new Activity(operationNameForLegacyActivity);
activity.Start();
ActivityInstrumentationHelper.SetActivitySourceProperty(activity, activitySourceForLegacyActivity);
SetActivitySourceProperty(activity, activitySourceForLegacyActivity);
activity.Stop();
Assert.True(startCalled); // Processor.OnStart is called since we provided the legacy OperationName
@ -1297,6 +1298,12 @@ public class TracerProviderSdkTest : IDisposable
GC.SuppressFinalize(this);
}
private static Action<Activity, ActivitySource> CreateActivitySourceSetter()
{
return (Action<Activity, ActivitySource>)typeof(Activity).GetProperty("Source")
.SetMethod.CreateDelegate(typeof(Action<Activity, ActivitySource>));
}
private sealed class TestTracerProviderBuilder : TracerProviderBuilderBase
{
public TracerProviderBuilder AddInstrumentation()