Disable profiler bootstrap process for .NET Core (#314)

* Disable profiler bootstrap process for .NET Core

* Update src/OpenTelemetry.ClrProfiler.Native/cor_profiler.cpp

Fixes spelling error.

Co-authored-by: Paulo Janotti <pjanotti@splunk.com>

* Update tests to use startup hook bootstrapping.

* Add test to validate startup hook is necessary

* Log if startup hook is not configured correctly.

* Add native tests for the startup hook validation.

* Update const and pass by ref for variables and parameters for startup hook functions

* Updating test and sample apps to use the startup hook.

* Updating scripts to set startup hook environment variable.

* Shutdown profiler if startup hook not configured correctly.

* Use const ref for all startup hook params and use OTEL_ naming convention.

Co-authored-by: Paulo Janotti <pjanotti@splunk.com>
This commit is contained in:
Chris Ventura 2022-02-02 16:10:25 -08:00 committed by GitHub
parent 04e64e54b2
commit 372d9ac871
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 229 additions and 117 deletions

View File

@ -1,5 +1,6 @@
export CORECLR_ENABLE_PROFILING=1
export CORECLR_PROFILER='{918728DD-259F-4A6A-AC2B-B85E1B658318}'
export CORECLR_PROFILER_PATH=/opt/opentelemetry-dotnet-autoinstrumentation/OpenTelemetry.ClrProfiler.Native.so
export DOTNET_STARTUP_HOOKS=/opt/opentelemetry-dotnet-autoinstrumentation/OpenTelemetry.Instrumentation.StartupHook.dll
export OTEL_INTEGRATIONS=/opt/opentelemetry-dotnet-autoinstrumentation/integrations.json
export OTEL_DOTNET_TRACER_HOME=/opt/opentelemetry-dotnet-autoinstrumentation

View File

@ -53,6 +53,7 @@ then
export CORECLR_PROFILER_PATH_64="${CURDIR}/bin/tracer-home/win-x64/OpenTelemetry.ClrProfiler.Native.${SUFIX}"
export CORECLR_PROFILER_PATH_32="${CURDIR}/bin/tracer-home/win-x86/OpenTelemetry.ClrProfiler.Native.${SUFIX}"
fi
export DOTNET_STARTUP_HOOKS="${CURDIR}/bin/tracer-home/netcoreapp3.1/OpenTelemetry.Instrumentation.StartupHook.dll"
# Configure OpenTelemetry Tracer
export OTEL_DOTNET_TRACER_HOME="${CURDIR}/bin/tracer-home"

View File

@ -22,7 +22,7 @@ namespace Samples.AspNetCoreMvc.Controllers
ViewBag.ClrProfilerAssemblyLocation = instrumentationType?.Assembly.Location;
ViewBag.StackTrace = StackTraceHelper.GetUsefulStack();
var prefixes = new[] { "COR_", "CORECLR_", "OTEL_" };
var prefixes = new[] { "COR_", "CORECLR_", "DOTNET_", "OTEL_" };
var envVars = from envVar in Environment.GetEnvironmentVariables().Cast<DictionaryEntry>()
from prefix in prefixes

View File

@ -16,10 +16,11 @@
"CORECLR_ENABLE_PROFILING": "1",
"CORECLR_PROFILER": "{918728DD-259F-4A6A-AC2B-B85E1B658318}",
"CORECLR_PROFILER_PATH": "$(ProjectDir)$(OutputPath)profiler-lib\\OpenTelemetry.ClrProfiler.Native.dll",
"CORECLR_PROFILER_PATH": "$(SolutionDir)bin\\tracer-home\\win-x64\\OpenTelemetry.ClrProfiler.Native.dll",
"DOTNET_STARTUP_HOOKS": "$(SolutionDir)bin\\tracer-home\\netcoreapp3.1\\OpenTelemetry.Instrumentation.StartupHook.dll",
"OTEL_DOTNET_TRACER_HOME": "$(ProjectDir)$(OutputPath)profiler-lib",
"OTEL_INTEGRATIONS": "$(ProjectDir)$(OutputPath)profiler-lib\\integrations.json",
"OTEL_DOTNET_TRACER_HOME": "$(SolutionDir)bin\\tracer-home",
"OTEL_INTEGRATIONS": "$(SolutionDir)bin\\tracer-home\\integrations.json",
"OTEL_SERVICE_NAME": "Samples.AspNetCoreMvc31",
"OTEL_EXPORTER": "jaeger",
"OTEL_EXPORTER_JAEGER_AGENT_HOST": "localhost",
@ -36,10 +37,11 @@
"CORECLR_ENABLE_PROFILING": "1",
"CORECLR_PROFILER": "{918728DD-259F-4A6A-AC2B-B85E1B658318}",
"CORECLR_PROFILER_PATH": "$(ProjectDir)$(OutputPath)profiler-lib\\OpenTelemetry.ClrProfiler.Native.dll",
"CORECLR_PROFILER_PATH": "$(SolutionDir)bin\\tracer-home$(OutputPath)\\OpenTelemetry.ClrProfiler.Native.dll",
"DOTNET_STARTUP_HOOKS": "$(SolutionDir)bin\\tracer-home\\netcoreapp3.1\\OpenTelemetry.Instrumentation.StartupHook.dll",
"OTEL_DOTNET_TRACER_HOME": "$(ProjectDir)$(OutputPath)profiler-lib",
"OTEL_INTEGRATIONS": "$(ProjectDir)$(OutputPath)profiler-lib\\integrations.json",
"OTEL_DOTNET_TRACER_HOME": "$(SolutionDir)bin\\tracer-home",
"OTEL_INTEGRATIONS": "$(SolutionDir)bin\\tracer-home\\integrations.json",
"OTEL_SERVICE_NAME": "Samples.AspNetCoreMvc31",
"OTEL_EXPORTER": "jaeger",

View File

@ -202,6 +202,7 @@
<ClInclude Include="module_metadata.h" />
<ClInclude Include="pal.h" />
<ClInclude Include="rejit_handler.h" />
<ClInclude Include="startup_hook.h" />
<ClInclude Include="stats.h" />
<ClInclude Include="string.h" />
<ClInclude Include="util.h" />

View File

@ -17,6 +17,7 @@
#include "module_metadata.h"
#include "pal.h"
#include "resource.h"
#include "startup_hook.h"
#include "stats.h"
#include "util.h"
#include "version.h"
@ -119,6 +120,10 @@ HRESULT STDMETHODCALLTYPE CorProfiler::Initialize(IUnknown* cor_profiler_info_un
if (SUCCEEDED(hr))
{
Logger::Debug("Interface ICorProfilerInfo10 found.");
// .NET Core applications should use the dotnet startup hook to bootstrap OpenTelemetry so that the
// necessary dependencies will be available. Bootstrapping with the profiling APIs occurs too early
// and the necessary dependencies are not available yet.
use_dotnet_startuphook_bootstrapper = true;
}
else
{
@ -135,6 +140,17 @@ HRESULT STDMETHODCALLTYPE CorProfiler::Initialize(IUnknown* cor_profiler_info_un
}
}
if (use_dotnet_startuphook_bootstrapper)
{
const auto home_path = GetEnvironmentValue(environment::profiler_home_path);
const auto startup_hooks = GetEnvironmentValue(environment::dotnet_startup_hooks);
if (!IsStartupHookEnabled(startup_hooks, home_path))
{
Logger::Error("The required startup hook was not configured correctly. No telemetry will be captured.");
return E_FAIL;
}
}
if (IsAzureAppServices())
{
Logger::Info("Profiler is operating within Azure App Services context.");
@ -742,7 +758,7 @@ HRESULT STDMETHODCALLTYPE CorProfiler::JITCompilationStarted(FunctionID function
{
auto _ = trace::Stats::Instance()->JITCompilationStartedMeasure();
if (!is_attached_ || !is_safe_to_block)
if (!is_attached_ || !is_safe_to_block || use_dotnet_startuphook_bootstrapper)
{
return S_OK;
}

View File

@ -29,6 +29,7 @@ private:
// Startup helper variables
bool first_jit_compilation_completed = false;
bool use_dotnet_startuphook_bootstrapper = false;
bool instrument_domain_neutral_assemblies = false;
bool corlib_module_loaded = false;

View File

@ -26,7 +26,8 @@ const WSTRING env_vars_to_display[]{environment::tracing_enabled,
environment::azure_app_services,
environment::azure_app_services_app_pool_id,
environment::azure_app_services_cli_telemetry_profile_value,
environment::internal_trace_profiler_path};
environment::internal_trace_profiler_path,
environment::dotnet_startup_hooks};
const WSTRING skip_assembly_prefixes[]{
WStr("Microsoft.AI"),

View File

@ -89,6 +89,12 @@ const WSTRING internal_trace_profiler_path =
// Sets whether to enable NGEN images.
const WSTRING clr_enable_ngen = WStr("OTEL_CLR_ENABLE_NGEN");
// The list of startup hooks defined for .NET Core 3.1+ applications.
// This is a .NET runtime environment variable.
// See https://github.com/dotnet/runtime/blob/main/docs/design/features/host-startup-hook.md
// for more information about this environment variable.
const WSTRING dotnet_startup_hooks = WStr("DOTNET_STARTUP_HOOKS");
} // namespace environment
} // namespace trace

View File

@ -22,6 +22,12 @@
#include "string.h" // NOLINT
#include "util.h"
#ifdef _WIN32
#define DIR_SEPARATOR WStr('\\')
#else
#define DIR_SEPARATOR WStr('/')
#endif
namespace trace
{
@ -34,13 +40,7 @@ inline WSTRING GetDatadogLogFilePath(const std::string& file_name_suffix)
if (directory.length() > 0)
{
return directory +
#ifdef _WIN32
WStr('\\') +
#else
WStr('/') +
#endif
ToWSTRING(file_name);
return directory + DIR_SEPARATOR + ToWSTRING(file_name);
}
WSTRING path = GetEnvironmentValue(TLoggerPolicy::logging_environment::log_path);

View File

@ -0,0 +1,30 @@
#ifndef OTEL_CLR_PROFILER_STARTUP_HOOK_H_
#define OTEL_CLR_PROFILER_STARTUP_HOOK_H_
#include "string.h" // NOLINT
#include "pal.h"
namespace trace
{
inline WSTRING GetExpectedStartupHookPath(const WSTRING& home_path) {
WSTRING separator = EmptyWStr;
if (home_path.back() != DIR_SEPARATOR) {
separator = DIR_SEPARATOR;
}
return home_path + separator + WStr("netcoreapp3.1") + DIR_SEPARATOR +
WStr("OpenTelemetry.Instrumentation.StartupHook.dll");
}
inline bool IsStartupHookEnabled(const WSTRING& startup_hooks, const WSTRING& home_path)
{
const WSTRING expected_startup_hook = GetExpectedStartupHookPath(home_path);
auto n = startup_hooks.find(expected_startup_hook);
return n != WSTRING::npos;
}
} // namespace trace
#endif // OTEL_CLR_PROFILER_STARTUP_HOOK_H_

View File

@ -80,6 +80,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="startup_hook_test.cpp" />
<ClCompile Include="version_struct_test.cpp" />
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,82 @@
#include "pch.h"
#include "../../src/OpenTelemetry.ClrProfiler.Native/startup_hook.h"
using namespace trace;
TEST(StartupHookTest, GetExpectedStartupHookPathDoesNotAddSeparator) {
const auto home_path = WStr("C:\\tracer_home\\");
const auto expected_path = WStr("C:\\tracer_home\\netcoreapp3.1\\OpenTelemetry.Instrumentation.StartupHook.dll");
const auto startup_hook_path = GetExpectedStartupHookPath(home_path);
ASSERT_EQ(expected_path, startup_hook_path);
}
TEST(StartupHookTest, GetExpectedStartupHookPathAddsSeparator) {
const auto home_path = WStr("C:\\tracer_home");
const auto expected_path = WStr("C:\\tracer_home\\netcoreapp3.1\\OpenTelemetry.Instrumentation.StartupHook.dll");
const auto startup_hook_path = GetExpectedStartupHookPath(home_path);
ASSERT_EQ(expected_path, startup_hook_path);
}
TEST(StartupHookTest, StartupHookIsEnabled) {
const auto startup_hooks = WStr("C:\\tracer_home\\netcoreapp3.1\\OpenTelemetry.Instrumentation.StartupHook.dll");
const auto home_path = WStr("C:\\tracer_home");
const auto is_enabled = IsStartupHookEnabled(startup_hooks, home_path);
ASSERT_TRUE(is_enabled);
}
TEST(StartupHookTest, StartupHookIsNotEnabledWhenStartupHooksIsEmpty) {
const auto startup_hooks = WStr("");
const auto home_path = WStr("C:\\tracer_home");
const auto is_enabled = IsStartupHookEnabled(startup_hooks, home_path);
ASSERT_FALSE(is_enabled);
}
TEST(StartupHookTest, StartupHookIsNotEnabledWhenNoStartupHooksDefined) {
const WSTRING startup_hooks;
const auto home_path = WStr("C:\\tracer_home");
const auto is_enabled = IsStartupHookEnabled(startup_hooks, home_path);
ASSERT_FALSE(is_enabled);
}
TEST(StartupHookTest, StartupHookIsNotEnabledWhenStartupHookDoesNotContainOpenTelemetryHook) {
const auto startup_hooks = WStr("C:\\other_folder\\StartupHook.dll");
const auto home_path = WStr("C:\\tracer_home");
const auto is_enabled = IsStartupHookEnabled(startup_hooks, home_path);
ASSERT_FALSE(is_enabled);
}
TEST(StartupHookTest, StartupHookIsNotEnabledWhenNotInTheCorrectLocation) {
const auto startup_hooks = WStr("C:\\other_folder\\netcoreapp3.1\\OpenTelemetry.Instrumentation.StartupHook.dll");
const auto home_path = WStr("C:\\tracer_home");
const auto is_enabled = IsStartupHookEnabled(startup_hooks, home_path);
ASSERT_FALSE(is_enabled);
}
TEST(StartupHookTest, StartupHookIsEnabledWhenMultipleStartupHooksDefined) {
std::stringstream ss;
ss << "C:\\folder1\\StartupHook.dll" << DIR_SEPARATOR
<< "C:\\tracer_home\\netcoreapp3.1\\OpenTelemetry.Instrumentation.StartupHook.dll"
<< DIR_SEPARATOR << "C:\\folder2\\StartupHook.dll";
const auto startup_hooks = ToWSTRING(ss.str());
const auto home_path = WStr("C:\\tracer_home");
const auto is_enabled = IsStartupHookEnabled(startup_hooks, home_path);
ASSERT_TRUE(is_enabled);
}

View File

@ -142,34 +142,31 @@ namespace IntegrationTests.Helpers
int agentPort,
int aspNetCorePort,
StringDictionary environmentVariables,
string processToProfile = null,
bool isStartupHook = false)
bool enableStartupHook,
string processToProfile = null)
{
string profilerEnabled = _requiresProfiling ? "1" : "0";
string profilerPath = GetProfilerPath();
if (isStartupHook)
if (IsCoreClr())
{
string hookPath = GetStartupHookOutputPath();
// enableStartupHook should be true by default, and the parameter should only be set
// to false when testing the case that instrumentation should not be available.
if (enableStartupHook)
{
string hookPath = GetStartupHookOutputPath();
environmentVariables["DOTNET_STARTUP_HOOKS"] = hookPath;
}
environmentVariables["DOTNET_STARTUP_HOOKS"] = hookPath;
environmentVariables["OTEL_DOTNET_TRACER_INSTRUMENTATIONS"] = "HttpClient";
environmentVariables["CORECLR_ENABLE_PROFILING"] = profilerEnabled;
environmentVariables["CORECLR_PROFILER"] = EnvironmentTools.ProfilerClsId;
environmentVariables["CORECLR_PROFILER_PATH"] = profilerPath;
}
else
{
string profilerPath = GetProfilerPath();
if (IsCoreClr())
{
environmentVariables["CORECLR_ENABLE_PROFILING"] = profilerEnabled;
environmentVariables["CORECLR_PROFILER"] = EnvironmentTools.ProfilerClsId;
environmentVariables["CORECLR_PROFILER_PATH"] = profilerPath;
}
else
{
environmentVariables["COR_ENABLE_PROFILING"] = profilerEnabled;
environmentVariables["COR_PROFILER"] = EnvironmentTools.ProfilerClsId;
environmentVariables["COR_PROFILER_PATH"] = profilerPath;
}
environmentVariables["COR_ENABLE_PROFILING"] = profilerEnabled;
environmentVariables["COR_PROFILER"] = EnvironmentTools.ProfilerClsId;
environmentVariables["COR_PROFILER_PATH"] = profilerPath;
}
if (DebugModeEnabled)

View File

@ -3,16 +3,17 @@ using System.Diagnostics;
namespace IntegrationTests.Helpers
{
public class ProfilerHelper
public class InstrumentedProcessHelper
{
public static Process StartProcessWithProfiler(
public static Process StartInstrumentedProcess(
string executable,
EnvironmentHelper environmentHelper,
string arguments = null,
bool redirectStandardInput = false,
int traceAgentPort = 9696,
int aspNetCorePort = 5000,
string processToProfile = null)
string processToProfile = null,
bool enableStartupHook = true)
{
if (environmentHelper == null)
{
@ -24,7 +25,7 @@ namespace IntegrationTests.Helpers
var startInfo = new ProcessStartInfo(executable, $"{arguments ?? string.Empty}");
environmentHelper.SetEnvironmentVariables(traceAgentPort, aspNetCorePort, startInfo.EnvironmentVariables, processToProfile);
environmentHelper.SetEnvironmentVariables(traceAgentPort, aspNetCorePort, startInfo.EnvironmentVariables, enableStartupHook, processToProfile);
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;

View File

@ -1,38 +0,0 @@
using System;
using System.Diagnostics;
namespace IntegrationTests.Helpers
{
public class StartupHookHelper
{
public static Process StartProcessWithStartupHook(
string executable,
EnvironmentHelper environmentHelper,
string arguments = null,
bool redirectStandardInput = false,
int traceAgentPort = 9696,
int aspNetCorePort = 5000,
string processToProfile = null)
{
if (environmentHelper == null)
{
throw new ArgumentNullException(nameof(environmentHelper));
}
// clear all relevant environment variables to start with a clean slate
EnvironmentHelper.ClearProfilerEnvironmentVariables();
var startInfo = new ProcessStartInfo(executable, $"{arguments ?? string.Empty}");
environmentHelper.SetEnvironmentVariables(traceAgentPort, aspNetCorePort, startInfo.EnvironmentVariables, processToProfile, true);
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardInput = redirectStandardInput;
return Process.Start(startInfo);
}
}
}

View File

@ -89,7 +89,7 @@ namespace IntegrationTests.Helpers
return new Container(container);
}
public Process StartSample(int traceAgentPort, string arguments, string packageVersion, int aspNetCorePort, string framework = "", bool startupHook = false)
public Process StartSample(int traceAgentPort, string arguments, string packageVersion, int aspNetCorePort, string framework = "", bool enableStartupHook = true)
{
// get path to sample app that the profiler will attach to
string sampleAppPath = EnvironmentHelper.GetSampleApplicationPath(packageVersion, framework);
@ -102,31 +102,19 @@ namespace IntegrationTests.Helpers
var executable = EnvironmentHelper.IsCoreClr() ? EnvironmentHelper.GetSampleExecutionSource() : sampleAppPath;
var args = EnvironmentHelper.IsCoreClr() ? $"{sampleAppPath} {arguments ?? string.Empty}" : arguments;
if (startupHook)
{
return StartupHookHelper.StartProcessWithStartupHook(
executable,
EnvironmentHelper,
args,
traceAgentPort: traceAgentPort,
aspNetCorePort: aspNetCorePort,
processToProfile: executable);
}
else
{
return ProfilerHelper.StartProcessWithProfiler(
executable,
EnvironmentHelper,
args,
traceAgentPort: traceAgentPort,
aspNetCorePort: aspNetCorePort,
processToProfile: executable);
}
return InstrumentedProcessHelper.StartInstrumentedProcess(
executable,
EnvironmentHelper,
args,
traceAgentPort: traceAgentPort,
aspNetCorePort: aspNetCorePort,
processToProfile: executable,
enableStartupHook: enableStartupHook);
}
public ProcessResult RunSampleAndWaitForExit(int traceAgentPort, string arguments = null, string packageVersion = "", string framework = "", int aspNetCorePort = 5000, bool startupHook = false)
public ProcessResult RunSampleAndWaitForExit(int traceAgentPort, string arguments = null, string packageVersion = "", string framework = "", int aspNetCorePort = 5000, bool enableStartupHook = true)
{
var process = StartSample(traceAgentPort, arguments, packageVersion, aspNetCorePort: aspNetCorePort, framework: framework, startupHook: startupHook);
var process = StartSample(traceAgentPort, arguments, packageVersion, aspNetCorePort: aspNetCorePort, framework: framework, enableStartupHook: enableStartupHook);
var name = process.ProcessName;
using var helper = new ProcessHelper(process);

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using IntegrationTests.Helpers;
using IntegrationTests.Helpers.Mocks;
@ -18,6 +19,8 @@ namespace IntegrationTests.StartupHook
public StartupHookTests(ITestOutputHelper output)
: base("StartupHook", output)
{
SetEnvironmentVariable("OTEL_SERVICE_NAME", ServiceName);
SetEnvironmentVariable("OTEL_DOTNET_TRACER_INSTRUMENTATIONS", "HttpClient");
_expectations.Add(new WebServerSpanExpectation(ServiceName, null, "SayHello", "SayHello", null));
_expectations.Add(new WebServerSpanExpectation(ServiceName, null, "HTTP GET", "HTTP GET", null, "GET"));
}
@ -26,9 +29,22 @@ namespace IntegrationTests.StartupHook
[Trait("Category", "EndToEnd")]
public void SubmitsTraces()
{
SetEnvironmentVariable("OTEL_SERVICE_NAME", ServiceName);
const int expectedSpanCount = 2;
RunTestAndValidateResults(2);
var spans = RunTestApplication(enableStartupHook: true);
AssertExpectedSpansReceived(expectedSpanCount, spans);
}
[Fact]
[Trait("Category", "EndToEnd")]
public void InstrumentationNotAvailableWhenStartupHookIsNotEnabled()
{
const int expectedSpanCount = 0;
var spans = RunTestApplication(enableStartupHook: false);
AssertExpectedSpansReceived(expectedSpanCount, spans);
}
[Theory]
@ -45,30 +61,34 @@ namespace IntegrationTests.StartupHook
expectedSpanCount = 0;
}
SetEnvironmentVariable("OTEL_SERVICE_NAME", ServiceName);
SetEnvironmentVariable("OTEL_PROFILER_EXCLUDE_PROCESSES", $"dotnet,dotnet.exe,{applicationNameToExclude}");
RunTestAndValidateResults(expectedSpanCount);
var spans = RunTestApplication(enableStartupHook: true);
AssertExpectedSpansReceived(expectedSpanCount, spans);
}
private void RunTestAndValidateResults(int expectedSpanCount)
private IImmutableList<IMockSpan> RunTestApplication(bool enableStartupHook)
{
int agentPort = TcpPortProvider.GetOpenPort();
using (var agent = new MockZipkinCollector(Output, agentPort))
using (var processResult = RunSampleAndWaitForExit(agent.Port, startupHook: true))
using (var processResult = RunSampleAndWaitForExit(agent.Port, enableStartupHook: enableStartupHook))
{
Assert.True(processResult.ExitCode >= 0, $"Process exited with code {processResult.ExitCode} and exception: {processResult.StandardError}");
var span = agent.WaitForSpans(2, 500);
return agent.WaitForSpans(2, 500);
}
}
Assert.True(span.Count() == expectedSpanCount, $"Expecting {expectedSpanCount} spans, received {span.Count()}");
if (expectedSpanCount > 0)
{
Assert.Single(span.Select(s => s.Service).Distinct());
private void AssertExpectedSpansReceived(int expectedSpanCount, IImmutableList<IMockSpan> spans)
{
Assert.True(spans.Count() == expectedSpanCount, $"Expecting {expectedSpanCount} spans, received {spans.Count()}");
if (expectedSpanCount > 0)
{
Assert.Single(spans.Select(s => s.Service).Distinct());
var spanList = span.ToList();
AssertExpectationsMet(_expectations, spanList);
}
var spanList = spans.ToList();
AssertExpectationsMet(_expectations, spanList);
}
}

View File

@ -28,7 +28,7 @@ namespace Samples.GraphQL
var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogInformation($"Instrumentation.ProfilerAttached = {IsProfilerAttached()}");
var prefixes = new[] { "COR_", "CORECLR_", "OTEL_" };
var prefixes = new[] { "COR_", "CORECLR_", "DOTNET_", "OTEL_" };
var envVars = from envVar in Environment.GetEnvironmentVariables().Cast<DictionaryEntry>()
from prefix in prefixes
let key = (envVar.Key as string)?.ToUpperInvariant()

View File

@ -17,6 +17,7 @@
"CORECLR_ENABLE_PROFILING": "1",
"CORECLR_PROFILER": "{918728DD-259F-4A6A-AC2B-B85E1B658318}",
"CORECLR_PROFILER_PATH": "$(SolutionDir)bin\\tracer-home\\win-x64\\OpenTelemetry.ClrProfiler.Native.dll",
"DOTNET_STARTUP_HOOKS": "$(SolutionDir)bin\\tracer-home\\netcoreapp3.1\\OpenTelemetry.Instrumentation.StartupHook.dll",
"OTEL_DOTNET_TRACER_HOME": "$(SolutionDir)bin\\tracer-home\\",
"OTEL_INTEGRATIONS": "$(SolutionDir)bin\\tracer-home\\integrations.json",

View File

@ -6,6 +6,7 @@
"CORECLR_ENABLE_PROFILING": "1",
"CORECLR_PROFILER": "{918728DD-259F-4A6A-AC2B-B85E1B658318}",
"CORECLR_PROFILER_PATH": "$(SolutionDir)bin\\tracer-home\\win-x64\\OpenTelemetry.ClrProfiler.Native.dll",
"DOTNET_STARTUP_HOOKS": "$(SolutionDir)bin\\tracer-home\\netcoreapp3.1\\OpenTelemetry.Instrumentation.StartupHook.dll",
"OTEL_DOTNET_TRACER_HOME": "$(SolutionDir)bin\\tracer-home\\",
"OTEL_INTEGRATIONS": "$(SolutionDir)bin\\tracer-home\\integrations.json",

View File

@ -12,7 +12,7 @@ namespace Samples.AspNet.Controllers
{
public ActionResult Index()
{
var prefixes = new[] { "COR_", "CORECLR_", "OTEL_" };
var prefixes = new[] { "COR_", "CORECLR_", "DOTNET_", "OTEL_" };
var envVars = from envVar in Environment.GetEnvironmentVariables().Cast<DictionaryEntry>()
from prefix in prefixes