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

Add Google Protobuf Instrumentation #6166

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
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 Datadog.Trace.OSX.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
"tracer\\test\\test-applications\\integrations\\Samples.Elasticsearch.V7\\Samples.Elasticsearch.V7.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.Elasticsearch\\Samples.Elasticsearch.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.FakeDbCommand\\Samples.FakeDbCommand.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.GoogleProtobuf\\Samples.GoogleProtobuf.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.GraphQL3\\Samples.GraphQL3.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.GraphQL4\\Samples.GraphQL4.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.GraphQL7\\Samples.GraphQL7.csproj",
Expand Down
7 changes: 7 additions & 0 deletions Datadog.Trace.Samples.g.sln
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssemblyLoadContextResolve"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.AzureFunctions.V4Isolated.SdkV1", "tracer\test\test-applications\azure-functions\Samples.AzureFunctions.V4Isolated.SdkV1\Samples.AzureFunctions.V4Isolated.SdkV1.csproj", "{18767A3E-9ADC-485C-A8C7-50660D5B579D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.GoogleProtobuf", "tracer\test\test-applications\integrations\Samples.GoogleProtobuf\Samples.GoogleProtobuf.csproj", "{EF8C4CCE-E79C-4D78-BF31-222A11E198B9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1043,6 +1045,10 @@ Global
{18767A3E-9ADC-485C-A8C7-50660D5B579D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{18767A3E-9ADC-485C-A8C7-50660D5B579D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{18767A3E-9ADC-485C-A8C7-50660D5B579D}.Release|Any CPU.Build.0 = Release|Any CPU
{EF8C4CCE-E79C-4D78-BF31-222A11E198B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EF8C4CCE-E79C-4D78-BF31-222A11E198B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EF8C4CCE-E79C-4D78-BF31-222A11E198B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EF8C4CCE-E79C-4D78-BF31-222A11E198B9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9518425A-36A5-4B8F-B0B8-6137DB88441D} = {8CEC2042-F11C-49F5-A674-2355793B600A}
Expand Down Expand Up @@ -1216,5 +1222,6 @@ Global
{D6155F26-8245-4B66-8944-79C3DF9F9DA3} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A}
{8B1AF6A7-DD41-4347-B637-90C23D69B50E} = {498A300E-D036-49B7-A43D-821D1CAF11A5}
{18767A3E-9ADC-485C-A8C7-50660D5B579D} = {FE9F14E0-8DFF-413B-BB9E-49CEA4115A5D}
{EF8C4CCE-E79C-4D78-BF31-222A11E198B9} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A}
EndGlobalSection
EndGlobal
7 changes: 7 additions & 0 deletions Datadog.Trace.sln
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "azure-functions", "azure-fu
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.AzureFunctions.V4Isolated.SdkV1", "tracer\test\test-applications\azure-functions\Samples.AzureFunctions.V4Isolated.SdkV1\Samples.AzureFunctions.V4Isolated.SdkV1.csproj", "{18767A3E-9ADC-485C-A8C7-50660D5B579D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.GoogleProtobuf", "tracer\test\test-applications\integrations\Samples.GoogleProtobuf\Samples.GoogleProtobuf.csproj", "{EF8C4CCE-E79C-4D78-BF31-222A11E198B9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1442,6 +1444,10 @@ Global
{18767A3E-9ADC-485C-A8C7-50660D5B579D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{18767A3E-9ADC-485C-A8C7-50660D5B579D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{18767A3E-9ADC-485C-A8C7-50660D5B579D}.Release|Any CPU.Build.0 = Release|Any CPU
{EF8C4CCE-E79C-4D78-BF31-222A11E198B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EF8C4CCE-E79C-4D78-BF31-222A11E198B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EF8C4CCE-E79C-4D78-BF31-222A11E198B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EF8C4CCE-E79C-4D78-BF31-222A11E198B9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1678,6 +1684,7 @@ Global
{F8C637E1-1F4F-4E3B-9E34-AAD61097C3F8} = {07D12F26-2583-4C6F-AFBB-AA30FF339FC6}
{FE9F14E0-8DFF-413B-BB9E-49CEA4115A5D} = {F8C637E1-1F4F-4E3B-9E34-AAD61097C3F8}
{18767A3E-9ADC-485C-A8C7-50660D5B579D} = {FE9F14E0-8DFF-413B-BB9E-49CEA4115A5D}
{EF8C4CCE-E79C-4D78-BF31-222A11E198B9} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {160A1D00-1F5B-40F8-A155-621B4459D78F}
Expand Down
4 changes: 2 additions & 2 deletions docs/development/DuckTyping.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ DuckType.CreateTypeResult proxyResult = DuckType.GetOrCreateProxyType(proxyTarge
if (proxyResult.Success)
{
// Pass in null, as there's no "instance" to duck type here
return proxyResult.CreateInstance(null);
return proxyResult.CreateInstance(null!);
}
else
{
Expand Down Expand Up @@ -355,7 +355,7 @@ DuckType.CreateTypeResult proxyResult = DuckType.GetOrCreateProxyType(proxyType,
if (proxyResult.Success)
{
// Pass in null, as there's no "instance" to duck type here, to create an instance of our proxy
var proxy = (IObjectFactoryProxy)proxyResult.CreateInstance(null);
var proxy = (IObjectFactoryProxy)proxyResult.CreateInstance(null!);

// invoke methods on the proxy
object obj = proxy.CreateObject();
Expand Down
10 changes: 10 additions & 0 deletions tracer/build/PackageVersionsGeneratorDefinitions.json
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,16 @@
"ExcludeTargetFrameworks": ["netcoreapp2.1", "netcoreapp3.0"]
}]
},
{
"IntegrationName": "Protobuf",
"SampleProjectName": "Samples.GoogleProtobuf",
"NugetPackageSearchName": "Google.Protobuf",
"MinVersion": "3.0.0",
"MaxVersionExclusive": "4.0.0",
"SpecificVersions": [
"3.*.*"
]
},
{
"IntegrationName": "RabbitMQ",
"SampleProjectName": "Samples.RabbitMQ",
Expand Down
8 changes: 7 additions & 1 deletion tracer/build/_build/Build.ExplorationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,13 @@ public static ExplorationTestDescription GetExplorationTestDescription(Explorati
"Google.Protobuf.CodedInputStreamTest.MaliciousRecursion",
"Google.Protobuf.CodedInputStreamTest.MaliciousRecursion_UnknownFields",
"Google.Protobuf.CodedInputStreamTest.RecursionLimitAppliedWhileSkippingGroup",
"Google.Protobuf.JsonParserTest.MaliciousRecursion"
"Google.Protobuf.JsonParserTest.MaliciousRecursion",
// exclude those "legacy" tests because they are on manually modified code
// that throws a NotImplementedException on the `Descriptor` property that we use.
"Google.Protobuf.LegacyGeneratedCodeTest.IntermixingOfNewAndLegacyGeneratedCodeWorksWithCodedInputStream",
"Google.Protobuf.LegacyGeneratedCodeTest.IntermixingOfNewAndLegacyGeneratedCodeWorksWithCodedOutputStream",
"Google.Protobuf.LegacyGeneratedCodeTest.LegacyGeneratedCodeThrowsWithIBufferWriter",
"Google.Protobuf.LegacyGeneratedCodeTest.LegacyGeneratedCodeThrowsWithReadOnlySequence"
},
LineProbesEnabled = true
},
Expand Down
96 changes: 96 additions & 0 deletions tracer/build/supported_calltargets.g.json
Original file line number Diff line number Diff line change
Expand Up @@ -11719,6 +11719,102 @@
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "Protobuf",
"AssemblyName": "Google.Protobuf",
"TargetTypeName": "Google.Protobuf.IBufferMessage",
"TargetMethodName": "InternalMergeFrom",
"TargetReturnType": "System.Void",
"TargetParameterTypes": [
"Google.Protobuf.ParseContext&"
],
"MinimumVersion": {
"Item1": 3,
"Item2": 15,
"Item3": 0
},
"MaximumVersion": {
"Item1": 3,
"Item2": 65535,
"Item3": 65535
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.Protobuf.BufferMessageInternalMergeFromIntegration",
"IntegrationKind": 2,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "Protobuf",
"AssemblyName": "Google.Protobuf",
"TargetTypeName": "Google.Protobuf.IBufferMessage",
"TargetMethodName": "InternalWriteTo",
"TargetReturnType": "System.Void",
"TargetParameterTypes": [
"Google.Protobuf.WriteContext&"
],
"MinimumVersion": {
"Item1": 3,
"Item2": 15,
"Item3": 0
},
"MaximumVersion": {
"Item1": 3,
"Item2": 65535,
"Item3": 65535
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.Protobuf.BufferMessageInternalWriteToIntegration",
"IntegrationKind": 2,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "Protobuf",
"AssemblyName": "Google.Protobuf",
"TargetTypeName": "Google.Protobuf.IMessage",
"TargetMethodName": "MergeFrom",
"TargetReturnType": "System.Void",
"TargetParameterTypes": [
"Google.Protobuf.CodedInputStream"
],
"MinimumVersion": {
"Item1": 3,
"Item2": 0,
"Item3": 0
},
"MaximumVersion": {
"Item1": 3,
"Item2": 65535,
"Item3": 65535
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.Protobuf.MessageMergeFromIntegration",
"IntegrationKind": 2,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "Protobuf",
"AssemblyName": "Google.Protobuf",
"TargetTypeName": "Google.Protobuf.IMessage",
"TargetMethodName": "WriteTo",
"TargetReturnType": "System.Void",
"TargetParameterTypes": [
"Google.Protobuf.CodedOutputStream"
],
"MinimumVersion": {
"Item1": 3,
"Item2": 0,
"Item3": 0
},
"MaximumVersion": {
"Item1": 3,
"Item2": 65535,
"Item3": 65535
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.Protobuf.MessageWriteToIntegration",
"IntegrationKind": 2,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "RabbitMQ",
"AssemblyName": "RabbitMQ.Client",
Expand Down
1 change: 0 additions & 1 deletion tracer/missing-nullability-files.csv
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,6 @@ src/Datadog.Trace/Util/ArraySlice.cs
src/Datadog.Trace/Util/AsyncUtil.cs
src/Datadog.Trace/Util/Clock.cs
src/Datadog.Trace/Util/DomainMetadata.cs
src/Datadog.Trace/Util/FnvHash64.cs
src/Datadog.Trace/Util/IClock.cs
src/Datadog.Trace/Util/IRandomIdGenerator.cs
src/Datadog.Trace/Util/RandomIdGenerator.Net6.cs
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// <copyright file="BufferMessageInternalMergeFromIntegration.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>

#nullable enable

using System;
using System.ComponentModel;
using Datadog.Trace.ClrProfiler.CallTarget;

namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.Protobuf;

/// <summary>
/// System.Void Google.Protobuf.IBufferMessage::InternalMergeFrom(Google.Protobuf.ParseContext) calltarget instrumentation
/// </summary>
[InstrumentMethod(
AssemblyName = "Google.Protobuf",
TypeName = "Google.Protobuf.IBufferMessage",
MethodName = "InternalMergeFrom",
ParameterTypeNames = ["Google.Protobuf.ParseContext&"],
ReturnTypeName = ClrNames.Void,
MinimumVersion = "3.15.0",
MaximumVersion = "3.*.*",
IntegrationName = nameof(Configuration.IntegrationId.Protobuf),
CallTargetIntegrationKind = CallTargetKind.Interface)]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public class BufferMessageInternalMergeFromIntegration
{
internal static CallTargetState OnMethodBegin<TTarget, TOutput>(TTarget instance, ref TOutput? output)
where TTarget : IMessageProxy
{
if (Helper.TryGetDescriptor(instance, out var descriptor))
{
SchemaExtractor.EnrichActiveSpanWith(descriptor, "deserialization");
}

return CallTargetState.GetDefault();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// <copyright file="BufferMessageInternalWriteToIntegration.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>

#nullable enable

using System.ComponentModel;
using Datadog.Trace.ClrProfiler.CallTarget;

namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.Protobuf;

/// <summary>
/// System.Void Google.Protobuf.IBufferMessage::InternalWriteTo(Google.Protobuf.WriteContext) calltarget instrumentation
/// </summary>
[InstrumentMethod(
AssemblyName = "Google.Protobuf",
TypeName = "Google.Protobuf.IBufferMessage",
MethodName = "InternalWriteTo",
ReturnTypeName = ClrNames.Void,
ParameterTypeNames = ["Google.Protobuf.WriteContext&"],
MinimumVersion = "3.15.0",
MaximumVersion = "3.*.*",
IntegrationName = nameof(Configuration.IntegrationId.Protobuf),
CallTargetIntegrationKind = CallTargetKind.Interface)]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public class BufferMessageInternalWriteToIntegration
{
internal static CallTargetState OnMethodBegin<TTarget, TCtx>(TTarget instance, ref TCtx ctx)
where TTarget : IMessageProxy
{
if (instance.Instance is not null)
{
SchemaExtractor.EnrichActiveSpanWith(instance.Descriptor, "deserialization");
}

return CallTargetState.GetDefault();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// <copyright file="Helper.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>

#nullable enable

using System;
using System.Threading;
using Datadog.Trace.DuckTyping;
using Datadog.Trace.Logging;

namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.Protobuf;

internal class Helper
{
private static readonly IDatadogLogger Log = DatadogLogging.GetLoggerFor<Helper>();

private static readonly Lazy<IDescriptorReflectionProxy?> DescriptorReflectionProxy = new(
() =>
{
// prepare incantations to access the static property DescriptorReflection.Descriptor
var staticType = Type.GetType("Google.Protobuf.Reflection.DescriptorReflection,Google.Protobuf");
if (staticType == null)
{
return null;
}

var proxyType = typeof(IDescriptorReflectionProxy);

var proxyResult = DuckType.GetOrCreateProxyType(proxyType, staticType);
if (!proxyResult.Success)
{
Log.Warning("Cannot create proxy for type Google.Protobuf.Reflection.DescriptorReflection, protobuf instrumentation may malfunction.");
return null;
}

return (IDescriptorReflectionProxy)proxyResult.CreateInstance(null!);
});

public interface IDescriptorReflectionProxy
{
object? Descriptor { get; } // this is actually a static property
}

public static bool TryGetDescriptor(IMessageProxy messageProxy, out IMessageDescriptorProxy? descriptor)
{
descriptor = null;
if (messageProxy.Instance is null)
{
return false;
}

// some public functions that we are instrumenting are also called internally by protobuf,
// and there is one case where trying to access the descriptor at that point results in a nullref
// because it relies on this property. We check it here to make sure we're not going to generate an exception by accessing it.
if (DescriptorReflectionProxy.Value?.Descriptor == null)
{
return false;
}

// now we know it's safe to access the Descriptor property on the message
descriptor = messageProxy.Descriptor;
return true;
}
}
Loading
Loading