From 3fcf0044f497505e6cc01663f16d2ab391fe43be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Wed, 7 Jun 2023 14:37:10 +0200 Subject: [PATCH 01/10] Drop GraphQL Instrumentation attribute for simpler code in source code generator --- .../GraphQL/ExecuteAsyncIntegration.cs | 18 +++++++--- .../GraphQL/GraphQLExecuteAsyncAttribute.cs | 34 ------------------- 2 files changed, 14 insertions(+), 38 deletions(-) delete mode 100644 src/OpenTelemetry.AutoInstrumentation/Instrumentations/GraphQL/GraphQLExecuteAsyncAttribute.cs diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/GraphQL/ExecuteAsyncIntegration.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/GraphQL/ExecuteAsyncIntegration.cs index 038953e92c..9217dfa701 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/GraphQL/ExecuteAsyncIntegration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/GraphQL/ExecuteAsyncIntegration.cs @@ -22,16 +22,26 @@ namespace OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL; /// /// GraphQL.Execution.ExecutionStrategy calltarget instrumentation /// -[GraphQLExecuteAsync( +[InstrumentMethod( assemblyName: GraphQLCommon.GraphQLAssembly, typeName: "GraphQL.Execution.ExecutionStrategy", + methodName: "ExecuteAsync", + returnTypeName: "System.Threading.Tasks.Task`1[GraphQL.ExecutionResult]", + parameterTypeNames: new[] { "GraphQL.Execution.ExecutionContext" }, minimumVersion: GraphQLCommon.Major2Minor3, - maximumVersion: GraphQLCommon.Major2)] -[GraphQLExecuteAsync( + maximumVersion: GraphQLCommon.Major2, + integrationName: GraphQLCommon.IntegrationName, + type: InstrumentationType.Trace)] +[InstrumentMethod( assemblyName: GraphQLCommon.GraphQLAssembly, typeName: "GraphQL.Execution.SubscriptionExecutionStrategy", + methodName: "ExecuteAsync", + returnTypeName: "System.Threading.Tasks.Task`1[GraphQL.ExecutionResult]", + parameterTypeNames: new[] { "GraphQL.Execution.ExecutionContext" }, minimumVersion: GraphQLCommon.Major2Minor3, - maximumVersion: GraphQLCommon.Major2)] + maximumVersion: GraphQLCommon.Major2, + integrationName: GraphQLCommon.IntegrationName, + type: InstrumentationType.Trace)] public static class ExecuteAsyncIntegration { /// diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/GraphQL/GraphQLExecuteAsyncAttribute.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/GraphQL/GraphQLExecuteAsyncAttribute.cs deleted file mode 100644 index 6e1390d3b2..0000000000 --- a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/GraphQL/GraphQLExecuteAsyncAttribute.cs +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License 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 OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL; - -internal class GraphQLExecuteAsyncAttribute : InstrumentMethodAttribute -{ - public GraphQLExecuteAsyncAttribute(string assemblyName, string typeName, string minimumVersion, string maximumVersion) - : base( - assemblyName: assemblyName, - typeName: typeName, - methodName: "ExecuteAsync", - returnTypeName: "System.Threading.Tasks.Task`1[GraphQL.ExecutionResult]", - parameterTypeNames: new[] { "GraphQL.Execution.ExecutionContext" }, - minimumVersion: minimumVersion, - maximumVersion: maximumVersion, - integrationName: GraphQLCommon.IntegrationName, - type: InstrumentationType.Trace) - { - } -} From 95b99123473c30bb7a42b0d3c0c4aa5af28d59fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Thu, 1 Jun 2023 10:50:29 +0200 Subject: [PATCH 02/10] SourceGenerator --- OpenTelemetry.AutoInstrumentation.sln | 15 + src/Directory.Packages.props | 6 + .../InstrumentationDefinitions.g.cs | 83 ++++++ .../InstrumentationDefinitions.g.cs | 92 ++++++ .../InstrumentationDefinitions.cs | 102 +------ .../Instrumentations/InstrumentationType.cs | 6 +- .../OpenTelemetry.AutoInstrumentation.csproj | 7 + .../InstrumentationDefinitionsGenerator.cs | 280 ++++++++++++++++++ src/SourceGenerators/IntegrationToGenerate.cs | 44 +++ src/SourceGenerators/SourceGenerators.csproj | 18 ++ 10 files changed, 549 insertions(+), 104 deletions(-) create mode 100644 src/OpenTelemetry.AutoInstrumentation/Generated/net462/SourceGenerators/SourceGenerators.InstrumentationDefinitionsGenerator/InstrumentationDefinitions.g.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Generated/net6.0/SourceGenerators/SourceGenerators.InstrumentationDefinitionsGenerator/InstrumentationDefinitions.g.cs create mode 100644 src/SourceGenerators/InstrumentationDefinitionsGenerator.cs create mode 100644 src/SourceGenerators/IntegrationToGenerate.cs create mode 100644 src/SourceGenerators/SourceGenerators.csproj diff --git a/OpenTelemetry.AutoInstrumentation.sln b/OpenTelemetry.AutoInstrumentation.sln index b98e2bb102..5225f9d886 100644 --- a/OpenTelemetry.AutoInstrumentation.sln +++ b/OpenTelemetry.AutoInstrumentation.sln @@ -191,6 +191,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApplication.AssemblyRed EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.Wcf.Server.IIS.NetFramework", "test\test-applications\integrations\TestApplication.Wcf.Server.IIS.NetFramework\TestApplication.Wcf.Server.IIS.NetFramework.csproj", "{65619BD1-4517-400C-8071-C1409A7D255E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceGenerators", "src\SourceGenerators\SourceGenerators.csproj", "{0366116E-2444-4837-8AB0-6908BF29DB51}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -879,6 +881,18 @@ Global {65619BD1-4517-400C-8071-C1409A7D255E}.Release|x64.Build.0 = Release|Any CPU {65619BD1-4517-400C-8071-C1409A7D255E}.Release|x86.ActiveCfg = Release|Any CPU {65619BD1-4517-400C-8071-C1409A7D255E}.Release|x86.Build.0 = Release|Any CPU + {0366116E-2444-4837-8AB0-6908BF29DB51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0366116E-2444-4837-8AB0-6908BF29DB51}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0366116E-2444-4837-8AB0-6908BF29DB51}.Debug|x64.ActiveCfg = Debug|Any CPU + {0366116E-2444-4837-8AB0-6908BF29DB51}.Debug|x64.Build.0 = Debug|Any CPU + {0366116E-2444-4837-8AB0-6908BF29DB51}.Debug|x86.ActiveCfg = Debug|Any CPU + {0366116E-2444-4837-8AB0-6908BF29DB51}.Debug|x86.Build.0 = Debug|Any CPU + {0366116E-2444-4837-8AB0-6908BF29DB51}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0366116E-2444-4837-8AB0-6908BF29DB51}.Release|Any CPU.Build.0 = Release|Any CPU + {0366116E-2444-4837-8AB0-6908BF29DB51}.Release|x64.ActiveCfg = Release|Any CPU + {0366116E-2444-4837-8AB0-6908BF29DB51}.Release|x64.Build.0 = Release|Any CPU + {0366116E-2444-4837-8AB0-6908BF29DB51}.Release|x86.ActiveCfg = Release|Any CPU + {0366116E-2444-4837-8AB0-6908BF29DB51}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -946,6 +960,7 @@ Global {0077F121-DC2B-425E-A2F4-DEAC2A566E14} = {5C915382-C886-457D-8641-9E766D8E5A17} {66FB648E-7FAF-418B-B2F6-B7CB9EE579CA} = {E409ADD3-9574-465C-AB09-4324D205CC7C} {65619BD1-4517-400C-8071-C1409A7D255E} = {E409ADD3-9574-465C-AB09-4324D205CC7C} + {0366116E-2444-4837-8AB0-6908BF29DB51} = {9E5F0022-0A50-40BF-AC6A-C3078585ECAB} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {160A1D00-1F5B-40F8-A155-621B4459D78F} diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 88c9fa2ed6..825ffbfcaa 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -28,6 +28,12 @@ + + + + + + diff --git a/src/OpenTelemetry.AutoInstrumentation/Generated/net462/SourceGenerators/SourceGenerators.InstrumentationDefinitionsGenerator/InstrumentationDefinitions.g.cs b/src/OpenTelemetry.AutoInstrumentation/Generated/net462/SourceGenerators/SourceGenerators.InstrumentationDefinitionsGenerator/InstrumentationDefinitions.g.cs new file mode 100644 index 0000000000..81aa4f95c5 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Generated/net462/SourceGenerators/SourceGenerators.InstrumentationDefinitionsGenerator/InstrumentationDefinitions.g.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by the InstrumentationDefinitionsGenerator tool. To safely +// modify this file, edit InstrumentMethodAttribute on the classes and +// compile project. + +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using OpenTelemetry.AutoInstrumentation.Configurations; + +namespace OpenTelemetry.AutoInstrumentation; + +internal static partial class InstrumentationDefinitions +{ + private static readonly string AssemblyFullName = typeof(InstrumentationDefinitions).Assembly.FullName!; + + private static NativeCallTargetDefinition[] GetDefinitionsArray() + { + var nativeCallTargetDefinitions = new List(11); + // Traces + var tracerSettings = Instrumentation.TracerSettings.Value; + if (tracerSettings.TracesEnabled) +{ + // AspNet + if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.AspNet)) + { + nativeCallTargetDefinitions.Add(new("System.Web", "System.Web.Compilation.BuildManager", "InvokePreStartInitMethodsCore", new[] {"System.Void", "System.Collections.Generic.ICollection`1[System.Reflection.MethodInfo]", "System.Func`1[System.IDisposable]"}, 4, 0, 0, 4, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.AspNet.HttpModuleIntegration")); + } + + // GraphQL + if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.GraphQL)) + { + nativeCallTargetDefinitions.Add(new("GraphQL", "GraphQL.Execution.ExecutionStrategy", "ExecuteAsync", new[] {"System.Threading.Tasks.Task`1[GraphQL.ExecutionResult]", "GraphQL.Execution.ExecutionContext"}, 2, 3, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ExecuteAsyncIntegration")); + nativeCallTargetDefinitions.Add(new("GraphQL", "GraphQL.Execution.SubscriptionExecutionStrategy", "ExecuteAsync", new[] {"System.Threading.Tasks.Task`1[GraphQL.ExecutionResult]", "GraphQL.Execution.ExecutionContext"}, 2, 3, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ExecuteAsyncIntegration")); + } + + // MongoDB + if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.MongoDB)) + { + nativeCallTargetDefinitions.Add(new("MongoDB.Driver", "MongoDB.Driver.MongoClient", ".ctor", new[] {"System.Void", "MongoDB.Driver.MongoClientSettings"}, 2, 13, 3, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.MongoDB.MongoClientIntegration")); + } + + // NServiceBus + if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.NServiceBus)) + { + nativeCallTargetDefinitions.Add(new("NServiceBus.Core", "NServiceBus.EndpointConfiguration", ".ctor", new[] {"System.Void", "System.String"}, 8, 0, 0, 8, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.NServiceBus.EndpointConfigurationIntegration")); + } + + // WcfService + if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.WcfService)) + { + nativeCallTargetDefinitions.Add(new("System.ServiceModel", "System.ServiceModel.ServiceHostBase", "InitializeDescription", new[] {"System.Void", "System.ServiceModel.UriSchemeKeyedCollection"}, 4, 0, 0, 4, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.Wcf.ServiceHostIntegration")); + } + + // WcfClient + if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.WcfClient)) + { + nativeCallTargetDefinitions.Add(new("System.ServiceModel", "System.ServiceModel.ChannelFactory", "InitializeEndpoint", new[] {"System.Void", "System.String", "System.ServiceModel.EndpointAddress"}, 4, 0, 0, 4, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.Wcf.WcfClientIntegration")); + nativeCallTargetDefinitions.Add(new("System.ServiceModel", "System.ServiceModel.ChannelFactory", "InitializeEndpoint", new[] {"System.Void", "System.String", "System.ServiceModel.EndpointAddress", "System.Configuration.Configuration"}, 4, 0, 0, 4, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.Wcf.WcfClientIntegration")); + nativeCallTargetDefinitions.Add(new("System.ServiceModel", "System.ServiceModel.ChannelFactory", "InitializeEndpoint", new[] {"System.Void", "System.ServiceModel.Description.ServiceEndpoint"}, 4, 0, 0, 4, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.Wcf.WcfClientIntegration")); + nativeCallTargetDefinitions.Add(new("System.ServiceModel", "System.ServiceModel.ChannelFactory", "InitializeEndpoint", new[] {"System.Void", "System.ServiceModel.Channels.Binding", "System.ServiceModel.EndpointAddress"}, 4, 0, 0, 4, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.Wcf.WcfClientIntegration")); + } + + } + + // Metrics + var metricSettings = Instrumentation.MetricSettings.Value; + if (metricSettings.MetricsEnabled) +{ + // NServiceBus + if (metricSettings.EnabledInstrumentations.Contains(MetricInstrumentation.NServiceBus)) + { + nativeCallTargetDefinitions.Add(new("NServiceBus.Core", "NServiceBus.EndpointConfiguration", ".ctor", new[] {"System.Void", "System.String"}, 8, 0, 0, 8, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.NServiceBus.EndpointConfigurationIntegration")); + } + + } + + return nativeCallTargetDefinitions.ToArray(); + } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Generated/net6.0/SourceGenerators/SourceGenerators.InstrumentationDefinitionsGenerator/InstrumentationDefinitions.g.cs b/src/OpenTelemetry.AutoInstrumentation/Generated/net6.0/SourceGenerators/SourceGenerators.InstrumentationDefinitionsGenerator/InstrumentationDefinitions.g.cs new file mode 100644 index 0000000000..cb3f029e04 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Generated/net6.0/SourceGenerators/SourceGenerators.InstrumentationDefinitionsGenerator/InstrumentationDefinitions.g.cs @@ -0,0 +1,92 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by the InstrumentationDefinitionsGenerator tool. To safely +// modify this file, edit InstrumentMethodAttribute on the classes and +// compile project. + +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using OpenTelemetry.AutoInstrumentation.Configurations; + +namespace OpenTelemetry.AutoInstrumentation; + +internal static partial class InstrumentationDefinitions +{ + private static readonly string AssemblyFullName = typeof(InstrumentationDefinitions).Assembly.FullName!; + + private static NativeCallTargetDefinition[] GetDefinitionsArray() + { + var nativeCallTargetDefinitions = new List(14); + // Traces + var tracerSettings = Instrumentation.TracerSettings.Value; + if (tracerSettings.TracesEnabled) +{ + // GraphQL + if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.GraphQL)) + { + nativeCallTargetDefinitions.Add(new("GraphQL", "GraphQL.Execution.ExecutionStrategy", "ExecuteAsync", new[] {"System.Threading.Tasks.Task`1[GraphQL.ExecutionResult]", "GraphQL.Execution.ExecutionContext"}, 2, 3, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ExecuteAsyncIntegration")); + nativeCallTargetDefinitions.Add(new("GraphQL", "GraphQL.Execution.SubscriptionExecutionStrategy", "ExecuteAsync", new[] {"System.Threading.Tasks.Task`1[GraphQL.ExecutionResult]", "GraphQL.Execution.ExecutionContext"}, 2, 3, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ExecuteAsyncIntegration")); + } + + // MongoDB + if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.MongoDB)) + { + nativeCallTargetDefinitions.Add(new("MongoDB.Driver", "MongoDB.Driver.MongoClient", ".ctor", new[] {"System.Void", "MongoDB.Driver.MongoClientSettings"}, 2, 13, 3, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.MongoDB.MongoClientIntegration")); + } + + // MySqlData + if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.MySqlData)) + { + nativeCallTargetDefinitions.Add(new("MySql.Data", "MySql.Data.MySqlClient.MySqlConnectionStringBuilder", "get_Logging", new[] {"System.Boolean"}, 8, 0, 31, 8, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.MySqlData.MySqlConnectionStringBuilderIntegration")); + } + + // NServiceBus + if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.NServiceBus)) + { + nativeCallTargetDefinitions.Add(new("NServiceBus.Core", "NServiceBus.EndpointConfiguration", ".ctor", new[] {"System.Void", "System.String"}, 8, 0, 0, 8, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.NServiceBus.EndpointConfigurationIntegration")); + } + + // StackExchangeRedis + if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.StackExchangeRedis)) + { + nativeCallTargetDefinitions.Add(new("StackExchange.Redis", "StackExchange.Redis.ConnectionMultiplexer", "ConnectImpl", new[] {"StackExchange.Redis.ConnectionMultiplexer", "System.Object", "System.IO.TextWriter"}, 2, 0, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegration")); + nativeCallTargetDefinitions.Add(new("StackExchange.Redis", "StackExchange.Redis.ConnectionMultiplexer", "ConnectImpl", new[] {"StackExchange.Redis.ConnectionMultiplexer", "StackExchange.Redis.ConfigurationOptions", "System.IO.TextWriter"}, 2, 0, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegration")); + nativeCallTargetDefinitions.Add(new("StackExchange.Redis", "StackExchange.Redis.ConnectionMultiplexer", "ConnectImpl", new[] {"StackExchange.Redis.ConnectionMultiplexer", "StackExchange.Redis.ConfigurationOptions", "System.IO.TextWriter", "System.Nullable`1[StackExchange.Redis.ServerType]"}, 2, 0, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegration")); + nativeCallTargetDefinitions.Add(new("StackExchange.Redis", "StackExchange.Redis.ConnectionMultiplexer", "ConnectImpl", new[] {"StackExchange.Redis.ConnectionMultiplexer", "StackExchange.Redis.ConfigurationOptions", "System.IO.TextWriter", "System.Nullable`1[StackExchange.Redis.ServerType]", "StackExchange.Redis.EndPointCollection"}, 2, 0, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegration")); + nativeCallTargetDefinitions.Add(new("StackExchange.Redis", "StackExchange.Redis.ConnectionMultiplexer", "ConnectImplAsync", new[] {"System.Threading.Tasks.Task`1[StackExchange.Redis.ConnectionMultiplexer]", "System.Object", "System.IO.TextWriter"}, 2, 0, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegrationAsync")); + nativeCallTargetDefinitions.Add(new("StackExchange.Redis", "StackExchange.Redis.ConnectionMultiplexer", "ConnectImplAsync", new[] {"System.Threading.Tasks.Task`1[StackExchange.Redis.ConnectionMultiplexer]", "StackExchange.Redis.ConfigurationOptions", "System.IO.TextWriter"}, 2, 0, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegrationAsync")); + nativeCallTargetDefinitions.Add(new("StackExchange.Redis", "StackExchange.Redis.ConnectionMultiplexer", "ConnectImplAsync", new[] {"System.Threading.Tasks.Task`1[StackExchange.Redis.ConnectionMultiplexer]", "StackExchange.Redis.ConfigurationOptions", "System.IO.TextWriter", "System.Nullable`1[StackExchange.Redis.ServerType]"}, 2, 0, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegrationAsync")); + } + + } + + // Logs + var logSettings = Instrumentation.LogSettings.Value; + if (logSettings.LogsEnabled) +{ + // ILogger + if (logSettings.EnabledInstrumentations.Contains(LogInstrumentation.ILogger)) + { + nativeCallTargetDefinitions.Add(new("Microsoft.Extensions.Logging", "Microsoft.Extensions.Logging.LoggingBuilder", ".ctor", new[] {"System.Void", "Microsoft.Extensions.DependencyInjection.IServiceCollection"}, 3, 1, 0, 7, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.Logger.LoggingBuilderIntegration")); + } + + } + + // Metrics + var metricSettings = Instrumentation.MetricSettings.Value; + if (metricSettings.MetricsEnabled) +{ + // NServiceBus + if (metricSettings.EnabledInstrumentations.Contains(MetricInstrumentation.NServiceBus)) + { + nativeCallTargetDefinitions.Add(new("NServiceBus.Core", "NServiceBus.EndpointConfiguration", ".ctor", new[] {"System.Void", "System.String"}, 8, 0, 0, 8, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.NServiceBus.EndpointConfigurationIntegration")); + } + + } + + return nativeCallTargetDefinitions.ToArray(); + } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/InstrumentationDefinitions.cs b/src/OpenTelemetry.AutoInstrumentation/InstrumentationDefinitions.cs index a2d61214fc..a8e2892b6c 100644 --- a/src/OpenTelemetry.AutoInstrumentation/InstrumentationDefinitions.cs +++ b/src/OpenTelemetry.AutoInstrumentation/InstrumentationDefinitions.cs @@ -14,14 +14,10 @@ // limitations under the License. // -using OpenTelemetry.AutoInstrumentation.Configurations; - namespace OpenTelemetry.AutoInstrumentation; -internal static class InstrumentationDefinitions +internal static partial class InstrumentationDefinitions { - private static readonly string AssemblyFullName = typeof(InstrumentationDefinitions).Assembly.FullName!; - internal static Payload GetAllDefinitions() { return new Payload @@ -46,102 +42,6 @@ internal static Payload GetDerivedDefinitions() }; } - // TODO: Generate this list using source generators - private static NativeCallTargetDefinition[] GetDefinitionsArray() - { - var nativeCallTargetDefinitions = new List(); - - // Traces - var tracerSettings = Instrumentation.TracerSettings.Value; - if (tracerSettings.TracesEnabled) - { -#if NETFRAMEWORK - // AspNet - if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.AspNet)) - { - nativeCallTargetDefinitions.Add(new("System.Web", "System.Web.Compilation.BuildManager", "InvokePreStartInitMethodsCore", new[] { "System.Void", "System.Collections.Generic.ICollection`1[System.Reflection.MethodInfo]", "System.Func`1[System.IDisposable]" }, 4, 0, 0, 4, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.AspNet.HttpModuleIntegration")); - } -#endif - - if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.GraphQL)) - { - nativeCallTargetDefinitions.Add(new("GraphQL", "GraphQL.Execution.ExecutionStrategy", "ExecuteAsync", new[] { "System.Threading.Tasks.Task`1", "GraphQL.Execution.ExecutionContext" }, 2, 3, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ExecuteAsyncIntegration")); - nativeCallTargetDefinitions.Add(new("GraphQL", "GraphQL.Execution.SubscriptionExecutionStrategy", "ExecuteAsync", new[] { "System.Threading.Tasks.Task`1", "GraphQL.Execution.ExecutionContext" }, 2, 3, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ExecuteAsyncIntegration")); - } - - if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.MongoDB)) - { - nativeCallTargetDefinitions.Add(new("MongoDB.Driver", "MongoDB.Driver.MongoClient", ".ctor", new[] { "System.Void", "MongoDB.Driver.MongoClientSettings" }, 2, 13, 3, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.MongoDB.MongoClientIntegration")); - } - -#if NET6_0_OR_GREATER - if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.MySqlData)) - { - nativeCallTargetDefinitions.Add(new("MySql.Data", "MySql.Data.MySqlClient.MySqlConnectionStringBuilder", "get_Logging", new[] { "System.Boolean" }, 8, 0, 31, 8, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.MySqlData.MySqlConnectionStringBuilderIntegration")); - } -#endif - - if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.NServiceBus)) - { - nativeCallTargetDefinitions.Add(new("NServiceBus.Core", "NServiceBus.EndpointConfiguration", ".ctor", new[] { "System.Void", "System.String" }, 8, 0, 0, 8, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.NServiceBus.EndpointConfigurationIntegration")); - } - -#if NET6_0_OR_GREATER - if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.StackExchangeRedis)) - { - nativeCallTargetDefinitions.Add(new("StackExchange.Redis", "StackExchange.Redis.ConnectionMultiplexer", "ConnectImpl", new[] { "StackExchange.Redis.ConnectionMultiplexer", "System.Object", "System.IO.TextWriter" }, 2, 0, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegration")); - nativeCallTargetDefinitions.Add(new("StackExchange.Redis", "StackExchange.Redis.ConnectionMultiplexer", "ConnectImpl", new[] { "StackExchange.Redis.ConnectionMultiplexer", "StackExchange.Redis.ConfigurationOptions", "System.IO.TextWriter" }, 2, 0, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegration")); - nativeCallTargetDefinitions.Add(new("StackExchange.Redis", "StackExchange.Redis.ConnectionMultiplexer", "ConnectImpl", new[] { "StackExchange.Redis.ConnectionMultiplexer", "StackExchange.Redis.ConfigurationOptions", "System.IO.TextWriter", "System.Nullable`1[StackExchange.Redis.ServerType]" }, 2, 0, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegration")); - nativeCallTargetDefinitions.Add(new("StackExchange.Redis", "StackExchange.Redis.ConnectionMultiplexer", "ConnectImpl", new[] { "StackExchange.Redis.ConnectionMultiplexer", "StackExchange.Redis.ConfigurationOptions", "System.IO.TextWriter", "System.Nullable`1[StackExchange.Redis.ServerType]", "StackExchange.Redis.EndPointCollection" }, 2, 0, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegration")); - nativeCallTargetDefinitions.Add(new("StackExchange.Redis", "StackExchange.Redis.ConnectionMultiplexer", "ConnectImplAsync", new[] { "System.Threading.Tasks.Task`1", "System.Object", "System.IO.TextWriter" }, 2, 0, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegrationAsync")); - nativeCallTargetDefinitions.Add(new("StackExchange.Redis", "StackExchange.Redis.ConnectionMultiplexer", "ConnectImplAsync", new[] { "System.Threading.Tasks.Task`1", "StackExchange.Redis.ConfigurationOptions", "System.IO.TextWriter" }, 2, 0, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegrationAsync")); - nativeCallTargetDefinitions.Add(new("StackExchange.Redis", "StackExchange.Redis.ConnectionMultiplexer", "ConnectImplAsync", new[] { "System.Threading.Tasks.Task`1", "StackExchange.Redis.ConfigurationOptions", "System.IO.TextWriter", "System.Nullable`1[StackExchange.Redis.ServerType]" }, 2, 0, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegrationAsync")); - } -#endif - -#if NETFRAMEWORK - if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.WcfClient)) - { - nativeCallTargetDefinitions.Add(new("System.ServiceModel", "System.ServiceModel.ChannelFactory", "InitializeEndpoint", new[] { "System.Void", "System.String", "System.ServiceModel.EndpointAddress" }, 4, 0, 0, 4, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.Wcf.WcfClientIntegration")); - nativeCallTargetDefinitions.Add(new("System.ServiceModel", "System.ServiceModel.ChannelFactory", "InitializeEndpoint", new[] { "System.Void", "System.String", "System.ServiceModel.EndpointAddress", "System.Configuration.Configuration" }, 4, 0, 0, 4, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.Wcf.WcfClientIntegration")); - nativeCallTargetDefinitions.Add(new("System.ServiceModel", "System.ServiceModel.ChannelFactory", "InitializeEndpoint", new[] { "System.Void", "System.ServiceModel.Description.ServiceEndpoint" }, 4, 0, 0, 4, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.Wcf.WcfClientIntegration")); - nativeCallTargetDefinitions.Add(new("System.ServiceModel", "System.ServiceModel.ChannelFactory", "InitializeEndpoint", new[] { "System.Void", "System.ServiceModel.Channels.Binding", "System.ServiceModel.EndpointAddress" }, 4, 0, 0, 4, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.Wcf.WcfClientIntegration")); - } -#endif - -#if NETFRAMEWORK - if (tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.WcfService)) - { - nativeCallTargetDefinitions.Add(new("System.ServiceModel", "System.ServiceModel.ServiceHostBase", "InitializeDescription", new[] { "System.Void", "System.ServiceModel.UriSchemeKeyedCollection" }, 4, 0, 0, 4, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.Wcf.ServiceHostIntegration")); - } -#endif - } - -#if NET6_0_OR_GREATER - // Logs - var logSettings = Instrumentation.LogSettings.Value; - if (logSettings.LogsEnabled) - { - if (logSettings.EnabledInstrumentations.Contains(LogInstrumentation.ILogger)) - { - nativeCallTargetDefinitions.Add(new("Microsoft.Extensions.Logging", "Microsoft.Extensions.Logging.LoggingBuilder", ".ctor", new[] { "System.Void", "Microsoft.Extensions.DependencyInjection.IServiceCollection" }, 3, 1, 0, 7, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.Logger.LoggingBuilderIntegration")); - } - } -#endif - - // Metrics - var metricSettings = Instrumentation.MetricSettings.Value; - if (metricSettings.MetricsEnabled) - { - if (metricSettings.EnabledInstrumentations.Contains(MetricInstrumentation.NServiceBus)) - { - nativeCallTargetDefinitions.Add(new("NServiceBus.Core", "NServiceBus.EndpointConfiguration", ".ctor", new[] { "System.Void", "System.String" }, 8, 0, 0, 8, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.NServiceBus.EndpointConfigurationIntegration")); - } - } - - return nativeCallTargetDefinitions.ToArray(); - } - // TODO: Generate this list using source generators private static NativeCallTargetDefinition[] GetDerivedDefinitionsArray() => new NativeCallTargetDefinition[] diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/InstrumentationType.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/InstrumentationType.cs index 0e5d8e7c74..14c14a5d67 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/InstrumentationType.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/InstrumentationType.cs @@ -18,7 +18,7 @@ namespace OpenTelemetry.AutoInstrumentation.Instrumentations; internal enum InstrumentationType { - Trace, - Metric, - Log + Trace = 0, + Metric = 1, + Log = 2 } diff --git a/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj b/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj index ed4eac69e6..e6e7335473 100644 --- a/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj +++ b/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj @@ -4,7 +4,14 @@ OpenTelemetry.AutoInstrumentation.Runtime.Managed + true + Generated + $(GeneratedFolder)\$(TargetFramework) + + + + diff --git a/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs b/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs new file mode 100644 index 0000000000..d45a88fd55 --- /dev/null +++ b/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs @@ -0,0 +1,280 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License 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.Immutable; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Text; + +namespace SourceGenerators; + +[Generator] +public class InstrumentationDefinitionsGenerator : IIncrementalGenerator +{ + public void Initialize(IncrementalGeneratorInitializationContext context) + { + var classesWithAttributes = context.SyntaxProvider.CreateSyntaxProvider( + static (node, _) => IsAttributedClass(node), + static (node, _) => GetClassesMarkedByInstrumentMethodAttribute(node)) + .Where(static m => m != null); + + IncrementalValueProvider<(Compilation, ImmutableArray)> compilationAndClasses + = context.CompilationProvider.Combine(classesWithAttributes.Collect()); + + context.RegisterSourceOutput( + compilationAndClasses, + static (context, source) => Generate(source.Item1, source.Item2, context)); + } + + private static void Generate(Compilation compilation, ImmutableArray classesWithAttributes, SourceProductionContext context) + { + if (classesWithAttributes.IsDefaultOrEmpty) + { + return; + } + + var distinctClasses = classesWithAttributes.Distinct(); + + var (traceIntegrations, metricsIntegrations, logsIntegrations) = GetIntegrationsToGenerate(compilation, distinctClasses, context.CancellationToken); + + var result = GenerateInstrumentationDefinitionsPartialClass(traceIntegrations, metricsIntegrations, logsIntegrations); + context.AddSource("InstrumentationDefinitions.g.cs", SourceText.From(result, Encoding.UTF8)); + } + + private static (IReadOnlyCollection TraceIntegrations, IReadOnlyCollection MetricsIntegrations, IReadOnlyCollection LogsIntegrations) GetIntegrationsToGenerate(Compilation compilation, IEnumerable classes, CancellationToken contextCancellationToken) + { + var instrumentAttribute = compilation.GetTypeByMetadataName("OpenTelemetry.AutoInstrumentation.Instrumentations.InstrumentMethodAttribute"); + + if (instrumentAttribute == null) + { + return (Array.Empty(), Array.Empty(), Array.Empty()); + } + + var traceIntegrations = new List(); + var metricsIntegrations = new List(); + var logsIntegrations = new List(); + + foreach (var classDeclaration in classes) + { + var semanticModel = compilation.GetSemanticModel(classDeclaration!.SyntaxTree); + var classNamedTypeSymbol = semanticModel.GetDeclaredSymbol(classDeclaration, contextCancellationToken) as INamedTypeSymbol; + + var attributes = classNamedTypeSymbol!.GetAttributes(); + + foreach (var attribute in attributes) + { + if (!instrumentAttribute.Equals(attribute.AttributeClass, SymbolEqualityComparer.Default)) + { + continue; + } + + var (integrationToGenerate, type) = CreateIntegrationToGenerate(attribute, classNamedTypeSymbol); + + switch (type) + { + case 0: + traceIntegrations.Add(integrationToGenerate); + break; + case 1: + metricsIntegrations.Add(integrationToGenerate); + break; + case 2: + logsIntegrations.Add(integrationToGenerate); + break; + } + } + } + + return (traceIntegrations, metricsIntegrations, logsIntegrations); + } + + private static (IntegrationToGenerate IntegrationToGenerate, int Type) CreateIntegrationToGenerate(AttributeData attribute, INamedTypeSymbol classNamedTypeSymbol) + { + var returnTypeName = attribute.ConstructorArguments[3].Value?.ToString()!; + var parameterTypeNames = attribute.ConstructorArguments[4].Values; + + var targetSignatureTypes = new string[parameterTypeNames.Length + 1]; + + targetSignatureTypes[0] = returnTypeName; + + for (var i = 0; i < parameterTypeNames.Length; i++) + { + targetSignatureTypes[i + 1] = parameterTypeNames[i].Value?.ToString()!; + } + + var integrationToGenerate = new IntegrationToGenerate + { + TargetAssembly = attribute.ConstructorArguments[0].Value?.ToString(), + TargetType = attribute.ConstructorArguments[1].Value?.ToString(), + TargetMethod = attribute.ConstructorArguments[2].Value?.ToString(), + TargetSignatureTypes = targetSignatureTypes, + IntegrationName = attribute.ConstructorArguments[7].Value?.ToString(), + IntegrationType = classNamedTypeSymbol.ToDisplayString() + }; + + var minVersion = attribute.ConstructorArguments[5].Value?.ToString().Split('.')!; + integrationToGenerate.TargetMinimumMajor = int.Parse(minVersion[0]); + if (minVersion.Length > 1 && minVersion[1] != "*") + { + integrationToGenerate.TargetMinimumMinor = int.Parse(minVersion[1]); + } + + if (minVersion.Length > 2 && minVersion[2] != "*") + { + integrationToGenerate.TargetMinimumPatch = int.Parse(minVersion[2]); + } + + var maxVersion = attribute.ConstructorArguments[6].Value?.ToString().Split('.')!; + integrationToGenerate.TargetMaximumMajor = int.Parse(maxVersion[0]); + if (maxVersion.Length > 1 && maxVersion[1] != "*") + { + integrationToGenerate.TargetMaximumMinor = int.Parse(maxVersion[1]); + } + + if (maxVersion.Length > 2 && maxVersion[2] != "*") + { + integrationToGenerate.TargetMaximumPatch = int.Parse(maxVersion[2]); + } + + return (integrationToGenerate, int.Parse(attribute.ConstructorArguments[8].Value!.ToString())); + } + + private static string GenerateInstrumentationDefinitionsPartialClass(IReadOnlyCollection traceIntegrations, IReadOnlyCollection metricsIntegrations, IReadOnlyCollection logsIntegrations) + { + var sb = new StringBuilder() + .AppendFormat( + @"//------------------------------------------------------------------------------ +// +// This code was generated by the InstrumentationDefinitionsGenerator tool. To safely +// modify this file, edit InstrumentMethodAttribute on the classes and +// compile project. + +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using OpenTelemetry.AutoInstrumentation.Configurations; + +namespace OpenTelemetry.AutoInstrumentation; + +internal static partial class InstrumentationDefinitions +{{ + private static readonly string AssemblyFullName = typeof(InstrumentationDefinitions).Assembly.FullName!; + + private static NativeCallTargetDefinition[] GetDefinitionsArray() + {{ + var nativeCallTargetDefinitions = new List({0});", + traceIntegrations.Count + metricsIntegrations.Count + logsIntegrations.Count) + .AppendLine(); + + const string tracesHeader = @" // Traces + var tracerSettings = Instrumentation.TracerSettings.Value; + if (tracerSettings.TracesEnabled)"; + GenerateInstrumentationForSignal(traceIntegrations, sb, tracesHeader, "tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation"); + + const string logsHeader = @" // Logs + var logSettings = Instrumentation.LogSettings.Value; + if (logSettings.LogsEnabled)"; + GenerateInstrumentationForSignal(logsIntegrations, sb, logsHeader, "logSettings.EnabledInstrumentations.Contains(LogInstrumentation"); + + const string metricsHeader = @" // Metrics + var metricSettings = Instrumentation.MetricSettings.Value; + if (metricSettings.MetricsEnabled)"; + GenerateInstrumentationForSignal(metricsIntegrations, sb, metricsHeader, "metricSettings.EnabledInstrumentations.Contains(MetricInstrumentation"); + + sb.AppendLine(@" return nativeCallTargetDefinitions.ToArray(); + } +}"); + + return sb.ToString(); + } + + private static void GenerateInstrumentationForSignal(IReadOnlyCollection integrations, StringBuilder sb, string signalHeader, string conditionPrefix) + { + if (integrations.Count > 0) + { + sb.AppendLine(signalHeader) + .AppendLine("{"); + GenerateIntegrations(integrations, sb, conditionPrefix); + + sb.AppendLine(" }") + .AppendLine(); + } + } + + private static void GenerateIntegrations(IReadOnlyCollection integrations, StringBuilder sb, string conditionPrefix) + { + var gropedByIntegrationName = integrations.GroupBy(x => x.IntegrationName); + + foreach (var group in gropedByIntegrationName) + { + sb.Append(" // "); + sb.AppendLine(group.Key); + sb.AppendFormat( + @" if ({0}.{1})) + {{", + conditionPrefix, + group.Key); + sb.AppendLine(); + + foreach (var integration in group) + { + sb.AppendFormat( + " nativeCallTargetDefinitions.Add(new(\"{0}\", \"{1}\", \"{2}\", new[] {{{3}}}, {4}, {5}, {6}, {7}, {8}, {9}, AssemblyFullName, \"{10}\"));", + integration.TargetAssembly, + integration.TargetType, + integration.TargetMethod, + string.Join(", ", integration.TargetSignatureTypes!.Select(x => $"\"{x}\"")), + integration.TargetMinimumMajor, + integration.TargetMinimumMinor, + integration.TargetMinimumPatch, + integration.TargetMaximumMajor, + integration.TargetMaximumMinor, + integration.TargetMaximumPatch, + integration.IntegrationType); + sb.AppendLine(); + } + + sb.AppendLine(" }"); + sb.AppendLine(); + } + } + + private static bool IsAttributedClass(SyntaxNode node) + { + return node is ClassDeclarationSyntax { AttributeLists.Count: > 0 }; + } + + private static ClassDeclarationSyntax? GetClassesMarkedByInstrumentMethodAttribute(GeneratorSyntaxContext context) + { + var classDeclarationSyntax = (ClassDeclarationSyntax)context.Node; + + foreach (var attributeListSyntax in classDeclarationSyntax.AttributeLists) + { + foreach (var attributeSyntax in attributeListSyntax.Attributes) + { + if (attributeSyntax.Name.ToString() is "InstrumentMethod" or "InstrumentMethodAttribute" or "GraphQLExecuteAsync" or "AdoNetTargetSignature") + { + return classDeclarationSyntax; + } + } + } + + return null; + } +} diff --git a/src/SourceGenerators/IntegrationToGenerate.cs b/src/SourceGenerators/IntegrationToGenerate.cs new file mode 100644 index 0000000000..1af42f2bf1 --- /dev/null +++ b/src/SourceGenerators/IntegrationToGenerate.cs @@ -0,0 +1,44 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License 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 SourceGenerators; + +internal class IntegrationToGenerate +{ + public string? IntegrationName { get; set; } + + public string? TargetAssembly { get; set; } + + public string? TargetType { get; set; } + + public string? TargetMethod { get; set; } + + public int TargetMinimumMajor { get; set; } + + public int TargetMinimumMinor { get; set; } + + public int TargetMinimumPatch { get; set; } + + public int TargetMaximumMajor { get; set; } + + public int TargetMaximumMinor { get; set; } = 65535; + + public int TargetMaximumPatch { get; set; } = 65535; + + public string? IntegrationType { get; set; } + + public string[]? TargetSignatureTypes { get; set; } +} diff --git a/src/SourceGenerators/SourceGenerators.csproj b/src/SourceGenerators/SourceGenerators.csproj new file mode 100644 index 0000000000..3c6dfb7e3d --- /dev/null +++ b/src/SourceGenerators/SourceGenerators.csproj @@ -0,0 +1,18 @@ + + + + netstandard2.0 + false + true + true + $(NoWarn);SA1600;CS1591 + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + From 7b0f29e0c03ed4f0521fa45cf6ba602d33582f3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Fri, 9 Jun 2023 08:45:14 +0200 Subject: [PATCH 03/10] Sync header with real project name --- src/Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 66a13bff5b..6215f2f0d0 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -34,7 +34,7 @@ - + From 80974e2705f34789dd189c692856107d45f860a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Fri, 9 Jun 2023 08:49:42 +0200 Subject: [PATCH 04/10] Document public SourceGenerator and Remove NoWarn --- src/SourceGenerators/InstrumentationDefinitionsGenerator.cs | 5 +++++ src/SourceGenerators/SourceGenerators.csproj | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs b/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs index d45a88fd55..98fbbc9ee2 100644 --- a/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs +++ b/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs @@ -22,9 +22,14 @@ namespace SourceGenerators; +/// +/// Generates InstrumentationDefinitions for byte code instrumentation. +/// It is based on InstrumentMethodAttribute. +/// [Generator] public class InstrumentationDefinitionsGenerator : IIncrementalGenerator { + /// public void Initialize(IncrementalGeneratorInitializationContext context) { var classesWithAttributes = context.SyntaxProvider.CreateSyntaxProvider( diff --git a/src/SourceGenerators/SourceGenerators.csproj b/src/SourceGenerators/SourceGenerators.csproj index 3c6dfb7e3d..df9a499045 100644 --- a/src/SourceGenerators/SourceGenerators.csproj +++ b/src/SourceGenerators/SourceGenerators.csproj @@ -5,7 +5,6 @@ false true true - $(NoWarn);SA1600;CS1591 From f02feab0ac6f361fbf3b6babe83aa2e3aa99abbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Fri, 9 Jun 2023 08:50:33 +0200 Subject: [PATCH 05/10] Remove non-used references to attributes --- src/SourceGenerators/InstrumentationDefinitionsGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs b/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs index 98fbbc9ee2..babe0f6cd4 100644 --- a/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs +++ b/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs @@ -273,7 +273,7 @@ private static bool IsAttributedClass(SyntaxNode node) { foreach (var attributeSyntax in attributeListSyntax.Attributes) { - if (attributeSyntax.Name.ToString() is "InstrumentMethod" or "InstrumentMethodAttribute" or "GraphQLExecuteAsync" or "AdoNetTargetSignature") + if (attributeSyntax.Name.ToString() is "InstrumentMethod" or "InstrumentMethodAttribute") { return classDeclarationSyntax; } From 3705b3f86980974f86272058a87486ed2a395147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Fri, 9 Jun 2023 12:32:35 +0200 Subject: [PATCH 06/10] PR feedback - better naming for local variable --- src/SourceGenerators/InstrumentationDefinitionsGenerator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs b/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs index babe0f6cd4..95970006ec 100644 --- a/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs +++ b/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs @@ -32,13 +32,13 @@ public class InstrumentationDefinitionsGenerator : IIncrementalGenerator /// public void Initialize(IncrementalGeneratorInitializationContext context) { - var classesWithAttributes = context.SyntaxProvider.CreateSyntaxProvider( + var instrumentationClasses = context.SyntaxProvider.CreateSyntaxProvider( static (node, _) => IsAttributedClass(node), static (node, _) => GetClassesMarkedByInstrumentMethodAttribute(node)) .Where(static m => m != null); IncrementalValueProvider<(Compilation, ImmutableArray)> compilationAndClasses - = context.CompilationProvider.Combine(classesWithAttributes.Collect()); + = context.CompilationProvider.Combine(instrumentationClasses.Collect()); context.RegisterSourceOutput( compilationAndClasses, From 7bb5f9b542e6e46c177974f02f682b959e5be57c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Tue, 13 Jun 2023 08:13:01 +0200 Subject: [PATCH 07/10] PR feedback --- .../InstrumentationDefinitionsGenerator.cs | 227 ++++++++---------- src/SourceGenerators/IntegrationToGenerate.cs | 29 +-- src/SourceGenerators/TargetToGenerate.cs | 46 ++++ 3 files changed, 151 insertions(+), 151 deletions(-) create mode 100644 src/SourceGenerators/TargetToGenerate.cs diff --git a/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs b/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs index 95970006ec..1db3020681 100644 --- a/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs +++ b/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs @@ -29,137 +29,115 @@ namespace SourceGenerators; [Generator] public class InstrumentationDefinitionsGenerator : IIncrementalGenerator { + private const string InstrumentMethodAttributeName = "OpenTelemetry.AutoInstrumentation.Instrumentations.InstrumentMethodAttribute"; + /// public void Initialize(IncrementalGeneratorInitializationContext context) { - var instrumentationClasses = context.SyntaxProvider.CreateSyntaxProvider( - static (node, _) => IsAttributedClass(node), - static (node, _) => GetClassesMarkedByInstrumentMethodAttribute(node)) + var instrumentationClasses = context.SyntaxProvider.ForAttributeWithMetadataName( + InstrumentMethodAttributeName, + (node, _) => node is ClassDeclarationSyntax, + GetClassesMarkedByInstrumentMethodAttribute) .Where(static m => m != null); - IncrementalValueProvider<(Compilation, ImmutableArray)> compilationAndClasses - = context.CompilationProvider.Combine(instrumentationClasses.Collect()); + var instrumentationClassesAsOneCollection = instrumentationClasses.Collect(); context.RegisterSourceOutput( - compilationAndClasses, - static (context, source) => Generate(source.Item1, source.Item2, context)); + instrumentationClassesAsOneCollection, + static (context, instrumentationClasses) => Generate(in instrumentationClasses, context)); } - private static void Generate(Compilation compilation, ImmutableArray classesWithAttributes, SourceProductionContext context) + private static void Generate(in ImmutableArray instrumentationClasses, SourceProductionContext context) { - if (classesWithAttributes.IsDefaultOrEmpty) + if (instrumentationClasses.IsDefaultOrEmpty) { return; } - var distinctClasses = classesWithAttributes.Distinct(); - - var (traceIntegrations, metricsIntegrations, logsIntegrations) = GetIntegrationsToGenerate(compilation, distinctClasses, context.CancellationToken); - - var result = GenerateInstrumentationDefinitionsPartialClass(traceIntegrations, metricsIntegrations, logsIntegrations); + var result = GenerateInstrumentationDefinitionsPartialClass(instrumentationClasses); context.AddSource("InstrumentationDefinitions.g.cs", SourceText.From(result, Encoding.UTF8)); } - private static (IReadOnlyCollection TraceIntegrations, IReadOnlyCollection MetricsIntegrations, IReadOnlyCollection LogsIntegrations) GetIntegrationsToGenerate(Compilation compilation, IEnumerable classes, CancellationToken contextCancellationToken) + private static TargetToGenerate CreateTargetToGenerate(AttributeData attribute) { - var instrumentAttribute = compilation.GetTypeByMetadataName("OpenTelemetry.AutoInstrumentation.Instrumentations.InstrumentMethodAttribute"); + var returnTypeName = attribute.ConstructorArguments[3].Value?.ToString()!; + var parameterTypeNames = attribute.ConstructorArguments[4].Values; + + var targetSignatureTypesBuilder = new StringBuilder(); - if (instrumentAttribute == null) + targetSignatureTypesBuilder.AppendFormat("\"{0}\"", returnTypeName); + + foreach (var parameterTypeName in parameterTypeNames) { - return (Array.Empty(), Array.Empty(), Array.Empty()); + targetSignatureTypesBuilder.AppendFormat(", \"{0}\"", parameterTypeName.Value); } - var traceIntegrations = new List(); - var metricsIntegrations = new List(); - var logsIntegrations = new List(); + var signalType = int.Parse(attribute.ConstructorArguments[8].Value!.ToString()); + var integrationName = attribute.ConstructorArguments[7].Value!.ToString(); + var targetAssembly = attribute.ConstructorArguments[0].Value!.ToString(); + var targetType = attribute.ConstructorArguments[1].Value!.ToString(); + var targetMethod = attribute.ConstructorArguments[2].Value!.ToString(); - foreach (var classDeclaration in classes) - { - var semanticModel = compilation.GetSemanticModel(classDeclaration!.SyntaxTree); - var classNamedTypeSymbol = semanticModel.GetDeclaredSymbol(classDeclaration, contextCancellationToken) as INamedTypeSymbol; + var minVersion = attribute.ConstructorArguments[5].Value?.ToString().Split('.')!; - var attributes = classNamedTypeSymbol!.GetAttributes(); + var targetMinimumMajor = int.Parse(minVersion[0]); + var targetMinimumMinor = minVersion.Length > 1 && minVersion[1] != "*" ? int.Parse(minVersion[1]) : ushort.MinValue; + var targetMinimumPatch = minVersion.Length > 2 && minVersion[2] != "*" ? int.Parse(minVersion[2]) : ushort.MinValue; - foreach (var attribute in attributes) - { - if (!instrumentAttribute.Equals(attribute.AttributeClass, SymbolEqualityComparer.Default)) - { - continue; - } + var maxVersion = attribute.ConstructorArguments[6].Value?.ToString().Split('.')!; + var targetMaximumMajor = int.Parse(maxVersion[0]); + var targetMaximumMinor = maxVersion.Length > 1 && maxVersion[1] != "*" ? int.Parse(maxVersion[1]) : ushort.MaxValue; + var targetMaximumPatch = maxVersion.Length > 2 && maxVersion[2] != "*" ? int.Parse(maxVersion[2]) : ushort.MaxValue; + + return new TargetToGenerate(signalType, integrationName, targetAssembly, targetType, targetMethod, targetMinimumMajor, targetMinimumMinor, targetMinimumPatch, targetMaximumMajor, targetMaximumMinor, targetMaximumPatch, targetSignatureTypesBuilder.ToString()); + } + + private static string GenerateInstrumentationDefinitionsPartialClass(ImmutableArray integrationClasses) + { + var tracesByIntegrationName = new Dictionary>(); + var logsByIntegrationName = new Dictionary>(); + var metricsByIntegrationName = new Dictionary>(); - var (integrationToGenerate, type) = CreateIntegrationToGenerate(attribute, classNamedTypeSymbol); + var instrumentationCount = 0; - switch (type) + foreach (var integrationToGenerate in integrationClasses) + { + foreach (var targetToGenerate in integrationToGenerate!.Value.Targets) + { + Dictionary> byName; + switch (targetToGenerate.SignalType) { case 0: - traceIntegrations.Add(integrationToGenerate); + byName = tracesByIntegrationName; break; case 1: - metricsIntegrations.Add(integrationToGenerate); + byName = metricsByIntegrationName; break; case 2: - logsIntegrations.Add(integrationToGenerate); + byName = logsByIntegrationName; break; + default: + continue; } - } - } - - return (traceIntegrations, metricsIntegrations, logsIntegrations); - } - - private static (IntegrationToGenerate IntegrationToGenerate, int Type) CreateIntegrationToGenerate(AttributeData attribute, INamedTypeSymbol classNamedTypeSymbol) - { - var returnTypeName = attribute.ConstructorArguments[3].Value?.ToString()!; - var parameterTypeNames = attribute.ConstructorArguments[4].Values; - - var targetSignatureTypes = new string[parameterTypeNames.Length + 1]; - - targetSignatureTypes[0] = returnTypeName; - - for (var i = 0; i < parameterTypeNames.Length; i++) - { - targetSignatureTypes[i + 1] = parameterTypeNames[i].Value?.ToString()!; - } - var integrationToGenerate = new IntegrationToGenerate - { - TargetAssembly = attribute.ConstructorArguments[0].Value?.ToString(), - TargetType = attribute.ConstructorArguments[1].Value?.ToString(), - TargetMethod = attribute.ConstructorArguments[2].Value?.ToString(), - TargetSignatureTypes = targetSignatureTypes, - IntegrationName = attribute.ConstructorArguments[7].Value?.ToString(), - IntegrationType = classNamedTypeSymbol.ToDisplayString() - }; - - var minVersion = attribute.ConstructorArguments[5].Value?.ToString().Split('.')!; - integrationToGenerate.TargetMinimumMajor = int.Parse(minVersion[0]); - if (minVersion.Length > 1 && minVersion[1] != "*") - { - integrationToGenerate.TargetMinimumMinor = int.Parse(minVersion[1]); - } - - if (minVersion.Length > 2 && minVersion[2] != "*") - { - integrationToGenerate.TargetMinimumPatch = int.Parse(minVersion[2]); - } - - var maxVersion = attribute.ConstructorArguments[6].Value?.ToString().Split('.')!; - integrationToGenerate.TargetMaximumMajor = int.Parse(maxVersion[0]); - if (maxVersion.Length > 1 && maxVersion[1] != "*") - { - integrationToGenerate.TargetMaximumMinor = int.Parse(maxVersion[1]); - } + if (byName.TryGetValue(targetToGenerate.IntegrationName, out var value)) + { + value.Add((integrationToGenerate.Value.IntegrationType, targetToGenerate)); + } + else + { + byName.Add( + targetToGenerate.IntegrationName, + new List<(string IntegrationType, TargetToGenerate Target)> + { + (integrationToGenerate.Value.IntegrationType, targetToGenerate) + }); + } - if (maxVersion.Length > 2 && maxVersion[2] != "*") - { - integrationToGenerate.TargetMaximumPatch = int.Parse(maxVersion[2]); + instrumentationCount++; + } } - return (integrationToGenerate, int.Parse(attribute.ConstructorArguments[8].Value!.ToString())); - } - - private static string GenerateInstrumentationDefinitionsPartialClass(IReadOnlyCollection traceIntegrations, IReadOnlyCollection metricsIntegrations, IReadOnlyCollection logsIntegrations) - { var sb = new StringBuilder() .AppendFormat( @"//------------------------------------------------------------------------------ @@ -184,23 +162,23 @@ internal static partial class InstrumentationDefinitions private static NativeCallTargetDefinition[] GetDefinitionsArray() {{ var nativeCallTargetDefinitions = new List({0});", - traceIntegrations.Count + metricsIntegrations.Count + logsIntegrations.Count) + instrumentationCount) .AppendLine(); const string tracesHeader = @" // Traces var tracerSettings = Instrumentation.TracerSettings.Value; if (tracerSettings.TracesEnabled)"; - GenerateInstrumentationForSignal(traceIntegrations, sb, tracesHeader, "tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation"); + GenerateInstrumentationForSignal(tracesByIntegrationName, sb, tracesHeader, "tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation"); const string logsHeader = @" // Logs var logSettings = Instrumentation.LogSettings.Value; if (logSettings.LogsEnabled)"; - GenerateInstrumentationForSignal(logsIntegrations, sb, logsHeader, "logSettings.EnabledInstrumentations.Contains(LogInstrumentation"); + GenerateInstrumentationForSignal(logsByIntegrationName, sb, logsHeader, "logSettings.EnabledInstrumentations.Contains(LogInstrumentation"); const string metricsHeader = @" // Metrics var metricSettings = Instrumentation.MetricSettings.Value; if (metricSettings.MetricsEnabled)"; - GenerateInstrumentationForSignal(metricsIntegrations, sb, metricsHeader, "metricSettings.EnabledInstrumentations.Contains(MetricInstrumentation"); + GenerateInstrumentationForSignal(metricsByIntegrationName, sb, metricsHeader, "metricSettings.EnabledInstrumentations.Contains(MetricInstrumentation"); sb.AppendLine(@" return nativeCallTargetDefinitions.ToArray(); } @@ -209,7 +187,7 @@ private static NativeCallTargetDefinition[] GetDefinitionsArray() return sb.ToString(); } - private static void GenerateInstrumentationForSignal(IReadOnlyCollection integrations, StringBuilder sb, string signalHeader, string conditionPrefix) + private static void GenerateInstrumentationForSignal(Dictionary> integrations, StringBuilder sb, string signalHeader, string conditionPrefix) { if (integrations.Count > 0) { @@ -222,11 +200,9 @@ private static void GenerateInstrumentationForSignal(IReadOnlyCollection integrations, StringBuilder sb, string conditionPrefix) + private static void GenerateIntegrations(Dictionary> integrationsByName, StringBuilder sb, string conditionPrefix) { - var gropedByIntegrationName = integrations.GroupBy(x => x.IntegrationName); - - foreach (var group in gropedByIntegrationName) + foreach (var group in integrationsByName) { sb.Append(" // "); sb.AppendLine(group.Key); @@ -237,20 +213,20 @@ private static void GenerateIntegrations(IReadOnlyCollection $"\"{x}\"")), - integration.TargetMinimumMajor, - integration.TargetMinimumMinor, - integration.TargetMinimumPatch, - integration.TargetMaximumMajor, - integration.TargetMaximumMinor, - integration.TargetMaximumPatch, + integration.Target.Assembly, + integration.Target.Type, + integration.Target.Method, + integration.Target.SignatureTypes, + integration.Target.MinimumMajor, + integration.Target.MinimumMinor, + integration.Target.MinimumPatch, + integration.Target.MaximumMajor, + integration.Target.MaximumMinor, + integration.Target.MaximumPatch, integration.IntegrationType); sb.AppendLine(); } @@ -260,26 +236,23 @@ private static void GenerateIntegrations(IReadOnlyCollection 0 }; - } + if (context.TargetSymbol is not INamedTypeSymbol classSymbol) + { + return null; + } - private static ClassDeclarationSyntax? GetClassesMarkedByInstrumentMethodAttribute(GeneratorSyntaxContext context) - { - var classDeclarationSyntax = (ClassDeclarationSyntax)context.Node; + var integrationType = classSymbol.ToDisplayString(); - foreach (var attributeListSyntax in classDeclarationSyntax.AttributeLists) + var targets = new List(); + + foreach (var contextAttribute in context.Attributes) { - foreach (var attributeSyntax in attributeListSyntax.Attributes) - { - if (attributeSyntax.Name.ToString() is "InstrumentMethod" or "InstrumentMethodAttribute") - { - return classDeclarationSyntax; - } - } + var targetToGenerate = CreateTargetToGenerate(contextAttribute); + targets.Add(targetToGenerate); } - return null; + return new IntegrationToGenerate(integrationType, targets.ToImmutableArray()); } } diff --git a/src/SourceGenerators/IntegrationToGenerate.cs b/src/SourceGenerators/IntegrationToGenerate.cs index 1af42f2bf1..d997e489ad 100644 --- a/src/SourceGenerators/IntegrationToGenerate.cs +++ b/src/SourceGenerators/IntegrationToGenerate.cs @@ -14,31 +14,12 @@ // limitations under the License. // +using System.Collections.Immutable; + namespace SourceGenerators; -internal class IntegrationToGenerate +internal readonly record struct IntegrationToGenerate(string IntegrationType, ImmutableArray Targets) { - public string? IntegrationName { get; set; } - - public string? TargetAssembly { get; set; } - - public string? TargetType { get; set; } - - public string? TargetMethod { get; set; } - - public int TargetMinimumMajor { get; set; } - - public int TargetMinimumMinor { get; set; } - - public int TargetMinimumPatch { get; set; } - - public int TargetMaximumMajor { get; set; } - - public int TargetMaximumMinor { get; set; } = 65535; - - public int TargetMaximumPatch { get; set; } = 65535; - - public string? IntegrationType { get; set; } - - public string[]? TargetSignatureTypes { get; set; } + public readonly string IntegrationType = IntegrationType; + public readonly ImmutableArray Targets = Targets; } diff --git a/src/SourceGenerators/TargetToGenerate.cs b/src/SourceGenerators/TargetToGenerate.cs new file mode 100644 index 0000000000..22fc2d39e4 --- /dev/null +++ b/src/SourceGenerators/TargetToGenerate.cs @@ -0,0 +1,46 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License 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.Immutable; + +namespace SourceGenerators; + +internal readonly record struct TargetToGenerate(int SignalType, string IntegrationName, string Assembly, string Type, string Method, int MinimumMajor, int MinimumMinor, int MinimumPatch, int MaximumMajor, int MaximumMinor, int MaximumPatch, string SignatureTypes) +{ + public readonly int SignalType = SignalType; + + public readonly string IntegrationName = IntegrationName; + + public readonly string Assembly = Assembly; + + public readonly string Type = Type; + + public readonly string Method = Method; + + public readonly int MinimumMajor = MinimumMajor; + + public readonly int MinimumMinor = MinimumMinor; + + public readonly int MinimumPatch = MinimumPatch; + + public readonly int MaximumMajor = MaximumMajor; + + public readonly int MaximumMinor = MaximumMinor; + + public readonly int MaximumPatch = MaximumPatch; + + public readonly string SignatureTypes = SignatureTypes; +} From 51221f28ad2cfbb229a3bdfe8978021f4ba807dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Tue, 13 Jun 2023 09:03:40 +0200 Subject: [PATCH 08/10] Update dotnet-format to support records --- .github/workflows/dotnet-format.yml | 4 +- .../AspNetCoreMvc/GlobalSuppressions.cs | 24 ++++++++++ .../NativeCallTargetDefinition.cs | 44 +++++++++---------- src/SourceGenerators/TargetToGenerate.cs | 2 - test/IntegrationTests/Helpers/TestHelper.cs | 12 ----- .../StarWarsSubscription.cs | 5 ++- 6 files changed, 52 insertions(+), 39 deletions(-) create mode 100644 examples/playground/AspNetCoreMvc/GlobalSuppressions.cs diff --git a/.github/workflows/dotnet-format.yml b/.github/workflows/dotnet-format.yml index 808eff0ef6..c12ed58a1f 100644 --- a/.github/workflows/dotnet-format.yml +++ b/.github/workflows/dotnet-format.yml @@ -28,7 +28,7 @@ jobs: dotnet-version: 7.0.302 - name: Install format tool - run: dotnet tool install -g dotnet-format + run: dotnet tool install -g dotnet-format --version "7.*" --add-source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json - name: dotnet format - run: dotnet-format --folder --check + run: dotnet-format .\OpenTelemetry.AutoInstrumentation.sln --no-restore --verify-no-changes diff --git a/examples/playground/AspNetCoreMvc/GlobalSuppressions.cs b/examples/playground/AspNetCoreMvc/GlobalSuppressions.cs new file mode 100644 index 0000000000..f405b75d6d --- /dev/null +++ b/examples/playground/AspNetCoreMvc/GlobalSuppressions.cs @@ -0,0 +1,24 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License 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. +// + +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented", Justification = "Reviewed.")] diff --git a/src/OpenTelemetry.AutoInstrumentation/NativeCallTargetDefinition.cs b/src/OpenTelemetry.AutoInstrumentation/NativeCallTargetDefinition.cs index 1f81487386..49b9a3a9b6 100644 --- a/src/OpenTelemetry.AutoInstrumentation/NativeCallTargetDefinition.cs +++ b/src/OpenTelemetry.AutoInstrumentation/NativeCallTargetDefinition.cs @@ -18,28 +18,28 @@ namespace OpenTelemetry.AutoInstrumentation; - // ! ██ - // ██░░██ - // ██░░░░░░██ - // ██░░░░░░░░░░██ - // ██░░░░░░░░░░██ - // ██░░░░░░░░░░░░░░██ - // ██░░░░░░██████░░░░░░██ - // ██░░░░░░██████░░░░░░██ - // ██░░░░░░░░██████░░░░░░░░██ - // ██░░░░░░░░██████░░░░░░░░██ - // ██░░░░░░░░░░██████░░░░░░░░░░██ - // ██░░░░░░░░░░░░██████░░░░░░░░░░░░██ - // ██░░░░░░░░░░░░██████░░░░░░░░░░░░██ - // ██░░░░░░░░░░░░░░██████░░░░░░░░░░░░░░██ - // ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░██ - // ██░░░░░░░░░░░░░░░░██████░░░░░░░░░░░░░░░░██ - // ██░░░░░░░░░░░░░░░░██████░░░░░░░░░░░░░░░░██ - // ██░░░░░░░░░░░░░░░░░░██████░░░░░░░░░░░░░░░░░░██ - // ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░██ - // ██████████████████████████████████████████ - // - // This struct is marshalled for use in the native layer, so this struct must be kept in sync with the _CallTargetDefinition native struct +// ! ██ +// ██░░██ +// ██░░░░░░██ +// ██░░░░░░░░░░██ +// ██░░░░░░░░░░██ +// ██░░░░░░░░░░░░░░██ +// ██░░░░░░██████░░░░░░██ +// ██░░░░░░██████░░░░░░██ +// ██░░░░░░░░██████░░░░░░░░██ +// ██░░░░░░░░██████░░░░░░░░██ +// ██░░░░░░░░░░██████░░░░░░░░░░██ +// ██░░░░░░░░░░░░██████░░░░░░░░░░░░██ +// ██░░░░░░░░░░░░██████░░░░░░░░░░░░██ +// ██░░░░░░░░░░░░░░██████░░░░░░░░░░░░░░██ +// ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░██ +// ██░░░░░░░░░░░░░░░░██████░░░░░░░░░░░░░░░░██ +// ██░░░░░░░░░░░░░░░░██████░░░░░░░░░░░░░░░░██ +// ██░░░░░░░░░░░░░░░░░░██████░░░░░░░░░░░░░░░░░░██ +// ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░██ +// ██████████████████████████████████████████ +// +// This struct is marshalled for use in the native layer, so this struct must be kept in sync with the _CallTargetDefinition native struct [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct NativeCallTargetDefinition diff --git a/src/SourceGenerators/TargetToGenerate.cs b/src/SourceGenerators/TargetToGenerate.cs index 22fc2d39e4..72c5359a1d 100644 --- a/src/SourceGenerators/TargetToGenerate.cs +++ b/src/SourceGenerators/TargetToGenerate.cs @@ -14,8 +14,6 @@ // limitations under the License. // -using System.Collections.Immutable; - namespace SourceGenerators; internal readonly record struct TargetToGenerate(int SignalType, string IntegrationName, string Assembly, string Type, string Method, int MinimumMajor, int MinimumMinor, int MinimumPatch, int MaximumMajor, int MaximumMinor, int MaximumPatch, string SignatureTypes) diff --git a/test/IntegrationTests/Helpers/TestHelper.cs b/test/IntegrationTests/Helpers/TestHelper.cs index f3d0cb51ec..45ca0bd821 100644 --- a/test/IntegrationTests/Helpers/TestHelper.cs +++ b/test/IntegrationTests/Helpers/TestHelper.cs @@ -42,9 +42,6 @@ protected TestHelper(string testApplicationName, ITestOutputHelper output, strin protected ITestOutputHelper Output { get; } - /// - /// Gets the path for the test assembly, not the shadow copy created by xunit. - /// public string GetTestAssemblyPath() { #if NETFRAMEWORK @@ -99,10 +96,6 @@ public void EnableDefaultExporters() RemoveEnvironmentVariable("OTEL_LOGS_EXPORTER"); } - /// - /// RunTestApplication starts the test application, wait up to DefaultProcessTimeout. - /// Assertion exceptions are thrown if it timed out or the exit code is non-zero. - /// public (string StandardOutput, string ErrorOutput) RunTestApplication(TestSettings? testSettings = null) { testSettings ??= new(); @@ -128,11 +121,6 @@ public void EnableDefaultExporters() return (helper.StandardOutput, helper.ErrorOutput); } - /// - /// StartTestApplication starts the test application - /// and returns the Process instance for further interaction. - /// - /// Test application process public Process? StartTestApplication(TestSettings? testSettings = null) { testSettings ??= new(); diff --git a/test/test-applications/integrations/TestApplication.GraphQL/StarWarsExtensions/StarWarsSubscription.cs b/test/test-applications/integrations/TestApplication.GraphQL/StarWarsExtensions/StarWarsSubscription.cs index bde65d5212..a971d88b1f 100644 --- a/test/test-applications/integrations/TestApplication.GraphQL/StarWarsExtensions/StarWarsSubscription.cs +++ b/test/test-applications/integrations/TestApplication.GraphQL/StarWarsExtensions/StarWarsSubscription.cs @@ -24,11 +24,14 @@ namespace TestApplication.GraphQL.StarWarsExtensions; +/// +/// StarWars Subscription +/// /// /// This is an example JSON request for a subscription /// { /// "query": "subscription HumanAddedSub{ humanAdded { name } }", -/// } +/// }. /// public class StarWarsSubscription : ObjectGraphType { From 129778794dd799f3b8c9175c7daff6d9a27fb1be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Tue, 13 Jun 2023 09:16:34 +0200 Subject: [PATCH 09/10] handle cancellation token --- src/SourceGenerators/InstrumentationDefinitionsGenerator.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs b/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs index 1db3020681..4a60d7791b 100644 --- a/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs +++ b/src/SourceGenerators/InstrumentationDefinitionsGenerator.cs @@ -249,6 +249,7 @@ private static void GenerateIntegrations(Dictionary Date: Wed, 14 Jun 2023 06:45:12 +0200 Subject: [PATCH 10/10] internal comments - pr feedback --- test/IntegrationTests/Helpers/TestHelper.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/IntegrationTests/Helpers/TestHelper.cs b/test/IntegrationTests/Helpers/TestHelper.cs index 45ca0bd821..a24a9d10e1 100644 --- a/test/IntegrationTests/Helpers/TestHelper.cs +++ b/test/IntegrationTests/Helpers/TestHelper.cs @@ -44,6 +44,7 @@ protected TestHelper(string testApplicationName, ITestOutputHelper output, strin public string GetTestAssemblyPath() { + // Gets the path for the test assembly, not the shadow copy created by xunit. #if NETFRAMEWORK // CodeBase is deprecated outside .NET Framework, instead of suppressing the error // build the code as per recommendation for each runtime. @@ -98,6 +99,8 @@ public void EnableDefaultExporters() public (string StandardOutput, string ErrorOutput) RunTestApplication(TestSettings? testSettings = null) { + // RunTestApplication starts the test application, wait up to DefaultProcessTimeout. + // Assertion exceptions are thrown if it timed out or the exit code is non-zero. testSettings ??= new(); using var process = StartTestApplication(testSettings); Output.WriteLine($"ProcessName: " + process?.ProcessName); @@ -123,6 +126,8 @@ public void EnableDefaultExporters() public Process? StartTestApplication(TestSettings? testSettings = null) { + // StartTestApplication starts the test application + // and returns the Process instance for further interaction. testSettings ??= new(); // get path to test application that the profiler will attach to