Fix bytecode instrumentation of strong named assemblies (#1153)

* Fix instrumentation of strong-named assemblies

* Add strong name where required

* Native changes for strong name only on .NET Framework

* Doc that StrongNamedValidation is temporary

* Add test application to sln

* dotnet-format fixes for new cs code

* Remove output log from test

* Add CHANGELOG.md note
This commit is contained in:
Paulo Janotti 2022-09-06 10:30:50 -07:00 committed by GitHub
parent 8bfb4ffcb9
commit 4d5167f5da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 407 additions and 91 deletions

View File

@ -10,6 +10,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Added
- Add support for Alpine.
- Add strong name signature to the OpenTelemetry.AutoInstrumentation assembly used
on the .NET Framework.
### Changed
## [0.3.0-beta.1](https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/tag/v0.3.0-beta.1)

View File

@ -138,6 +138,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApplication.GrpcNetClie
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper", "src\OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper\OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper.csproj", "{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.StrongNamed", "test\test-applications\integrations\TestApplication.StrongNamed\TestApplication.StrongNamed.csproj", "{505A5B7B-930E-42D3-909F-E97C7C247FCF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -586,6 +588,18 @@ Global
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}.Release|x64.Build.0 = Release|Any CPU
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}.Release|x86.ActiveCfg = Release|Any CPU
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}.Release|x86.Build.0 = Release|Any CPU
{505A5B7B-930E-42D3-909F-E97C7C247FCF}.Debug|Any CPU.ActiveCfg = Debug|x64
{505A5B7B-930E-42D3-909F-E97C7C247FCF}.Debug|Any CPU.Build.0 = Debug|x64
{505A5B7B-930E-42D3-909F-E97C7C247FCF}.Debug|x64.ActiveCfg = Debug|x64
{505A5B7B-930E-42D3-909F-E97C7C247FCF}.Debug|x64.Build.0 = Debug|x64
{505A5B7B-930E-42D3-909F-E97C7C247FCF}.Debug|x86.ActiveCfg = Debug|x86
{505A5B7B-930E-42D3-909F-E97C7C247FCF}.Debug|x86.Build.0 = Debug|x86
{505A5B7B-930E-42D3-909F-E97C7C247FCF}.Release|Any CPU.ActiveCfg = Release|x64
{505A5B7B-930E-42D3-909F-E97C7C247FCF}.Release|Any CPU.Build.0 = Release|x64
{505A5B7B-930E-42D3-909F-E97C7C247FCF}.Release|x64.ActiveCfg = Release|x64
{505A5B7B-930E-42D3-909F-E97C7C247FCF}.Release|x64.Build.0 = Release|x64
{505A5B7B-930E-42D3-909F-E97C7C247FCF}.Release|x86.ActiveCfg = Release|x86
{505A5B7B-930E-42D3-909F-E97C7C247FCF}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -633,6 +647,7 @@ Global
{671EB8F0-E164-4E9F-B423-27AF4B59D360} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
{0605872C-AB2B-4167-9B00-A525090D10BE} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6} = {9E5F0022-0A50-40BF-AC6A-C3078585ECAB}
{505A5B7B-930E-42D3-909F-E97C7C247FCF} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {160A1D00-1F5B-40F8-A155-621B4459D78F}

View File

@ -4,6 +4,11 @@
#include "logger.h"
#include "module_metadata.h"
#include "otel_profiler_constants.h"
#include "cor_profiler.h"
#ifndef _WIN32
#include <dlfcn.h>
#endif
namespace trace
{
@ -163,7 +168,9 @@ HRESULT CallTargetTokens::EnsureBaseCalltargetTokens()
// *** Ensure profiler assembly ref
if (profilerAssemblyRef == mdAssemblyRefNil)
{
const AssemblyReference assemblyReference = *trace::AssemblyReference::GetFromCache(managed_profiler_full_assembly_version);
const auto bytecode_instrumentation_name = trace::profiler->GetBytecodeInstrumentationAssembly();
Logger::Debug("CallTargetTokens::EnsureBaseCalltargetTokens() Bytecode Instrumentation Assembly: ", bytecode_instrumentation_name);
const AssemblyReference assemblyReference = *trace::AssemblyReference::GetFromCache(bytecode_instrumentation_name);
ASSEMBLYMETADATA assembly_metadata{};
assembly_metadata.usMajorVersion = assemblyReference.version.major;

View File

@ -102,6 +102,13 @@ HRESULT STDMETHODCALLTYPE CorProfiler::Initialize(IUnknown* cor_profiler_info_un
return E_FAIL;
}
// code is ready to get runtime information
runtime_information_ = GetRuntimeInformation(this->info_);
if (process_name == WStr("w3wp.exe") || process_name == WStr("iisexpress.exe"))
{
is_desktop_iis = runtime_information_.is_desktop();
}
// get ICorProfilerInfo6 for net46+
ICorProfilerInfo6* info6;
hr = cor_profiler_info_unknown->QueryInterface(__uuidof(ICorProfilerInfo6), (void**)&info6);
@ -232,11 +239,6 @@ HRESULT STDMETHODCALLTYPE CorProfiler::Initialize(IUnknown* cor_profiler_info_un
return E_FAIL;
}
runtime_information_ = GetRuntimeInformation(this->info_);
if (process_name == WStr("w3wp.exe") || process_name == WStr("iisexpress.exe"))
{
is_desktop_iis = runtime_information_.is_desktop();
}
// writing opcodes vector for the IL dumper
#define OPDEF(c, s, pop, push, args, type, l, s1, s2, flow) opcodes_names.push_back(s);
@ -262,10 +264,16 @@ HRESULT STDMETHODCALLTYPE CorProfiler::AssemblyLoadFinished(AssemblyID assembly_
{
// if assembly failed to load, skip it entirely,
// otherwise we can crash the process if module is not valid
Logger::Warn("AssemblyLoadFinished: ", assembly_id, " ", hr_status);
CorProfilerBase::AssemblyLoadFinished(assembly_id, hr_status);
return S_OK;
}
if (Logger::IsDebugEnabled())
{
Logger::Debug("AssemblyLoadFinished: ", assembly_id, " ", hr_status);
}
// keep this lock until we are done using the module,
// to prevent it from unloading while in use
std::lock_guard<std::mutex> guard(module_id_to_info_map_lock_);
@ -279,89 +287,48 @@ HRESULT STDMETHODCALLTYPE CorProfiler::AssemblyLoadFinished(AssemblyID assembly_
const auto assembly_info = GetAssemblyInfo(this->info_, assembly_id);
if (!assembly_info.IsValid())
{
Logger::Debug("AssemblyLoadFinished: ", assembly_id, " ", hr_status);
return S_OK;
}
const auto is_instrumentation_assembly = assembly_info.name == WStr("OpenTelemetry.AutoInstrumentation");
if (is_instrumentation_assembly)
const auto is_instrumentation_assembly = assembly_info.name == managed_profiler_name;
if (!is_instrumentation_assembly)
{
if (Logger::IsDebugEnabled())
return S_OK;
}
if (Logger::IsDebugEnabled())
{
Logger::Debug("AssemblyLoadFinished: Bytecode Instrumentation Assembly: ", GetBytecodeInstrumentationAssembly());
}
ComPtr<IUnknown> metadata_interfaces;
auto hr = this->info_->GetModuleMetaData(assembly_info.manifest_module_id, ofRead | ofWrite,
IID_IMetaDataImport2, metadata_interfaces.GetAddressOf());
if (FAILED(hr))
{
Logger::Warn("AssemblyLoadFinished failed to get metadata interface for module id ",
assembly_info.manifest_module_id, " from assembly ", assembly_info.name);
return S_OK;
}
// Get the IMetaDataAssemblyImport interface to get metadata from the managed assembly
const auto assembly_import = metadata_interfaces.As<IMetaDataAssemblyImport>(IID_IMetaDataAssemblyImport);
const auto assembly_metadata = GetAssemblyImportMetadata(assembly_import);
managed_profiler_loaded_app_domains.insert(assembly_info.app_domain_id);
if (runtime_information_.is_desktop() && corlib_module_loaded)
{
// Set the managed_profiler_loaded_domain_neutral flag whenever the
// managed profiler is loaded shared
if (assembly_info.app_domain_id == corlib_app_domain_id)
{
Logger::Debug("AssemblyLoadFinished: ", assembly_id, " ", hr_status);
Logger::Info("AssemblyLoadFinished: ", assembly_info.name, " was loaded domain-neutral");
managed_profiler_loaded_domain_neutral = true;
}
ComPtr<IUnknown> metadata_interfaces;
auto hr = this->info_->GetModuleMetaData(assembly_info.manifest_module_id, ofRead | ofWrite,
IID_IMetaDataImport2, metadata_interfaces.GetAddressOf());
if (FAILED(hr))
else
{
Logger::Warn("AssemblyLoadFinished failed to get metadata interface for module id ",
assembly_info.manifest_module_id, " from assembly ", assembly_info.name);
return S_OK;
}
// Get the IMetaDataAssemblyImport interface to get metadata from the managed assembly
const auto assembly_import = metadata_interfaces.As<IMetaDataAssemblyImport>(IID_IMetaDataAssemblyImport);
const auto assembly_metadata = GetAssemblyImportMetadata(assembly_import);
// used multiple times for logging
const auto assembly_version = assembly_metadata.version.str();
if (Logger::IsDebugEnabled())
{
Logger::Debug("AssemblyLoadFinished: AssemblyName=", assembly_info.name,
" AssemblyVersion=", assembly_version);
}
if (is_instrumentation_assembly)
{
const auto expected_assembly_reference = trace::AssemblyReference(managed_profiler_full_assembly_version);
// used multiple times for logging
const auto expected_version = expected_assembly_reference.version.str();
bool is_viable_version;
if (runtime_information_.is_core())
{
is_viable_version = (assembly_metadata.version >= expected_assembly_reference.version);
}
else
{
is_viable_version = (assembly_metadata.version == expected_assembly_reference.version);
}
// Check that Major.Minor.Build matches the profiler version.
// On .NET Core, allow managed library to be a higher version than the native library.
if (is_viable_version)
{
Logger::Info("AssemblyLoadFinished: OpenTelemetry.AutoInstrumentation.dll v", assembly_version,
" matched profiler version v", expected_version);
managed_profiler_loaded_app_domains.insert(assembly_info.app_domain_id);
if (runtime_information_.is_desktop() && corlib_module_loaded)
{
// Set the managed_profiler_loaded_domain_neutral flag whenever the
// managed profiler is loaded shared
if (assembly_info.app_domain_id == corlib_app_domain_id)
{
Logger::Info("AssemblyLoadFinished: OpenTelemetry.AutoInstrumentation.dll was loaded domain-neutral");
managed_profiler_loaded_domain_neutral = true;
}
else
{
Logger::Info("AssemblyLoadFinished: OpenTelemetry.AutoInstrumentation.dll was not loaded domain-neutral");
}
}
}
else
{
Logger::Warn("AssemblyLoadFinished: OpenTelemetry.AutoInstrumentation.dll v", assembly_version,
" did not match profiler version v", expected_version);
}
Logger::Info("AssemblyLoadFinished: ", assembly_info.name, " was not loaded domain-neutral");
}
}
@ -928,6 +895,22 @@ bool CorProfiler::IsAttached() const
return is_attached_;
}
WSTRING CorProfiler::GetBytecodeInstrumentationAssembly() const
{
WSTRING bytecodeInstrumentationAssembly = managed_profiler_full_assembly_version;
if (!runtime_information_.runtime_type)
{
Logger::Error("GetBytecodeInstrumentationAssembly: called before runtime_information was initialized.");
}
else if (!runtime_information_.is_core())
{
// When on .NET Framework use the signature with the public key so strong name works.
bytecodeInstrumentationAssembly = managed_profiler_full_assembly_version_strong_name;
}
return bytecodeInstrumentationAssembly;
}
//
// Helper methods
//
@ -985,15 +968,22 @@ bool CorProfiler::GetWrapperMethodRef(ModuleMetadata* module_metadata, ModuleID
module_metadata->metadata_emit, module_metadata->assembly_import,
module_metadata->assembly_emit);
const AssemblyReference* wrapper_assembly = &method_replacement.wrapper_method.assembly;
if (wrapper_assembly->name == managed_profiler_name)
{
// Handle the typical case in which the wrapper is also the bytecode instrumentation assembly.
wrapper_assembly = AssemblyReference::GetFromCache(GetBytecodeInstrumentationAssembly());
}
// for each wrapper assembly, emit an assembly reference
hr = metadata_builder.EmitAssemblyRef(method_replacement.wrapper_method.assembly);
hr = metadata_builder.EmitAssemblyRef(*wrapper_assembly);
if (FAILED(hr))
{
Logger::Warn("JITCompilationStarted failed to emit wrapper assembly ref for assembly=",
method_replacement.wrapper_method.assembly.name,
", Version=", method_replacement.wrapper_method.assembly.version.str(),
", Culture=", method_replacement.wrapper_method.assembly.locale,
" PublicKeyToken=", method_replacement.wrapper_method.assembly.public_key.str());
wrapper_assembly->name,
", Version=", wrapper_assembly->version.str(),
", Culture=", wrapper_assembly->locale,
" PublicKeyToken=", wrapper_assembly->public_key.str());
return false;
}

View File

@ -88,6 +88,8 @@ public:
bool IsAttached() const;
WSTRING GetBytecodeInstrumentationAssembly() const;
void GetAssemblyAndSymbolsBytes(BYTE** pAssemblyArray, int* assemblySize, BYTE** pSymbolsArray,
int* symbolsSize) const;

View File

@ -76,10 +76,13 @@ const WSTRING mscorlib_assemblyName = WStr("mscorlib");
const WSTRING system_private_corelib_assemblyName = WStr("System.Private.CoreLib");
const WSTRING opentelemetry_autoinstrumentation_loader_assemblyName = WStr("OpenTelemetry.AutoInstrumentation.Loader");
const WSTRING managed_profiler_name = WStr("OpenTelemetry.AutoInstrumentation");
const WSTRING managed_profiler_full_assembly_version =
WStr("OpenTelemetry.AutoInstrumentation, Version=0.3.0.0, Culture=neutral, PublicKeyToken=null");
const WSTRING managed_profiler_name = WStr("OpenTelemetry.AutoInstrumentation");
const WSTRING managed_profiler_full_assembly_version_strong_name =
WStr("OpenTelemetry.AutoInstrumentation, Version=0.3.0.0, Culture=neutral, PublicKeyToken=c0db600a13f60b51");
const WSTRING nonwindows_nativemethods_type = WStr("OpenTelemetry.AutoInstrumentation.NativeMethods+NonWindows");

View File

@ -0,0 +1,57 @@
// <copyright file="StrongNamedValidation.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>
using System;
using System.Diagnostics;
using OpenTelemetry.AutoInstrumentation.CallTarget;
namespace OpenTelemetry.AutoInstrumentation.Instrumentations.Validations
{
/// <summary>
/// Instrumentation targeting the test application used to validate the strong name scenario.
/// When an actual bytecode instrumentation targeting a strong named assembly on .NET Framework
/// is added we can remove this instrumentation.
/// </summary>
[InstrumentMethod(
AssemblyName = "TestApplication.StrongNamed",
TypeName = "TestApplication.StrongNamed.Command",
MethodName = "Execute",
ReturnTypeName = ClrNames.Void,
ParameterTypeNames = new string[0],
MinimumVersion = "1.0.0",
MaximumVersion = "1.65535.65535",
IntegrationName = "StrongNamedValidation")]
public class StrongNamedValidation
{
private static readonly ActivitySource ValidationActivitySource = new ActivitySource("TestApplication.StrongNamedValidation");
/// <summary>
/// OnMethodBegin callback.
/// </summary>
/// <typeparam name="TTarget">Type of the target</typeparam>
/// <param name="instance">Instance value, aka `this` of the instrumented method.</param>
/// <returns>Calltarget state value</returns>
public static CallTargetState OnMethodBegin<TTarget>(TTarget instance)
{
using var activity = ValidationActivitySource.StartActivity(nameof(StrongNamedValidation));
activity.AddTag("validation", nameof(StrongNamedValidation));
Console.WriteLine($"Validation: {nameof(StrongNamedValidation)}");
return CallTargetState.GetDefault();
}
}
}

View File

@ -0,0 +1,26 @@
// <copyright file="AssemblyInfo.NetFramework.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.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyKeyFileAttribute("keypair.snk")]
[assembly: InternalsVisibleTo("OpenTelemetry.AutoInstrumentation.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001008db7c66f4ebdc6aac4196be5ce1ff4b59b020028e6dbd6e46f15aa40b3215975b92d0a8e45aba5f36114a8cb56241fbfa49f4c017e6c62197857e4e9f62451bc23d3a660e20861f95a57f23e20c77d413ad216ff1bb55f94104d4c501e32b03219d8603fb6fa73401c6ae6808c8daa61b9eaee5d2377d3c23c9ca6016c6582d8")]
[assembly: InternalsVisibleTo("IntegrationTests, PublicKey=00240000048000009400000006020000002400005253413100040000010001008db7c66f4ebdc6aac4196be5ce1ff4b59b020028e6dbd6e46f15aa40b3215975b92d0a8e45aba5f36114a8cb56241fbfa49f4c017e6c62197857e4e9f62451bc23d3a660e20861f95a57f23e20c77d413ad216ff1bb55f94104d4c501e32b03219d8603fb6fa73401c6ae6808c8daa61b9eaee5d2377d3c23c9ca6016c6582d8")]
#endif

View File

@ -14,8 +14,10 @@
// limitations under the License.
// </copyright>
#if NETCOREAPP3_1_OR_GREATER
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper")]
[assembly: InternalsVisibleTo("OpenTelemetry.AutoInstrumentation.Tests")]
[assembly: InternalsVisibleTo("IntegrationTests")]
#endif

Binary file not shown.

19
test/AssemblyInfo.cs Normal file
View File

@ -0,0 +1,19 @@
// <copyright file="AssemblyInfo.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>
using System.Reflection;
[assembly: AssemblyKeyFileAttribute("test-keypair.snk")]

View File

@ -30,4 +30,8 @@
<Compile Include="$(MSBuildThisFileDirectory)GlobalSuppressions.cs" Link="GlobalSuppressions.test.cs" />
</ItemGroup>
<!-- Strong name conditional to limit it only to required projects -->
<ItemGroup Condition="$(TargetFramework.StartsWith('net4')) and '$(AddTestStrongNameAssemblyKeyOnNetFramework)' == 'true'">
<Compile Include="$(MSBuildThisFileDirectory)AssemblyInfo.cs" Link="AssemblyInfo.StrongName.cs" />
</ItemGroup>
</Project>

View File

@ -207,9 +207,9 @@ public class EnvironmentHelper
environmentVariables["OTEL_DOTNET_AUTO_INCLUDE_PROCESSES"] = Path.GetFileName(processToProfile);
}
string integrations = GetIntegrationsPath();
environmentVariables["OTEL_DOTNET_AUTO_HOME"] = GetNukeBuildOutput();
environmentVariables["OTEL_DOTNET_AUTO_INTEGRATIONS_FILE"] = integrations;
environmentVariables["OTEL_DOTNET_AUTO_INTEGRATIONS_FILE"] = Environment.GetEnvironmentVariable("OTEL_DOTNET_AUTO_INTEGRATIONS_FILE") ?? GetIntegrationsPath();
if (testSettings.TracesSettings != null)
{

View File

@ -17,6 +17,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Containers;
@ -47,6 +48,23 @@ public abstract class TestHelper
protected ITestOutputHelper Output { get; }
/// <summary>
/// Gets the path for the test assembly, not the shadow copy created by xunit.
/// </summary>
public string GetTestAssemblyPath()
{
#if NETFRAMEWORK
// CodeBase is deprecated outside .NET Framework, instead of suppressing the error
// build the code as per recommendation for each runtime.
var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().CodeBase);
var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);
var directory = Path.GetDirectoryName(codeBasePath);
return Path.GetFullPath(directory);
#else
return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
#endif
}
public async Task<Container> StartContainerAsync(TestSettings testSettings, int webPort)
{
// get path to test application that the profiler will attach to

View File

@ -1,11 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PropertyGroup>
<AddTestStrongNameAssemblyKeyOnNetFramework>true</AddTestStrongNameAssemblyKeyOnNetFramework>
<DisableStrongNamer Condition="!$(TargetFramework.StartsWith('net4'))">true</DisableStrongNamer>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.21.5" />
<PackageReference Include="Grpc.Tools" Version="2.48.1" PrivateAssets="all" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="StrongNamer" Version="0.2.5" Condition="$(TargetFramework.StartsWith('net4'))" />
<PackageReference Include="System.Collections.Immutable" Version="6.0.0" />
<PackageReference Include="System.Runtime.InteropServices" Version="4.3.0" />
<PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" />
@ -21,4 +26,10 @@
<!-- GrpcServices is 'none' so that we do not need to depend on the grpc nuget package, and we only need protobuf support. -->
<Protobuf Include="opentelemetry\**\*.proto" GrpcServices="none" />
</ItemGroup>
<ItemGroup>
<None Update="StrongNamedTestsIntegrations.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,59 @@
// <copyright file="StrongNamedTests.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>
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using FluentAssertions;
using FluentAssertions.Execution;
using IntegrationTests.Helpers;
using Xunit;
using Xunit.Abstractions;
namespace IntegrationTests;
public class StrongNamedTests : TestHelper
{
public StrongNamedTests(ITestOutputHelper output)
: base("StrongNamed", output)
{
}
[Fact]
public void SubmitsTraces()
{
var assemblyPath = GetTestAssemblyPath();
var integrationsFile = Path.Combine(assemblyPath, "StrongNamedTestsIntegrations.json");
File.Exists(integrationsFile).Should().BeTrue();
SetEnvironmentVariable("OTEL_DOTNET_AUTO_INTEGRATIONS_FILE", integrationsFile);
using var agent = new MockZipkinCollector(Output);
RunTestApplication(agent.Port);
const int expectedSpansCount = 1;
var spans = agent.WaitForSpans(expectedSpansCount, TimeSpan.FromSeconds(5));
using (new AssertionScope())
{
spans.Count.Should().Be(expectedSpansCount);
spans.Count(s => s.Tags["validation"] == "StrongNamedValidation").Should().Be(1);
}
}
}

View File

@ -0,0 +1,29 @@
[
{
"name": "StrongNamedTests",
"method_replacements": [
{
"caller": {},
"target": {
"assembly": "TestApplication.StrongNamed",
"type": "TestApplication.StrongNamed.Command",
"method": "Execute",
"signature_types": [
"System.Void"
],
"minimum_major": 1,
"minimum_minor": 0,
"minimum_patch": 0,
"maximum_major": 1,
"maximum_minor": 65535,
"maximum_patch": 65535
},
"wrapper": {
"assembly": "OpenTelemetry.AutoInstrumentation",
"type": "OpenTelemetry.AutoInstrumentation.Instrumentations.Validations.StrongNamedValidation",
"action": "CallTargetModification"
}
}
]
}
]

Binary file not shown.

View File

@ -1,5 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AddTestStrongNameAssemblyKeyOnNetFramework>true</AddTestStrongNameAssemblyKeyOnNetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\OpenTelemetry.AutoInstrumentation\OpenTelemetry.AutoInstrumentation.csproj" />
</ItemGroup>

View File

@ -0,0 +1,28 @@
// <copyright file="Command.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>
using System;
using System.Threading;
namespace TestApplication.StrongNamed;
public class Command
{
public void Execute()
{
Thread.Yield(); // Just to have some call to outside code.
}
}

View File

@ -0,0 +1,31 @@
// <copyright file="Program.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>
using System;
using System.Reflection;
[assembly: AssemblyKeyFileAttribute("keypair.snk")]
namespace TestApplication.StrongNamed;
public static class Program
{
public static void Main(string[] args)
{
var command = new Command();
command.Execute();
}
}

View File

@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
</PropertyGroup>
</Project>