protected async Task AssertAspNetSpanOnly( string path, MockTracerAgent agent, int httpPort, HttpStatusCode expectedHttpStatusCode, bool isError, string expectedErrorType, string expectedErrorMessage, string expectedSpanType, string expectedResourceName, string expectedServiceVersion) { IImmutableList <MockSpan> spans; using (var httpClient = new HttpClient()) { // disable tracing for this HttpClient request httpClient.DefaultRequestHeaders.Add(HttpHeaderNames.TracingEnabled, "false"); var testStart = DateTime.UtcNow; var response = await httpClient.GetAsync($"http://localhost:{httpPort}" + path); var content = await response.Content.ReadAsStringAsync(); Output.WriteLine($"[http] {response.StatusCode} {content}"); Assert.Equal(expectedHttpStatusCode, response.StatusCode); spans = agent.WaitForSpans( count: 1, minDateTime: testStart, operationName: "aspnet.request", returnAllOperations: true); Assert.True(spans.Count == 1, $"expected two span, saw {spans.Count}"); } var span = spans[0]; // base properties Assert.Equal(expectedResourceName, span.Resource); Assert.Equal(expectedSpanType, span.Type); // errors Assert.Equal(isError, span.Error == 1); Assert.Equal(expectedErrorType, span.Tags.GetValueOrDefault(Tags.ErrorType)); Assert.Equal(expectedErrorMessage, span.Tags.GetValueOrDefault(Tags.ErrorMsg)); // other tags Assert.Equal(SpanKinds.Server, span.Tags.GetValueOrDefault(Tags.SpanKind)); Assert.Equal(expectedServiceVersion, span.Tags.GetValueOrDefault(Tags.Version)); }
public ProcessResult RunSampleAndWaitForExit(MockTracerAgent agent, string arguments = null, string packageVersion = "", string framework = "", int aspNetCorePort = 5000) { var process = StartSample(agent, arguments, packageVersion, aspNetCorePort: aspNetCorePort, framework: framework); using var helper = new ProcessHelper(process); process.WaitForExit(); helper.Drain(); var exitCode = process.ExitCode; Output.WriteLine($"ProcessId: " + process.Id); Output.WriteLine($"Exit Code: " + exitCode); var standardOutput = helper.StandardOutput; if (!string.IsNullOrWhiteSpace(standardOutput)) { Output.WriteLine($"StandardOutput:{Environment.NewLine}{standardOutput}"); } var standardError = helper.ErrorOutput; if (!string.IsNullOrWhiteSpace(standardError)) { Output.WriteLine($"StandardError:{Environment.NewLine}{standardError}"); } #if NETCOREAPP2_1 if (exitCode == 139) { // Segmentation faults are expected on .NET Core because of a bug in the runtime: https://github.com/dotnet/runtime/issues/11885 throw new SkipException("Segmentation fault on .NET Core 2.1"); } #endif if (exitCode == 134 && standardError?.Contains("System.Threading.AbandonedMutexException: The wait completed due to an abandoned mutex") == true && standardError?.Contains("Coverlet.Core.Instrumentation.Tracker") == true) { // Coverlet occasionally throws AbandonedMutexException during clean up throw new SkipException("Coverlet threw AbandonedMutexException during cleanup"); } Assert.True(exitCode >= 0, $"Process exited with code {exitCode}"); return(new ProcessResult(process, standardOutput, standardError, exitCode)); }
public Process StartSample(MockTracerAgent agent, string arguments, string packageVersion, int aspNetCorePort, string framework = "") { // get path to sample app that the profiler will attach to string sampleAppPath = EnvironmentHelper.GetSampleApplicationPath(packageVersion, framework); if (!File.Exists(sampleAppPath)) { throw new Exception($"application not found: {sampleAppPath}"); } Output.WriteLine($"Starting Application: {sampleAppPath}"); var executable = EnvironmentHelper.IsCoreClr() ? EnvironmentHelper.GetSampleExecutionSource() : sampleAppPath; var args = EnvironmentHelper.IsCoreClr() ? $"{sampleAppPath} {arguments ?? string.Empty}" : arguments; return(ProfilerHelper.StartProcessWithProfiler( executable, EnvironmentHelper, agent, args, aspNetCorePort: aspNetCorePort, processToProfile: executable)); }
public static Process StartProcessWithProfiler( string executable, EnvironmentHelper environmentHelper, MockTracerAgent agent, string arguments = null, bool redirectStandardInput = false, int aspNetCorePort = 5000, string processToProfile = null, bool?enableSecurity = null, string externalRulesFile = 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( agent, aspNetCorePort, startInfo.Environment, processToProfile, enableSecurity.GetValueOrDefault(), externalRulesFile); startInfo.UseShellExecute = false; startInfo.CreateNoWindow = true; startInfo.RedirectStandardOutput = true; startInfo.RedirectStandardError = true; startInfo.RedirectStandardInput = redirectStandardInput; return(Process.Start(startInfo)); }
public void ConfigureTransportVariables(IDictionary <string, string> environmentVariables, MockTracerAgent agent) { if (TransportType == TestTransports.Uds) { string apmKey = "DD_APM_RECEIVER_SOCKET"; string dsdKey = "DD_DOGSTATSD_SOCKET"; environmentVariables.Add(apmKey, agent.TracesUdsPath); environmentVariables.Add(dsdKey, agent.StatsUdsPath); } else if (TransportType == TestTransports.WindowsNamedPipe) { string apmKey = "DD_TRACE_PIPE_NAME"; string dsdKey = "DD_DOGSTATSD_PIPE_NAME"; environmentVariables.Add(apmKey, agent.TracesUdsPath); environmentVariables.Add(dsdKey, agent.StatsUdsPath); } else if (TransportType == TestTransports.Tcp) { environmentVariables["DD_TRACE_AGENT_HOSTNAME"] = "127.0.0.1"; environmentVariables["DD_TRACE_AGENT_PORT"] = agent.Port.ToString(); if (agent.StatsdPort != default(int)) { environmentVariables["DD_DOGSTATSD_PORT"] = agent.StatsdPort.ToString(); } } }
public void SetEnvironmentVariables( MockTracerAgent agent, int aspNetCorePort, IDictionary <string, string> environmentVariables, string processToProfile = null, bool enableSecurity = false, string externalRulesFile = null) { string profilerEnabled = AutomaticInstrumentationEnabled ? "1" : "0"; environmentVariables["DD_DOTNET_TRACER_HOME"] = TracerHome; 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; } if (DebugModeEnabled) { environmentVariables["DD_TRACE_DEBUG"] = "1"; } if (!string.IsNullOrEmpty(processToProfile)) { environmentVariables["DD_PROFILER_PROCESSES"] = Path.GetFileName(processToProfile); } // for ASP.NET Core sample apps, set the server's port environmentVariables["ASPNETCORE_URLS"] = $"http://127.0.0.1:{aspNetCorePort}/"; if (enableSecurity) { environmentVariables[ConfigurationKeys.AppSecEnabled] = enableSecurity.ToString(); } if (!string.IsNullOrEmpty(externalRulesFile)) { environmentVariables[ConfigurationKeys.AppSecRules] = externalRulesFile; } foreach (var name in new[] { "SERVICESTACK_REDIS_HOST", "STACKEXCHANGE_REDIS_HOST" }) { var value = Environment.GetEnvironmentVariable(name); if (!string.IsNullOrEmpty(value)) { environmentVariables[name] = value; } } // set consistent env name (can be overwritten by custom environment variable) environmentVariables["DD_ENV"] = "integration_tests"; environmentVariables[ConfigurationKeys.Telemetry.Enabled] = "false"; // Don't attach the profiler to these processes environmentVariables["DD_PROFILER_EXCLUDE_PROCESSES"] = "devenv.exe;Microsoft.ServiceHub.Controller.exe;ServiceHub.Host.CLR.exe;ServiceHub.TestWindowStoreHost.exe;" + "ServiceHub.DataWarehouseHost.exe;sqlservr.exe;VBCSCompiler.exe;iisexpresstray.exe;msvsmon.exe;PerfWatson2.exe;" + "ServiceHub.IdentityHost.exe;ServiceHub.VSDetouredHost.exe;ServiceHub.SettingsHost.exe;ServiceHub.Host.CLR.x86.exe;" + "ServiceHub.RoslynCodeAnalysisService32.exe;MSBuild.exe;ServiceHub.ThreadedWaitDialog.exe"; ConfigureTransportVariables(environmentVariables, agent); foreach (var key in CustomEnvironmentVariables.Keys) { environmentVariables[key] = CustomEnvironmentVariables[key]; } }
protected async Task AssertWebServerSpan( string path, MockTracerAgent agent, int httpPort, HttpStatusCode expectedHttpStatusCode, bool isError, string expectedAspNetErrorType, string expectedAspNetErrorMessage, string expectedErrorType, string expectedErrorMessage, string expectedSpanType, string expectedOperationName, string expectedAspNetResourceName, string expectedResourceName, string expectedServiceVersion, SerializableDictionary expectedTags = null) { IImmutableList <MockSpan> spans; using (var httpClient = new HttpClient()) { // disable tracing for this HttpClient request httpClient.DefaultRequestHeaders.Add(HttpHeaderNames.TracingEnabled, "false"); var testStart = DateTime.UtcNow; var response = await httpClient.GetAsync($"http://localhost:{httpPort}" + path); var content = await response.Content.ReadAsStringAsync(); Output.WriteLine($"[http] {response.StatusCode} {content}"); Assert.Equal(expectedHttpStatusCode, response.StatusCode); agent.SpanFilters.Add(IsServerSpan); spans = agent.WaitForSpans( count: 2, minDateTime: testStart, returnAllOperations: true); Assert.True(spans.Count == 2, $"expected two span, saw {spans.Count}"); } var aspnetSpan = spans.FirstOrDefault(s => s.Name == "aspnet.request"); var innerSpan = spans.FirstOrDefault(s => s.Name == expectedOperationName); Assert.NotNull(aspnetSpan); Assert.Equal(expectedAspNetResourceName, aspnetSpan.Resource); Assert.NotNull(innerSpan); Assert.Equal(expectedResourceName, innerSpan.Resource); foreach (var span in spans) { // base properties Assert.Equal(expectedSpanType, span.Type); // errors Assert.Equal(isError, span.Error == 1); if (span == aspnetSpan) { Assert.Equal(expectedAspNetErrorType, span.Tags.GetValueOrDefault(Tags.ErrorType)); Assert.Equal(expectedAspNetErrorMessage, span.Tags.GetValueOrDefault(Tags.ErrorMsg)); } else if (span == innerSpan) { Assert.Equal(expectedErrorType, span.Tags.GetValueOrDefault(Tags.ErrorType)); Assert.Equal(expectedErrorMessage, span.Tags.GetValueOrDefault(Tags.ErrorMsg)); } // other tags Assert.Equal(SpanKinds.Server, span.Tags.GetValueOrDefault(Tags.SpanKind)); Assert.Equal(expectedServiceVersion, span.Tags.GetValueOrDefault(Tags.Version)); } if (expectedTags?.Values is not null) { foreach (var expectedTag in expectedTags) { Assert.Equal(expectedTag.Value, innerSpan.Tags.GetValueOrDefault(expectedTag.Key)); } } }
public (Process Process, string ConfigFile) StartIISExpress(MockTracerAgent agent, int iisPort, IisAppType appType) { var iisExpress = EnvironmentHelper.GetIisExpressPath(); var appPool = appType switch { IisAppType.AspNetClassic => "Clr4ClassicAppPool", IisAppType.AspNetIntegrated => "Clr4IntegratedAppPool", IisAppType.AspNetCoreInProcess => "UnmanagedClassicAppPool", IisAppType.AspNetCoreOutOfProcess => "UnmanagedClassicAppPool", _ => throw new InvalidOperationException($"Unknown {nameof(IisAppType)} '{appType}'"), }; var appPath = appType switch { IisAppType.AspNetClassic => EnvironmentHelper.GetSampleProjectDirectory(), IisAppType.AspNetIntegrated => EnvironmentHelper.GetSampleProjectDirectory(), IisAppType.AspNetCoreInProcess => EnvironmentHelper.GetSampleApplicationOutputDirectory(), IisAppType.AspNetCoreOutOfProcess => EnvironmentHelper.GetSampleApplicationOutputDirectory(), _ => throw new InvalidOperationException($"Unknown {nameof(IisAppType)} '{appType}'"), }; var configTemplate = File.ReadAllText("applicationHost.config"); var newConfig = Path.GetTempFileName(); configTemplate = configTemplate .Replace("[PATH]", appPath) .Replace("[PORT]", iisPort.ToString()) .Replace("[POOL]", appPool); var isAspNetCore = appType == IisAppType.AspNetCoreInProcess || appType == IisAppType.AspNetCoreOutOfProcess; if (isAspNetCore) { var hostingModel = appType == IisAppType.AspNetCoreInProcess ? "inprocess" : "outofprocess"; configTemplate = configTemplate .Replace("[DOTNET]", EnvironmentHelper.GetDotnetExe()) .Replace("[RELATIVE_SAMPLE_PATH]", $".\\{EnvironmentHelper.GetSampleApplicationFileName()}") .Replace("[HOSTING_MODEL]", hostingModel); } File.WriteAllText(newConfig, configTemplate); var args = new[] { "/site:sample", $"/config:{newConfig}", "/systray:false", "/trace:info" }; Output.WriteLine($"[webserver] starting {iisExpress} {string.Join(" ", args)}"); var process = ProfilerHelper.StartProcessWithProfiler( iisExpress, EnvironmentHelper, agent, arguments: string.Join(" ", args), redirectStandardInput: true, processToProfile: appType == IisAppType.AspNetCoreOutOfProcess ? "dotnet.exe" : iisExpress); var wh = new EventWaitHandle(false, EventResetMode.AutoReset); Task.Run(() => { string line; while ((line = process.StandardOutput.ReadLine()) != null) { Output.WriteLine($"[webserver][stdout] {line}"); if (line.Contains("IIS Express is running")) { wh.Set(); } } }); Task.Run(() => { string line; while ((line = process.StandardError.ReadLine()) != null) { Output.WriteLine($"[webserver][stderr] {line}"); } }); wh.WaitOne(5000); // Wait for iis express to finish starting up var retries = 5; while (true) { var usedPorts = IPGlobalProperties.GetIPGlobalProperties() .GetActiveTcpListeners() .Select(ipEndPoint => ipEndPoint.Port); if (usedPorts.Contains(iisPort)) { break; } retries--; if (retries == 0) { throw new Exception("Gave up waiting for IIS Express."); } Thread.Sleep(1500); } return(process, newConfig); }