Http Instrumentation: Fix gRPC causing issues retrieving request & response objects (#2698)

* Chain PropertyFetchers to support DiagnosticListener-based instrumentation being sent different payloads.

* CHANGELOG update.

* Unit test.
This commit is contained in:
Mikel Blanchard 2021-12-02 10:28:15 -08:00 committed by GitHub
parent 76d944130f
commit fd223474ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 22 deletions

View File

@ -2,6 +2,10 @@
## Unreleased
* Fixed an issue with `Filter` and `Enrich` callbacks not firing under certain
conditions when gRPC is used
([#2698](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2698))
## 1.0.0-rc8
Released 2021-Oct-08

View File

@ -73,14 +73,7 @@ namespace OpenTelemetry.Instrumentation
if (this.innerFetcher == null)
{
var type = obj.GetType().GetTypeInfo();
var property = type.DeclaredProperties.FirstOrDefault(p => string.Equals(p.Name, this.propertyName, StringComparison.InvariantCultureIgnoreCase));
if (property == null)
{
property = type.GetProperty(this.propertyName);
}
this.innerFetcher = PropertyFetch.FetcherForProperty(property);
this.innerFetcher = PropertyFetch.Create(obj.GetType().GetTypeInfo(), this.propertyName);
}
return this.innerFetcher.TryFetch(obj, out value);
@ -89,22 +82,29 @@ namespace OpenTelemetry.Instrumentation
// see https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagnosticSourceEventSource.cs
private class PropertyFetch
{
/// <summary>
/// Create a property fetcher from a .NET Reflection PropertyInfo class that
/// represents a property of a particular type.
/// </summary>
public static PropertyFetch FetcherForProperty(PropertyInfo propertyInfo)
public static PropertyFetch Create(TypeInfo type, string propertyName)
{
if (propertyInfo == null || !typeof(T).IsAssignableFrom(propertyInfo.PropertyType))
var property = type.DeclaredProperties.FirstOrDefault(p => string.Equals(p.Name, propertyName, StringComparison.InvariantCultureIgnoreCase));
if (property == null)
{
// returns null on any fetch.
return new PropertyFetch();
property = type.GetProperty(propertyName);
}
var typedPropertyFetcher = typeof(TypedPropertyFetch<,>);
var instantiatedTypedPropertyFetcher = typedPropertyFetcher.MakeGenericType(
typeof(T), propertyInfo.DeclaringType, propertyInfo.PropertyType);
return (PropertyFetch)Activator.CreateInstance(instantiatedTypedPropertyFetcher, propertyInfo);
return CreateFetcherForProperty(property);
static PropertyFetch CreateFetcherForProperty(PropertyInfo propertyInfo)
{
if (propertyInfo == null || !typeof(T).IsAssignableFrom(propertyInfo.PropertyType))
{
// returns null on any fetch.
return new PropertyFetch();
}
var typedPropertyFetcher = typeof(TypedPropertyFetch<,>);
var instantiatedTypedPropertyFetcher = typedPropertyFetcher.MakeGenericType(
typeof(T), propertyInfo.DeclaringType, propertyInfo.PropertyType);
return (PropertyFetch)Activator.CreateInstance(instantiatedTypedPropertyFetcher, propertyInfo);
}
}
public virtual bool TryFetch(object obj, out T value)
@ -116,10 +116,14 @@ namespace OpenTelemetry.Instrumentation
private sealed class TypedPropertyFetch<TDeclaredObject, TDeclaredProperty> : PropertyFetch
where TDeclaredProperty : T
{
private readonly string propertyName;
private readonly Func<TDeclaredObject, TDeclaredProperty> propertyFetch;
private PropertyFetch innerFetcher;
public TypedPropertyFetch(PropertyInfo property)
{
this.propertyName = property.Name;
this.propertyFetch = (Func<TDeclaredObject, TDeclaredProperty>)property.GetMethod.CreateDelegate(typeof(Func<TDeclaredObject, TDeclaredProperty>));
}
@ -131,8 +135,12 @@ namespace OpenTelemetry.Instrumentation
return true;
}
value = default;
return false;
if (this.innerFetcher == null)
{
this.innerFetcher = Create(obj.GetType().GetTypeInfo(), this.propertyName);
}
return this.innerFetcher.TryFetch(obj, out value);
}
}
}

View File

@ -50,5 +50,35 @@ namespace OpenTelemetry.Instrumentation.Tests
var fetch = new PropertyFetcher<string>("null");
Assert.False(fetch.TryFetch(null, out _));
}
[Fact]
public void FetchPropertyMultiplePayloadTypes()
{
var fetch = new PropertyFetcher<string>("Property");
Assert.True(fetch.TryFetch(new PayloadTypeA(), out string propertyValue));
Assert.Equal("A", propertyValue);
Assert.True(fetch.TryFetch(new PayloadTypeB(), out propertyValue));
Assert.Equal("B", propertyValue);
Assert.False(fetch.TryFetch(new PayloadTypeC(), out _));
Assert.False(fetch.TryFetch(null, out _));
}
private class PayloadTypeA
{
public string Property { get; set; } = "A";
}
private class PayloadTypeB
{
public string Property { get; set; } = "B";
}
private class PayloadTypeC
{
}
}
}