public async Task CaptureAutoInstrumentedSpans(string targetFramework) { if (!TestEnvironment.IsWindows) { return; } var apmLogger = new InMemoryBlockingLogger(Elastic.Apm.Logging.LogLevel.Error); var apmServer = new MockApmServer(apmLogger, nameof(CaptureAutoInstrumentedSpans)); var port = apmServer.FindAvailablePortToListen(); apmServer.RunInBackground(port); using (var profiledApplication = new ProfiledApplication("OracleManagedDataAccessSample")) { IDictionary <string, string> environmentVariables = new Dictionary <string, string> { ["ELASTIC_APM_SERVER_URL"] = $"http://localhost:{port}", ["ORACLE_CONNECTION_STRING"] = _fixture.ConnectionString, ["ELASTIC_APM_DISABLE_METRICS"] = "*", // to fix ORA-01882 Timezone region not found on CI. ["TZ"] = "GMT", ["ELASTIC_APM_EXIT_SPAN_MIN_DURATION"] = "0", ["ELASTIC_APM_SPAN_COMPRESSION_ENABLED"] = "false" }; profiledApplication.Start( targetFramework, TimeSpan.FromMinutes(2), environmentVariables, null, line => _output.WriteLine(line.Line), exception => _output.WriteLine($"{exception}")); } apmServer.ReceivedData.Transactions.Should().HaveCount(2); apmServer.ReceivedData.Spans.Should().HaveCount(AdoNetTestData.DbRunnerExpectedTotalSpans + AdoNetTestData.OracleProviderExpectedSpans); var testSpans = apmServer.ReceivedData.Spans .Where(s => !s.Name.StartsWith(AdoNetTestData.OracleProviderSpanNameStart)) .ToList(); var genericTransaction = apmServer.ReceivedData.Transactions.FirstOrDefault(t => t.Name == "RunAllAsync<TDbCommand>"); genericTransaction.Should().NotBeNull(); var genericSpans = testSpans.Where(s => s.TransactionId == genericTransaction.Id).ToList(); genericSpans.Should().HaveCount(AdoNetTestData.DbRunnerExpectedRunAllAsyncSpans); var baseTransaction = apmServer.ReceivedData.Transactions.FirstOrDefault(t => t.Name == "RunBaseTypesAsync"); baseTransaction.Should().NotBeNull(); var baseSpans = testSpans.Where(s => s.TransactionId == baseTransaction.Id).ToList(); baseSpans.Should().HaveCount(AdoNetTestData.DbRunnerExpectedRunBaseTypesAsyncSpans); await apmServer.StopAsync(); }
protected TestsBase( ITestOutputHelper xUnitOutputHelper, bool startMockApmServer = true, IDictionary <string, string> envVarsToSetForSampleAppPool = null, bool sampleAppShouldHaveAccessToPerfCounters = false, bool sampleAppLogEnabled = true ) : base(xUnitOutputHelper) { _logger = LoggerBase.Scoped(ThisClassName); MockApmServer = new MockApmServer(_logger, TestDisplayName); _iisAdministration = new IisAdministration(_logger); _startMockApmServer = startMockApmServer; SampleAppShouldHaveAccessToPerfCounters = sampleAppShouldHaveAccessToPerfCounters; _mockApmServerPort = _startMockApmServer ? MockApmServer.FindAvailablePortToListen() : ConfigConsts.DefaultValues.ApmServerPort; _sampleAppLogEnabled = sampleAppLogEnabled; _sampleAppLogFilePath = GetSampleAppLogFilePath(); EnvVarsToSetForSampleAppPool = envVarsToSetForSampleAppPool == null ? new Dictionary <string, string>() : new Dictionary <string, string>(envVarsToSetForSampleAppPool); EnvVarsToSetForSampleAppPool.TryAdd(ConfigConsts.EnvVarNames.ServerUrls, BuildApmServerUrl(_mockApmServerPort)); if (_sampleAppLogEnabled) { EnvVarsToSetForSampleAppPool.TryAdd(LoggingConfig.LogFileEnvVarName, _sampleAppLogFilePath); } EnvVarsToSetForSampleAppPool.TryAdd(ConfigConsts.EnvVarNames.FlushInterval, "10ms"); }
protected TestsBase(ITestOutputHelper xUnitOutputHelper, bool startMockApmServer = true, IDictionary <string, string> envVarsToSetForSampleAppPool = null, bool sampleAppShouldHaveAccessToPerfCounters = false, bool sampleAppLogEnabled = true ) { _xUnitOutputHelper = xUnitOutputHelper; _logger = new ToAllSinksLogger(_xUnitOutputHelper).Scoped(nameof(TestsBase)); _logger.Info()?.Log("Starting test: {FullUnitTestName}", GetCurrentTestDisplayName(_xUnitOutputHelper)); _mockApmServer = new MockApmServer(_logger, GetCurrentTestDisplayName(_xUnitOutputHelper)); _iisAdministration = new IisAdministration(_logger); _startMockApmServer = startMockApmServer; SampleAppShouldHaveAccessToPerfCounters = sampleAppShouldHaveAccessToPerfCounters; _mockApmServerPort = _startMockApmServer ? _mockApmServer.FindAvailablePortToListen() : ConfigConsts.DefaultValues.ApmServerPort; _sampleAppLogEnabled = sampleAppLogEnabled; _sampleAppLogFilePath = GetSampleAppLogFilePath(); _envVarsToSetForSampleAppPool = envVarsToSetForSampleAppPool == null ? new Dictionary <string, string>() : new Dictionary <string, string>(envVarsToSetForSampleAppPool); _envVarsToSetForSampleAppPool.TryAdd(ConfigConsts.EnvVarNames.ServerUrls, BuildApmServerUrl(_mockApmServerPort)); if (_sampleAppLogEnabled) { _envVarsToSetForSampleAppPool.TryAdd(LoggingConfig.LogFileEnvVarName, _sampleAppLogFilePath); } _envVarsToSetForSampleAppPool.TryAdd(ConfigConsts.EnvVarNames.FlushInterval, "10ms"); }
public async Task CaptureAutoInstrumentedSpans(string targetFramework) { var apmLogger = new InMemoryBlockingLogger(Elastic.Apm.Logging.LogLevel.Error); var apmServer = new MockApmServer(apmLogger, nameof(CaptureAutoInstrumentedSpans)); var port = apmServer.FindAvailablePortToListen(); apmServer.RunInBackground(port); using (var profiledApplication = new ProfiledApplication("MySqlDataSample")) { IDictionary <string, string> environmentVariables = new Dictionary <string, string> { ["ELASTIC_APM_SERVER_URL"] = $"http://localhost:{port}", ["MYSQL_CONNECTION_STRING"] = _fixture.ConnectionString, ["ELASTIC_APM_DISABLE_METRICS"] = "*", ["ELASTIC_APM_EXIT_SPAN_MIN_DURATION"] = "0", ["ELASTIC_APM_SPAN_COMPRESSION_ENABLED"] = "false" }; profiledApplication.Start( targetFramework, TimeSpan.FromMinutes(2), environmentVariables, null, line => _output.WriteLine(line.Line), exception => _output.WriteLine($"{exception}")); } // RunAllAsync<TDbCommand> transaction // RunBaseTypesAsync transaction apmServer.ReceivedData.Transactions.Should().HaveCount(2); // The first MySqlCommand on an opened MySqlConnection executes an additional // command that the profiler instrumentation will create a span for. Since there // are two connections opened, 1 for RunAllAsync<TDbCommand> and 1 for RunBaseTypesAsync, // expect 2 additional spans apmServer.ReceivedData.Spans.Should().HaveCount(AdoNetTestData.DbRunnerExpectedTotalSpans + 2); var genericTransaction = apmServer.ReceivedData.Transactions.FirstOrDefault(t => t.Name == "RunAllAsync<TDbCommand>"); genericTransaction.Should().NotBeNull(); var genericSpans = apmServer.ReceivedData.Spans.Where(s => s.TransactionId == genericTransaction.Id).ToList(); genericSpans.Should().HaveCount(AdoNetTestData.DbRunnerExpectedRunAllAsyncSpans + 1); var baseTransaction = apmServer.ReceivedData.Transactions.FirstOrDefault(t => t.Name == "RunBaseTypesAsync"); baseTransaction.Should().NotBeNull(); var baseSpans = apmServer.ReceivedData.Spans.Where(s => s.TransactionId == baseTransaction.Id).ToList(); baseSpans.Should().HaveCount(AdoNetTestData.DbRunnerExpectedRunBaseTypesAsyncSpans + 1); await apmServer.StopAsync(); }
public async Task CaptureAutoInstrumentedSpans(string targetFramework, string npgsqlVersion) { var apmLogger = new InMemoryBlockingLogger(Elastic.Apm.Logging.LogLevel.Error); var apmServer = new MockApmServer(apmLogger, nameof(CaptureAutoInstrumentedSpans)); var port = apmServer.FindAvailablePortToListen(); apmServer.RunInBackground(port); using (var profiledApplication = new ProfiledApplication("NpgsqlSample")) { var environmentVariables = new Dictionary <string, string> { ["ELASTIC_APM_SERVER_URL"] = $"http://localhost:{port}", ["POSTGRES_CONNECTION_STRING"] = _fixture.ConnectionString, ["ELASTIC_APM_DISABLE_METRICS"] = "*", ["ELASTIC_APM_EXIT_SPAN_MIN_DURATION"] = "0", ["ELASTIC_APM_SPAN_COMPRESSION_ENABLED"] = "false" }; var msBuildProperties = npgsqlVersion is null ? null : new Dictionary <string, string> { ["NpgsqlVersion"] = npgsqlVersion }; profiledApplication.Start( targetFramework, TimeSpan.FromMinutes(2), environmentVariables, msBuildProperties, line => _output.WriteLine(line.Line), exception => _output.WriteLine($"{exception}")); } apmServer.ReceivedData.Transactions.Should().HaveCount(2); apmServer.ReceivedData.Spans.Should().HaveCount(AdoNetTestData.DbRunnerExpectedTotalSpans); var genericTransaction = apmServer.ReceivedData.Transactions.FirstOrDefault(t => t.Name == "RunAllAsync<TDbCommand>"); genericTransaction.Should().NotBeNull(); var genericSpans = apmServer.ReceivedData.Spans.Where(s => s.TransactionId == genericTransaction.Id).ToList(); genericSpans.Should().HaveCount(AdoNetTestData.DbRunnerExpectedRunAllAsyncSpans); var baseTransaction = apmServer.ReceivedData.Transactions.FirstOrDefault(t => t.Name == "RunBaseTypesAsync"); baseTransaction.Should().NotBeNull(); var baseSpans = apmServer.ReceivedData.Spans.Where(s => s.TransactionId == baseTransaction.Id).ToList(); baseSpans.Should().HaveCount(AdoNetTestData.DbRunnerExpectedRunBaseTypesAsyncSpans); await apmServer.StopAsync(); }
public async Task Auto_Instrument_With_StartupHook_Should_Capture_Error(string targetFramework) { var apmLogger = new InMemoryBlockingLogger(LogLevel.Error); var apmServer = new MockApmServer(apmLogger, nameof(Auto_Instrument_With_StartupHook_Should_Capture_Error)); var port = apmServer.FindAvailablePortToListen(); apmServer.RunInBackground(port); var transactionWaitHandle = new ManualResetEvent(false); var errorWaitHandle = new ManualResetEvent(false); apmServer.OnReceive += o => { if (o is TransactionDto) { transactionWaitHandle.Set(); } if (o is ErrorDto) { errorWaitHandle.Set(); } }; using (var sampleApp = new SampleApplication()) { var environmentVariables = new Dictionary <string, string> { [EnvVarNames.ServerUrl] = $"http://localhost:{port}", [EnvVarNames.CloudProvider] = "none" }; var uri = sampleApp.Start(targetFramework, environmentVariables); var builder = new UriBuilder(uri) { Path = "Home/Exception" }; var client = new HttpClient(); var response = await client.GetAsync(builder.Uri); response.IsSuccessStatusCode.Should().BeFalse(); transactionWaitHandle.WaitOne(TimeSpan.FromMinutes(2)); apmServer.ReceivedData.Transactions.Should().HaveCount(1); var transaction = apmServer.ReceivedData.Transactions.First(); transaction.Name.Should().Be("GET Home/Exception"); errorWaitHandle.WaitOne(TimeSpan.FromMinutes(2)); apmServer.ReceivedData.Errors.Should().HaveCount(1); var error = apmServer.ReceivedData.Errors.First(); error.Culprit.Should().Be("Elastic.Apm.StartupHook.Sample.Controllers.HomeController"); } await apmServer.StopAsync(); }
public async Task Auto_Instrument_With_StartupHook_Should_Capture_Metadata( string targetFramework, string expectedRuntimeName, string expectedFrameworkVersion) { var apmLogger = new InMemoryBlockingLogger(LogLevel.Error); var apmServer = new MockApmServer(apmLogger, nameof(Auto_Instrument_With_StartupHook_Should_Capture_Metadata)); var port = apmServer.FindAvailablePortToListen(); apmServer.RunInBackground(port); var waitHandle = new ManualResetEvent(false); apmServer.OnReceive += o => { if (o is MetadataDto) { waitHandle.Set(); } }; using (var sampleApp = new SampleApplication()) { var environmentVariables = new Dictionary <string, string> { [EnvVarNames.ServerUrl] = $"http://localhost:{port}", [EnvVarNames.CloudProvider] = "none" }; var uri = sampleApp.Start(targetFramework, environmentVariables); var client = new HttpClient(); var response = await client.GetAsync(uri); response.IsSuccessStatusCode.Should().BeTrue(); waitHandle.WaitOne(TimeSpan.FromMinutes(2)); apmServer.ReceivedData.Metadata.Should().HaveCountGreaterOrEqualTo(1); var metadata = apmServer.ReceivedData.Metadata.First(); metadata.Service.Runtime.Name.Should().Be(expectedRuntimeName); metadata.Service.Framework.Name.Should().Be("ASP.NET Core"); metadata.Service.Framework.Version.Should().Be(expectedFrameworkVersion); } await apmServer.StopAsync(); }
protected TestsBase(ITestOutputHelper xUnitOutputHelper, bool startMockApmServer = true, Dictionary <string, string> envVarsToSetForSampleAppPool = null, bool sampleAppShouldHaveAccessToPerfCounters = false ) { _logger = new XunitOutputLogger(xUnitOutputHelper).Scoped(nameof(TestsBase)); _mockApmServer = new MockApmServer(_logger, GetCurrentTestName(xUnitOutputHelper)); _iisAdministration = new IisAdministration(_logger); _startMockApmServer = startMockApmServer; SampleAppShouldHaveAccessToPerfCounters = sampleAppShouldHaveAccessToPerfCounters; _mockApmServerPort = _startMockApmServer ? _mockApmServer.FindAvailablePortToListen() : ConfigConsts.DefaultValues.ApmServerPort; _envVarsToSetForSampleAppPool = envVarsToSetForSampleAppPool == null ? new Dictionary <string, string>() : new Dictionary <string, string>(envVarsToSetForSampleAppPool); _envVarsToSetForSampleAppPool.TryAdd(ConfigConsts.EnvVarNames.ServerUrls, $"http://localhost:{_mockApmServerPort}"); }
public async Task CaptureAutoInstrumentedSpans(string targetFramework) { var apmLogger = new InMemoryBlockingLogger(Logging.LogLevel.Error); var apmServer = new MockApmServer(apmLogger, nameof(CaptureAutoInstrumentedSpans)); var port = apmServer.FindAvailablePortToListen(); apmServer.RunInBackground(port); using (var profiledApplication = new ProfiledApplication("RabbitMqSample")) { IDictionary <string, string> environmentVariables = new Dictionary <string, string> { ["RABBITMQ_HOST"] = _fixture.ConnectionString, ["ELASTIC_APM_SERVER_URL"] = $"http://localhost:{port}", ["ELASTIC_APM_DISABLE_METRICS"] = "*", ["ELASTIC_APM_IGNORE_MESSAGE_QUEUES"] = "test-ignore-exchange-name,test-ignore-queue-name" }; profiledApplication.Start( targetFramework, TimeSpan.FromMinutes(2), environmentVariables, null, line => _output.WriteLine(line.Line), exception => _output.WriteLine($"{exception}")); } var transactions = apmServer.ReceivedData.Transactions; var spans = apmServer.ReceivedData.Spans; transactions.Should().HaveCount(9); var ignoreTransaction = transactions.Single(t => t.Name == "PublishAndGetIgnore"); // don't capture any spans for ignored queues and messages spans.Where(s => s.TransactionId == ignoreTransaction.Id).Should().BeEmpty(); var publishAndGetTransaction = transactions.Single(t => t.Name == "PublishAndGet"); spans.Where(s => s.TransactionId == publishAndGetTransaction.Id).Should().HaveCount(3, "PublishAndGet"); var publishAndGetDefaultTransaction = transactions.Single(t => t.Name == "PublishAndGetDefault"); spans.Where(s => s.TransactionId == publishAndGetDefaultTransaction.Id).Should().HaveCount(3, "PublishAndGetDefault"); var senderTransactions = transactions.Where(t => t.Name == "PublishToConsumer").ToList(); senderTransactions.Should().HaveCount(3, "PublishToConsumer"); var consumeTransactions = transactions.Where(t => t.Name.StartsWith("RabbitMQ RECEIVE from")).ToList(); consumeTransactions.Should().HaveCount(3, "RabbitMQ RECEIVE from"); foreach (var senderTransaction in senderTransactions) { var senderSpan = spans.FirstOrDefault(s => s.TransactionId == senderTransaction.Id); senderSpan.Should().NotBeNull(); var tracingTransaction = consumeTransactions.FirstOrDefault(t => t.TraceId == senderTransaction.TraceId); tracingTransaction.Should().NotBeNull(); tracingTransaction.ParentId.Should().Be(senderSpan.Id); } foreach (var consumeTransaction in consumeTransactions) { spans.Where(s => s.TransactionId == consumeTransaction.Id).Should().HaveCount(1); } await apmServer.StopAsync(); }
public async Task Auto_Instrument_With_StartupHook(string template, string name, string targetFramework, string path) { var apmLogger = new InMemoryBlockingLogger(LogLevel.Trace); var apmServer = new MockApmServer(apmLogger, nameof(Auto_Instrument_With_StartupHook)); var port = apmServer.FindAvailablePortToListen(); apmServer.RunInBackground(port); var transactionWaitHandle = new ManualResetEvent(false); var metadataWaitHandle = new ManualResetEvent(false); apmServer.OnReceive += o => { if (o is TransactionDto) { transactionWaitHandle.Set(); } else if (o is MetadataDto) { metadataWaitHandle.Set(); } }; using var project = DotnetProject.Create(name, template, targetFramework, "--no-https"); var environmentVariables = new Dictionary <string, string> { [EnvVarNames.ServerUrl] = $"http://*****:*****@"\s*Now listening on:\s*(?<endpoint>http\:[^\s]*)"); process.SubscribeLines( line => { capturedLines.Add(line.Line); var match = endpointRegex.Match(line.Line); if (match.Success) { try { var endpoint = match.Groups["endpoint"].Value.Trim(); uri = new UriBuilder(endpoint) { Path = path }.Uri; } catch (Exception exception) { e = ExceptionDispatchInfo.Capture(exception); } startHandle.Set(); } }, exception => e = ExceptionDispatchInfo.Capture(exception)); var timeout = TimeSpan.FromMinutes(2); var signalled = startHandle.WaitOne(timeout); if (!signalled) { throw new Exception($"Could not start dotnet project within timeout {timeout}: " + string.Join(Environment.NewLine, capturedLines)); } e?.Throw(); var client = new HttpClient(); var response = await client.GetAsync(uri); response.IsSuccessStatusCode.Should().BeTrue(); signalled = transactionWaitHandle.WaitOne(timeout); if (!signalled) { throw new Exception($"Did not receive transaction within timeout {timeout}: " + string.Join(Environment.NewLine, capturedLines) + Environment.NewLine + string.Join(Environment.NewLine, apmLogger.Lines)); } apmServer.ReceivedData.Transactions.Should().HaveCount(1); var transaction = apmServer.ReceivedData.Transactions.First(); transaction.Name.Should().NotBeNullOrEmpty(); signalled = metadataWaitHandle.WaitOne(timeout); if (!signalled) { throw new Exception($"Did not receive metadata within timeout {timeout}: " + string.Join(Environment.NewLine, capturedLines) + Environment.NewLine + string.Join(Environment.NewLine, apmLogger.Lines)); } apmServer.ReceivedData.Metadata.Should().HaveCountGreaterOrEqualTo(1); var metadata = apmServer.ReceivedData.Metadata.First(); metadata.Service.Runtime.Name.Should().NotBeNullOrEmpty(); metadata.Service.Framework.Name.Should().Be("ASP.NET Core"); metadata.Service.Framework.Version.Should().NotBeNullOrEmpty(); } await apmServer.StopAsync(); }
public async Task CaptureAutoInstrumentedSpans(string targetFramework) { var apmLogger = new InMemoryBlockingLogger(Elastic.Apm.Logging.LogLevel.Error); var apmServer = new MockApmServer(apmLogger, nameof(CaptureAutoInstrumentedSpans)); var port = apmServer.FindAvailablePortToListen(); apmServer.RunInBackground(port); var ignoreTopic = "ignore-topic"; using (var profiledApplication = new ProfiledApplication("KafkaSample")) { IDictionary <string, string> environmentVariables = new Dictionary <string, string> { ["KAFKA_HOST"] = _fixture.BootstrapServers, ["ELASTIC_APM_SERVER_URL"] = $"http://localhost:{port}", ["ELASTIC_APM_DISABLE_METRICS"] = "*", ["ELASTIC_APM_IGNORE_MESSAGE_QUEUES"] = ignoreTopic }; profiledApplication.Start( targetFramework, TimeSpan.FromMinutes(2), environmentVariables, line => _output.WriteLine(line.Line), exception => _output.WriteLine($"{exception}")); } // 6 * 10 consume transactions, 14 produce transactions var transactions = apmServer.ReceivedData.Transactions; transactions.Should().HaveCount(74); var consumeTransactions = transactions.Where(t => t.Name.StartsWith("Kafka RECEIVE")).ToList(); consumeTransactions.Should().HaveCount(60); foreach (var consumeTransaction in consumeTransactions) { var spans = apmServer.ReceivedData.Spans.Where(s => s.TransactionId == consumeTransaction.Id); spans.Should().HaveCount(1); consumeTransaction.Context.Message.Queue.Should().NotBeNull(); consumeTransaction.Context.Message.Queue.Name.Should().NotBeNullOrEmpty(); consumeTransaction.ParentId.Should().NotBeNull(); } var produceTransactions = transactions.Where(t => !t.Name.StartsWith("Kafka RECEIVE")).ToList(); produceTransactions.Should().HaveCount(14); foreach (var produceTransaction in produceTransactions) { var spans = apmServer.ReceivedData.Spans.Where(s => s.TransactionId == produceTransaction.Id).ToList(); if (produceTransaction.Name.Contains("INVALID-TOPIC")) { spans.Should().HaveCount(1); } // the produce transaction shouldn't have an auto instrumented publish span as topic is ignored else if (produceTransaction.Name.Contains(ignoreTopic)) { spans.Should().BeEmpty(); } else { spans.Should().HaveCount(10); } foreach (var span in spans) { span.Context.Message.Should().NotBeNull(); span.Context.Message.Queue.Should().NotBeNull(); span.Context.Message.Queue.Name.Should().NotBeNullOrEmpty(); } } await apmServer.StopAsync(); }