ASP.NET - auto registration for HttpModule (#2569)

Co-authored-by: Mateusz Łach <mateusza@splunk.com>
This commit is contained in:
Piotr Kiełkowicz 2023-05-25 10:57:34 +02:00 committed by GitHub
parent d54f7f548b
commit 23aea72241
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 117 additions and 76 deletions

View File

@ -15,6 +15,9 @@ This component adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.h
### Changed
- ASP.NET instrumentation no longer requires manual modification
of config files to include `TelemetryHttpModule`.
### Deprecated
### Removed

View File

@ -114,6 +114,9 @@ partial class Build
.SetProperty("PublishProfile", aspNetProject.Directory / "Properties" / "PublishProfiles" / $"FolderProfile.{BuildConfiguration}.pubxml")
.SetTargetPath(aspNetProject));
var localCopyTracerHome = aspNetProject.Directory / "bin" / "tracer-home";
CopyDirectoryRecursively(TracerHomeDirectory, localCopyTracerHome);
DockerBuild(x => x
.SetPath(".")
.SetBuildArg($"configuration={BuildConfiguration}", $"windowscontainer_version={WindowsContainerVersion}")
@ -121,6 +124,8 @@ partial class Build
.SetTag(Path.GetFileNameWithoutExtension(aspNetProject).Replace(".", "-").ToLowerInvariant())
.SetProcessWorkingDirectory(aspNetProject.Directory)
);
Directory.Delete(localCopyTracerHome, true);
});
Target GenerateNetFxTransientDependencies => _ => _

View File

@ -123,7 +123,7 @@ due to lack of stable semantic convention.
| ID | Instrumented library | Supported versions | Instrumentation type | Status |
|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| `ASPNET` | ASP.NET (.NET Framework) MVC / WebApi \[1\] **Not supported on .NET** | * | source | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
| `ASPNET` | ASP.NET (.NET Framework) MVC / WebApi \[1\] **Not supported on .NET** | * | source & bytecode | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
| `ASPNETCORE` | ASP.NET Core **Not supported on .NET Framework** | * | source | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
| `ELASTICSEARCH` | [Elastic.Clients.Elasticsearch](https://www.nuget.org/packages/Elastic.Clients.Elasticsearch) | ≥8.0.0 | source | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
| `ENTITYFRAMEWORKCORE` | [Microsoft.EntityFrameworkCore](https://www.nuget.org/packages/) **Not supported on .NET Framework** | ≥6.0.12 | source | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
@ -158,7 +158,7 @@ due to lack of stable semantic convention.
| ID | Instrumented library | Documentation | Supported versions | Instrumentation type | Status |
|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| `ASPNET` | ASP.NET Framework \[1\] **Not supported on .NET** | [ASP.NET metrics](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/blob/main/src/OpenTelemetry.Instrumentation.AspNet/README.md#list-of-metrics-produced) | * | source | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
| `ASPNET` | ASP.NET Framework \[1\] **Not supported on .NET** | [ASP.NET metrics](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/blob/main/src/OpenTelemetry.Instrumentation.AspNet/README.md#list-of-metrics-produced) | * | source & bytecode | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
| `ASPNETCORE` | ASP.NET Core \[2\] **Not supported on .NET Framework** | [ASP.NET Core metrics](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Instrumentation.AspNetCore/README.md#list-of-metrics-produced) | * | source | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
| `HTTPCLIENT` | [System.Net.Http.HttpClient](https://docs.microsoft.com/dotnet/api/system.net.http.httpclient) and [System.Net.HttpWebRequest](https://docs.microsoft.com/dotnet/api/system.net.httpwebrequest) | [HttpClient metrics](https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/src/OpenTelemetry.Instrumentation.Http#metrics) | * | source | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
| `NETRUNTIME` | [OpenTelemetry.Instrumentation.Runtime](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.Runtime) | [Process metrics](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/tree/main/src/OpenTelemetry.Instrumentation.Process#metrics) | * | source | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |

View File

@ -19,71 +19,6 @@ Register-OpenTelemetryForIIS
> **Warning**
> `Register-OpenTelemetryForIIS` performs IIS restart.
### Add TelemetryHttpModule ASP.NET HTTP module
> **Note**
> This is NOT required for ASP.NET Core deployments.
This step is necessary only for ASP.NET (.NET Framework).
> **Note**
> There are three distinct options.
Add `OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule, OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule`
by modifying and extending `web.config` (first two options)
or `applicationHost.config` (third option).
```xml
<system.web>
<httpModules>
<add name="TelemetryHttpModule" type="OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule, OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule" />
</httpModules>
</system.web>
```
> **Warning**
> After applying above changes you might experience following error as this configuration
> requires IIS classic mode.
> In order to fix it you can switch to classic mode or use other options. ![error](./images/iis-500-22-error.png).
```xml
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules>
<remove name="TelemetryHttpModule" />
<add name="TelemetryHttpModule" type="OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule, OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule" preCondition="managedHandler" />
</modules>
</system.webServer>
```
> **Note** `applicationHost.config` is located in `%SystemDrive%\Windows\system32\inetsrv\config`.
> Below is an example where you can add the module
> to set it for all ASP.NET application running in Integrated Pipeline Mode:
```xml
<location path="" overrideMode="Allow">
<system.webServer>
<modules>
<add name="TelemetryHttpModule" type="OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule, OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule" preCondition="managedHandler" />
</modules>
</system.webServer>
</location>
```
> **Note** After applying above changes you can check whether `opentelemetry modules`
> are loaded by using `appcmd` command which can be found under `%SystemDrive%\Windows\system32\inetsrv`.
> Following example shows invocation for `WebDemo\` application:
```terminal
appcmd list modules /app.name:"WebDemo/"
```
and correct result:
```terminal
MODULE "TelemetryHttpModule" ( type:OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule, OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule, preCondition:managedHandler )
```
## Configuration
> **Note**

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

View File

@ -241,8 +241,7 @@ HRESULT STDMETHODCALLTYPE CorProfiler::Initialize(IUnknown* cor_profiler_info_un
opcodes_names.push_back("->"); // CEE_SWITCH_ARG
}
//
managed_profiler_assembly_reference = AssemblyReference::GetFromCache(managed_profiler_full_assembly_version);
managed_profiler_assembly_reference = AssemblyReference::GetFromCache(GetBytecodeInstrumentationAssembly());
const auto currentModuleFileName = GetCurrentModuleFileName();
if (currentModuleFileName == EmptyWStr)

View File

@ -16,6 +16,7 @@ OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.Instance.get -> object!
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.ToString() -> string!
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.Type.get -> System.Type!
OpenTelemetry.AutoInstrumentation.Instrumentations.AspNet.HttpModuleIntegration
OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ExecuteAsyncIntegration
OpenTelemetry.AutoInstrumentation.Instrumentations.MongoDB.MongoClientIntegration
OpenTelemetry.AutoInstrumentation.Instrumentations.NServiceBus.EndpointConfigurationIntegration

View File

@ -55,6 +55,14 @@ internal static class InstrumentationDefinitions
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.ExecutionResult>", "GraphQL.Execution.ExecutionContext" }, 2, 3, 0, 2, 65535, 65535, AssemblyFullName, "OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ExecuteAsyncIntegration"));

View File

@ -0,0 +1,71 @@
// <copyright file="HttpModuleIntegration.cs" company="OpenTelemetry Authors">
// 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.
// </copyright>
#if NETFRAMEWORK
using System.Web;
using OpenTelemetry.AutoInstrumentation.CallTarget;
using OpenTelemetry.Instrumentation.AspNet;
namespace OpenTelemetry.AutoInstrumentation.Instrumentations.AspNet;
/// <summary>
/// System.Web.Compilation.BuildManager.InvokePreStartInitMethodsCore calltarget instrumentation
/// </summary>
[InstrumentMethod(
"System.Web",
"System.Web.Compilation.BuildManager",
"InvokePreStartInitMethodsCore",
ClrNames.Void,
new[] { "System.Collections.Generic.ICollection`1[System.Reflection.MethodInfo]", "System.Func`1[System.IDisposable]" },
"4.0.0",
"4.*.*",
"AspNet",
InstrumentationType.Trace)]
public static class HttpModuleIntegration
{
private static int _initialized;
/// <summary>
/// OnMethodBegin callback
/// </summary>
/// <typeparam name="TTarget">Type of the target</typeparam>
/// <typeparam name="TCollection">Type of the collection</typeparam>
/// <typeparam name="TFunc">Type of the </typeparam>
/// <param name="instance">Instance value, aka `this` of the instrumented method. This method is static so this parameter will always be null</param>
/// <param name="methods">The methods to be invoked</param>
/// <param name="setHostingEnvironmentCultures">The function to set the environment culture</param>
/// <returns>Calltarget state value</returns>
internal static CallTargetState OnMethodBegin<TTarget, TCollection, TFunc>(TTarget instance, TCollection methods, TFunc setHostingEnvironmentCultures)
{
if (Interlocked.Exchange(ref _initialized, 1) != default)
{
return CallTargetState.GetDefault();
}
try
{
HttpApplication.RegisterModule(typeof(TelemetryHttpModule));
}
catch
{
// Exception while registering telemetry http module
// nothing we can do with this
}
return CallTargetState.GetDefault();
}
}
#endif

View File

@ -4,6 +4,11 @@ ARG windowscontainer_version=ltsc2022
FROM mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-${windowscontainer_version}
ARG configuration=Debug
ARG platform=x64
WORKDIR C:\opentelemetry
COPY bin/tracer-home .
WORKDIR C:\init
COPY docker-init.ps1 .
RUN [ "powershell", "-c", ".\\docker-init.ps1" ]
ENV COR_ENABLE_PROFILING=1 `
COR_PROFILER={918728DD-259F-4A6A-AC2B-B85E1B658318} `
COR_PROFILER_PATH=C:\opentelemetry\win-${platform}\OpenTelemetry.AutoInstrumentation.Native.dll `

View File

@ -123,6 +123,7 @@
<Folder Include="App_Data\" />
</ItemGroup>
<ItemGroup>
<None Include="docker-init.ps1" />
<None Include="Dockerfile" />
<None Include=".dockerignore">
<DependentUpon>Dockerfile</DependentUpon>

View File

@ -13,9 +13,6 @@
</customErrors>
<compilation debug="true" targetFramework="4.6.2" />
<httpRuntime targetFramework="4.6.2" />
<httpModules>
<add name="TelemetryHttpModule" type="OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule, OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule" />
</httpModules>
</system.web>
<system.webServer>
<httpErrors errorMode="Detailed" />
@ -74,9 +71,5 @@
</system.codedom>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules>
<remove name="TelemetryHttpModule" />
<add name="TelemetryHttpModule" type="OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule, OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule" preCondition="managedHandler" />
</modules>
</system.webServer>
</configuration>

View File

@ -0,0 +1,20 @@
function Test-AssemblyNotForGAC([string] $Name) {
switch ($Name) {
"netstandard.dll" { return $true }
"grpc_csharp_ext.x64.dll" { return $true }
"grpc_csharp_ext.x86.dll" { return $true }
}
return $false
}
[System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a") | Out-Null
$publish = New-Object System.EnterpriseServices.Internal.Publish
$dlls = Get-ChildItem -Path C:\opentelemetry\netfx\ -Filter *.dll -File
for ($i = 0; $i -lt $dlls.Count; $i++) {
if (Test-AssemblyNotForGAC $dlls[$i].Name) {
continue
}
$publish.GacInstall($dlls[$i].FullName)
}
Write-Progress -Activity "Registering .NET Framework dlls in GAC" -Status "Ready" -Completed