Skip to content
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

Fix AOT warnings in StackExchangeRedis #1415

Merged
merged 2 commits into from
Oct 31, 2023
Merged
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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ jobs:
|| contains(needs.detect-changes.outputs.changes, 'azure')
|| contains(needs.detect-changes.outputs.changes, 'aottestapp')
|| contains(needs.detect-changes.outputs.changes, 'build')
|| contains(needs.detect-changes.outputs.changes, 'redis')
|| contains(needs.detect-changes.outputs.changes, 'shared')
uses: ./.github/workflows/verifyaotcompat.yml

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#nullable enable
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentation
OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentation.AddConnection(StackExchange.Redis.IConnectionMultiplexer! connection) -> System.IDisposable!
OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentation.AddConnection(string! name, StackExchange.Redis.IConnectionMultiplexer! connection) -> System.IDisposable!
OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentation.Dispose() -> void
OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentationOptions
OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentationOptions.Enrich.get -> System.Action<System.Diagnostics.Activity!, StackExchange.Redis.Profiling.IProfiledCommand!>?
OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentationOptions.Enrich.set -> void
OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentationOptions.EnrichActivityWithTimingEvents.get -> bool
OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentationOptions.EnrichActivityWithTimingEvents.set -> void
OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentationOptions.FlushInterval.get -> System.TimeSpan
OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentationOptions.FlushInterval.set -> void
OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentationOptions.SetVerboseDatabaseStatements.get -> bool
OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentationOptions.SetVerboseDatabaseStatements.set -> void
OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentationOptions.StackExchangeRedisInstrumentationOptions() -> void
OpenTelemetry.Trace.TracerProviderBuilderExtensions
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddRedisInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! builder) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddRedisInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! builder, StackExchange.Redis.IConnectionMultiplexer! connection) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddRedisInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! builder, StackExchange.Redis.IConnectionMultiplexer! connection, System.Action<OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentationOptions!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddRedisInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! builder, string? name, StackExchange.Redis.IConnectionMultiplexer? connection, System.Action<OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentationOptions!>? configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddRedisInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! builder, System.Action<OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentationOptions!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureRedisInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! builder, System.Action<OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentation!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureRedisInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! builder, System.Action<System.IServiceProvider!, OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisInstrumentation!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
* Update OTel API version to `1.6.0`.
([#1344](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/1344))

* Add `net6.0` target framework and make library AOT and trimming compatible
([#1415](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/1415))

## 1.0.0-rc9.10

Released 2023-Jun-09
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,21 @@
using System.Reflection.Emit;
using OpenTelemetry.Trace;
using StackExchange.Redis.Profiling;
#if NET6_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
#endif

namespace OpenTelemetry.Instrumentation.StackExchangeRedis.Implementation;

internal static class RedisProfilerEntryToActivityConverter
{
private const string ScriptEvalMessageTypeName = "StackExchange.Redis.RedisDatabase+ScriptEvalMessage";

private static readonly Lazy<Func<object, (string?, string?)>> MessageDataGetter = new(() =>
{
var redisAssembly = typeof(IProfiledCommand).Assembly;
Type profiledCommandType = redisAssembly.GetType("StackExchange.Redis.Profiling.ProfiledCommand");
Type scriptMessageType = redisAssembly.GetType("StackExchange.Redis.RedisDatabase+ScriptEvalMessage");
Type profiledCommandType = Type.GetType("StackExchange.Redis.Profiling.ProfiledCommand, StackExchange.Redis", throwOnError: true)!;
Type scriptMessageType = Type.GetType(ScriptEvalMessageTypeName + ", StackExchange.Redis", throwOnError: true)!;

var messageDelegate = CreateFieldGetter<object>(profiledCommandType, "Message", BindingFlags.NonPublic | BindingFlags.Instance);
var scriptDelegate = CreateFieldGetter<string>(scriptMessageType, "script", BindingFlags.NonPublic | BindingFlags.Instance);
Expand Down Expand Up @@ -59,12 +64,27 @@ internal static class RedisProfilerEntryToActivityConverter
script = scriptDelegate?.Invoke(message);
}

if (commandAndKeyFetcher.TryFetch(message, out var value))
if (GetCommandAndKey(commandAndKeyFetcher, message, out var value))
{
return (value, script);
}

return (null, script);

#if NET6_0_OR_GREATER
[DynamicDependency("CommandAndKey", ScriptEvalMessageTypeName, "StackExchange.Redis")]
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "The CommandAndKey property is preserved by the above DynamicDependency")]
#endif
static bool GetCommandAndKey(
PropertyFetcher<string> commandAndKeyFetcher,
object message,
#if NET6_0_OR_GREATER
[NotNullWhen(true)]
#endif
out string? value)
{
return commandAndKeyFetcher.TryFetch(message, out value);
}
});
});

Expand Down Expand Up @@ -186,20 +206,37 @@ public static void DrainSession(Activity? parentActivity, IEnumerable<IProfiledC
/// Creates getter for a field defined in private or internal type
/// represented with classType variable.
/// </summary>
private static Func<object, TField>? CreateFieldGetter<TField>(Type classType, string fieldName, BindingFlags flags)
private static Func<object, TField?>? CreateFieldGetter<TField>(
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
#endif
Type classType,
string fieldName,
BindingFlags flags)
{
FieldInfo field = classType.GetField(fieldName, flags);
FieldInfo? field = classType.GetField(fieldName, flags);
if (field != null)
{
string methodName = classType.FullName + ".get_" + field.Name;
DynamicMethod getterMethod = new DynamicMethod(methodName, typeof(TField), new[] { typeof(object) }, true);
ILGenerator generator = getterMethod.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Castclass, classType);
generator.Emit(OpCodes.Ldfld, field);
generator.Emit(OpCodes.Ret);

return (Func<object, TField>)getterMethod.CreateDelegate(typeof(Func<object, TField>));
#if NET6_0_OR_GREATER
if (RuntimeFeature.IsDynamicCodeSupported)
#endif
{
string methodName = classType.FullName + ".get_" + field.Name;
DynamicMethod getterMethod = new DynamicMethod(methodName, typeof(TField), new[] { typeof(object) }, true);
ILGenerator generator = getterMethod.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Castclass, classType);
generator.Emit(OpCodes.Ldfld, field);
generator.Emit(OpCodes.Ret);

return (Func<object, TField>)getterMethod.CreateDelegate(typeof(Func<object, TField>));
}
#if NET6_0_OR_GREATER
else
{
return obj => (TField?)field.GetValue(obj);
}
#endif
}

return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- OmniSharp/VS Code requires TargetFrameworks to be in descending order for IntelliSense and analysis. -->
<TargetFrameworks>netstandard2.0;net462</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0;net462</TargetFrameworks>
<Description>StackExchange.Redis instrumentation for OpenTelemetry .NET</Description>
<PackageTags>$(PackageTags);distributed-tracing;Redis;StackExchange.Redis</PackageTags>
<IncludeSharedInstrumentationSource>true</IncludeSharedInstrumentationSource>
<IncludeSharedExceptionExtensionsSource>true</IncludeSharedExceptionExtensionsSource>
<MinVerTagPrefix>Instrumentation.StackExchangeRedis-</MinVerTagPrefix>
<ImplicitUsings>true</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<Compile Include="$(RepoRoot)\src\Shared\Guard.cs" Link="Includes\Guard.cs" />
<Compile Include="$(RepoRoot)\src\Shared\PropertyFetcher.AOT.cs" Link="Includes\PropertyFetcher.AOT.cs" />
<Compile Include="$(RepoRoot)\src\Shared\SemanticConventions.cs" Link="Includes\SemanticConventions.cs" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ internal sealed class StackExchangeRedisConnectionInstrumentation : IDisposable
{
internal const string RedisDatabaseIndexKeyName = "db.redis.database_index";
internal const string RedisFlagsKeyName = "db.redis.flags";
internal static readonly string ActivitySourceName = typeof(StackExchangeRedisConnectionInstrumentation).Assembly.GetName().Name;
internal static readonly string ActivitySourceName = typeof(StackExchangeRedisConnectionInstrumentation).Assembly.GetName().Name!;
internal static readonly string ActivityName = ActivitySourceName + ".Execute";
internal static readonly Version Version = typeof(StackExchangeRedisConnectionInstrumentation).Assembly.GetName().Version;
internal static readonly Version Version = typeof(StackExchangeRedisConnectionInstrumentation).Assembly.GetName().Version!;
internal static readonly ActivitySource ActivitySource = new(ActivitySourceName, Version.ToString());
internal static readonly IEnumerable<KeyValuePair<string, object?>> CreationTags = new[]
{
Expand Down Expand Up @@ -137,7 +137,7 @@ internal void Flush()
}
}

private void DrainEntries(object state)
private void DrainEntries(object? state)
{
while (true)
{
Expand Down
Loading