public async Task Capture_Span_When_Send_To_Queue() { await using var scope = await QueueScope.CreateWithQueue(_adminClient); var sender = _client.CreateSender(scope.QueueName); await _agent.Tracer.CaptureTransaction("Send AzureServiceBus Message", "message", async() => { await sender.SendMessageAsync(new ServiceBusMessage("test message")).ConfigureAwait(false); }); if (!_sender.WaitForSpans()) { throw new Exception("No span received in timeout"); } _sender.Spans.Should().HaveCount(1); var span = _sender.FirstSpan; span.Name.Should().Be($"{ServiceBus.SegmentName} SEND to {scope.QueueName}"); span.Type.Should().Be(ApiConstants.TypeMessaging); span.Subtype.Should().Be(ServiceBus.SubType); span.Action.Should().Be("send"); span.Context.Destination.Should().NotBeNull(); var destination = span.Context.Destination; destination.Address.Should().Be(_environment.ServiceBusConnectionStringProperties.FullyQualifiedNamespace); destination.Service.Name.Should().Be(ServiceBus.SubType); destination.Service.Resource.Should().Be($"{ServiceBus.SubType}/{scope.QueueName}"); destination.Service.Type.Should().Be(ApiConstants.TypeMessaging); }
public async Task HomeIndexTransactionWithToggleRecording(bool withDiagnosticSourceOnly) { _agent = new ApmAgent(new TestAgentComponents( _logger, new MockConfigSnapshot(recording: "false"), _capturedPayload)); _client = Helper.ConfigureHttpClient(true, withDiagnosticSourceOnly, _agent, _factory); var response = await _client.GetAsync("/Home/Index"); response.IsSuccessStatusCode.Should().BeTrue(); _capturedPayload.WaitForAny(TimeSpan.FromSeconds(5)); _capturedPayload.Transactions.Should().BeNullOrEmpty(); _capturedPayload.Spans.Should().BeNullOrEmpty(); _capturedPayload.Errors.Should().BeNullOrEmpty(); //flip recording to true _agent.ConfigStore.CurrentSnapshot = new MockConfigSnapshot(recording: "true"); response = await _client.GetAsync("/Home/Index"); response.IsSuccessStatusCode.Should().BeTrue(); _capturedPayload.WaitForTransactions(); _capturedPayload.Transactions.Should().NotBeEmpty(); _capturedPayload.WaitForSpans(); _capturedPayload.Spans.Should().NotBeEmpty(); _capturedPayload.WaitForErrors(TimeSpan.FromSeconds(5)); _capturedPayload.Errors.Should().BeNullOrEmpty(); }
public async Task SqlClientDiagnosticListener_ShouldCaptureSpan(string providerName, Func <string, DbConnection> connectionCreator) { const string commandText = "SELECT getdate()"; // Arrange + Act _testOutputHelper.WriteLine(providerName); await _apmAgent.Tracer.CaptureTransaction("transaction", "type", async transaction => { using var dbConnection = connectionCreator.Invoke(_connectionString); await dbConnection.OpenAsync(); using var sqlCommand = dbConnection.CreateCommand(); sqlCommand.CommandText = commandText; // ReSharper disable once MethodHasAsyncOverload using (sqlCommand.ExecuteReader()) { // ignore } }); // Assert _payloadSender.WaitForSpans(); _payloadSender.Spans.Count.Should().Be(1); _payloadSender.Errors.Count.Should().Be(0); _payloadSender.FirstSpan.Should().NotBeNull(); _payloadSender.FirstSpan.Outcome.Should().Be(Outcome.Success); var span = _payloadSender.FirstSpan; #if !NETFRAMEWORK span.Name.ToLower().Should().Be("select"); #endif span.Subtype.Should().Be(ApiConstants.SubtypeMssql); span.Type.Should().Be(ApiConstants.TypeDb); span.Context.Db.Should().NotBeNull(); #if !NETFRAMEWORK span.Context.Db.Statement.Should().Be(commandText); #endif span.Context.Db.Type.Should().Be(Database.TypeSql); span.Context.Destination.Should().NotBeNull(); span.Context.Destination.Address.Should().Be(_expectedAddress); span.Context.Destination.Port.Should().NotBeNull(); span.Context.Destination.Service.Should().NotBeNull(); span.Context.Destination.Service.Resource.Should().Be($"{ApiConstants.SubtypeMssql}/{span.Context.Db.Instance}"); span.Context.Service.Target.Type.Should().Be(ApiConstants.SubtypeMssql); span.Context.Service.Target.Name.Should().Be(span.Context.Db.Instance); }
public void TransactionWithSpanWithoutEnd() { const string transactionName = TestTransaction; const string transactionType = UnitTest; const string spanName = "TestSpan"; var payloadSender = new MockPayloadSender(); using (var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender))) { var transaction = agent.Tracer.StartTransaction(transactionName, transactionType); var unused = transaction.StartSpan(spanName, ApiConstants.TypeExternal); Thread.Sleep(5); //Make sure we have duration > 0 transaction.End(); //Ends transaction, but doesn't end span. payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().NotBeEmpty(); payloadSender.SignalEndSpans(); payloadSender.WaitForSpans(); payloadSender.SpansOnFirstTransaction.Should().BeEmpty(); agent.Service.Should().NotBeNull(); } }
public async Task HttpCallWithW3CActivityFormar() { Activity.DefaultIdFormat = ActivityIdFormat.W3C; var mockPayloadSender = new MockPayloadSender(); using var localServer = LocalServer.Create(); using var agent = new ApmAgent(new TestAgentComponents(payloadSender: mockPayloadSender)); agent.Subscribe(new HttpDiagnosticsSubscriber()); await agent.Tracer.CaptureTransaction("Test", "Test", async() => { var httpClient = new HttpClient(); try { await httpClient.GetAsync(localServer.Uri); } catch { //ignore - we don't care about the result } }); mockPayloadSender.WaitForSpans(); mockPayloadSender.Spans.Should().HaveCount(1); }
/// <summary> /// Asserts on 1 transaction with 1 span and 1 error /// </summary> private void AssertWith1TransactionAnd1SpanAnd1Error(Action <ITransaction> action) { var payloadSender = new MockPayloadSender(); using (var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender))) { agent.Tracer.CaptureTransaction(TransactionName, TransactionType, t => { WaitHelpers.SleepMinimum(); action(t); }); } payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().NotBeEmpty(); payloadSender.FirstTransaction.Name.Should().Be(TransactionName); payloadSender.FirstTransaction.Type.Should().Be(TransactionType); var duration = payloadSender.FirstTransaction.Duration; duration.Should().BeGreaterOrEqualToMinimumSleepLength(3); payloadSender.WaitForSpans(); payloadSender.SpansOnFirstTransaction.Should().NotBeEmpty(); payloadSender.SpansOnFirstTransaction[0].Name.Should().Be(SpanName); payloadSender.SpansOnFirstTransaction[0].Type.Should().Be(SpanType); payloadSender.WaitForErrors(); payloadSender.Errors.Should().NotBeEmpty(); payloadSender.FirstError.Exception.Type.Should().Be(typeof(InvalidOperationException).FullName); payloadSender.FirstError.Exception.Message.Should().Be(ExceptionMessage); }
public void AllSpansShouldBeSent_WhenTransactionMaxSpansIsEqualToMinusOne() { // Arrange var mockPayloadSender = new MockPayloadSender(); var mockConfig = new MockConfigSnapshot(transactionMaxSpans: "-1"); var spansCount = 1000; // Act using (var agent = new ApmAgent(new TestAgentComponents(config: mockConfig, payloadSender: mockPayloadSender))) { agent.Tracer.CaptureTransaction("test transaction name", "test transaction type", transaction => { foreach (var iteration in Enumerable.Range(1, spansCount)) { transaction.CaptureSpan($"test span name #{iteration}", "test span type", span => { }); } }); } // Assert mockPayloadSender.WaitForTransactions(); mockPayloadSender.Transactions.Count.Should().Be(1); mockPayloadSender.WaitForSpans(); mockPayloadSender.Spans.Count.Should().Be(spansCount); mockPayloadSender.FirstTransaction.SpanCount.Dropped.Should().Be(0); }
public async Task HttpCallWithoutRegisteredListener() { var mockPayloadSender = new MockPayloadSender(); var agent = new ApmAgent(new TestAgentComponents(payloadSender: mockPayloadSender)); using (var localServer = LocalServer.Create()) { await agent.Tracer.CaptureTransaction("TestTransaction", "TestType", async t => { Thread.Sleep(5); var httpClient = new HttpClient(); try { await httpClient.GetAsync(localServer.Uri); } catch (Exception e) { t.CaptureException(e); } }); mockPayloadSender.WaitForTransactions(); mockPayloadSender.Transactions.Should().NotBeEmpty(); mockPayloadSender.SignalEndSpans(); mockPayloadSender.WaitForSpans(); mockPayloadSender.SpansOnFirstTransaction.Should().BeEmpty(); } }
[NetCoreFact] //see: https://github.com/elastic/apm-agent-dotnet/issues/516 public async Task HttpCallWithRegisteredListener() { var mockPayloadSender = new MockPayloadSender(); var agent = new ApmAgent(new TestAgentComponents(payloadSender: mockPayloadSender)); var subscriber = new HttpDiagnosticsSubscriber(); using (var localServer = LocalServer.Create()) using (agent.Subscribe(subscriber)) { var url = localServer.Uri; await agent.Tracer.CaptureTransaction("TestTransaction", "TestType", async t => { Thread.Sleep(5); var httpClient = new HttpClient(); try { await httpClient.GetAsync(url); } catch (Exception e) { t.CaptureException(e); } }); mockPayloadSender.WaitForTransactions(); mockPayloadSender.Transactions.Should().NotBeEmpty(); mockPayloadSender.WaitForSpans(); mockPayloadSender.SpansOnFirstTransaction.Should().NotBeEmpty(); mockPayloadSender.SpansOnFirstTransaction[0].Context.Http.Should().NotBeNull(); mockPayloadSender.SpansOnFirstTransaction[0].Context.Http.Url.Should().Be(url); } }
public void TransactionWithSpanWithSubTypeAndAction() { const string transactionName = TestTransaction; const string transactionType = UnitTest; const string spanName = "TestSpan"; var payloadSender = new MockPayloadSender(); using (var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender))) { var transaction = agent.Tracer.StartTransaction(transactionName, transactionType); var span = transaction.StartSpan(spanName, ApiConstants.TypeDb, ApiConstants.SubtypeMssql, ApiConstants.ActionQuery); span.End(); transaction.End(); payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().NotBeEmpty(); payloadSender.WaitForSpans(); payloadSender.SpansOnFirstTransaction.Should().NotBeEmpty(); payloadSender.SpansOnFirstTransaction[0].Type.Should().Be(ApiConstants.TypeDb); payloadSender.SpansOnFirstTransaction[0].Subtype.Should().Be(ApiConstants.SubtypeMssql); payloadSender.SpansOnFirstTransaction[0].Action.Should().Be(ApiConstants.ActionQuery); agent.Service.Should().NotBeNull(); } }
public void CallToEndDoesNotChangeAlreadySetDuration(bool isSampled) { var payloadSender = new MockPayloadSender(); var expectedSpansCount = isSampled ? 1 : 0; using (var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender, config: new MockConfigSnapshot(transactionSampleRate: isSampled ? "1" : "0")))) { var transaction = agent.Tracer.StartTransaction(TestTransaction, UnitTest); var span = transaction.StartSpan(TestSpan1, ApiConstants.TypeExternal); payloadSender.Spans.Should().HaveCount(0); span.Duration = 123456.789; span.End(); payloadSender.SignalEndSpans(); payloadSender.WaitForSpans(); payloadSender.Spans.Should().HaveCount(expectedSpansCount); if (isSampled) { payloadSender.FirstSpan.Duration.Should().Be(123456.789); } payloadSender.Transactions.Should().HaveCount(0); transaction.Duration = 987654.321; transaction.End(); payloadSender.SignalEndTransactions(); payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().HaveCount(1); payloadSender.FirstTransaction.Duration.Should().Be(987654.321); } }
[NetCoreFact] //see: https://github.com/elastic/apm-agent-dotnet/issues/516 public void OnNextWithStartAndStopTwice() { var logger = new TestLogger(LogLevel.Warning); var payloadSender = new MockPayloadSender(); var agent = new ApmAgent(new TestAgentComponents(logger, payloadSender: payloadSender)); StartTransaction(agent); var listener = HttpDiagnosticListener.New(agent); var request = new HttpRequestMessage(HttpMethod.Get, "https://elastic.co"); var response = new HttpResponseMessage(HttpStatusCode.OK); //Simulate Start listener.OnNext(new KeyValuePair <string, object>(StartEventKey(listener), new { Request = request })); //Simulate Stop listener.OnNext(new KeyValuePair <string, object>(StopEventKey(listener), new { Request = request, Response = response })); //Simulate Stop again. This should not happen, still we test for this. listener.OnNext(new KeyValuePair <string, object>(StopEventKey(listener), new { Request = request, Response = response })); logger.Lines.Should().NotBeEmpty(); logger.Lines .Should() .Contain( line => line.Contains("HttpDiagnosticListener") && line.Contains("Failed capturing request") && line.Contains(HttpMethod.Get.Method) && line.Contains(request.RequestUri.AbsoluteUri)); payloadSender.WaitForTransactions(TimeSpan.FromSeconds(5)); payloadSender.Transactions.Should().NotBeNull(); payloadSender.WaitForSpans(); payloadSender.Spans.Should().ContainSingle(); }
private void AssertSpan(string action, string db = null, int count = 1) { if (!_sender.WaitForSpans()) { throw new Exception("No span received in timeout"); } _sender.Spans.Should().HaveCount(count); var span = _sender.Spans.Last(); span.Name.Should().Be(string.IsNullOrEmpty(action) ? $"Cosmos DB" : $"Cosmos DB {action}"); span.Type.Should().Be(ApiConstants.TypeDb); span.Subtype.Should().Be(ApiConstants.SubTypeCosmosDb); if (!string.IsNullOrEmpty(db)) { span.Context.Destination.Service.Resource.Should().Be($"{ApiConstants.SubTypeCosmosDb}/{db}"); } else { span.Context.Destination.Service.Resource.Should().Be(ApiConstants.SubTypeCosmosDb); } span.Context.Service.Target.Type.Should().Be(ApiConstants.SubTypeCosmosDb); if (db != null) { span.Context.Db.Instance.Should().Be(db); span.Context.Service.Target.Name.Should().Be(db); } }
public void LimitedAmountOfSpansShouldBeSent_WhenSpansAreCapturedConcurrently() { // Arrange const int spansCount = 10; const int maxSpansCount = 2; var mockPayloadSender = new MockPayloadSender(); var mockConfig = new MockConfigSnapshot(transactionMaxSpans: maxSpansCount.ToString()); // Act using (var agent = new ApmAgent(new TestAgentComponents(config: mockConfig, payloadSender: mockPayloadSender))) { agent.Tracer.CaptureTransaction("test transaction name", "test transaction type", transaction => { MultiThreadsTestUtils.TestOnThreads(spansCount, threadIndex => { transaction.CaptureSpan($"test span name #{threadIndex}", "test span type", span => { }); return(1); }); }); } // Assert mockPayloadSender.WaitForTransactions(); mockPayloadSender.Transactions.Count.Should().Be(1); mockPayloadSender.WaitForSpans(); mockPayloadSender.Spans.Count.Should().Be(maxSpansCount); mockPayloadSender.FirstTransaction.SpanCount.Dropped.Should().Be(spansCount - maxSpansCount); }
/// <summary> /// Asserts on 1 transaction with 1 span /// </summary> private MockPayloadSender AssertWith1TransactionAnd1Span(Action <ITransaction> action) { var payloadSender = new MockPayloadSender(); var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender)); agent.Tracer.CaptureTransaction(TransactionName, TransactionType, t => { WaitHelpers.SleepMinimum(); action(t); }); payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().NotBeEmpty(); payloadSender.FirstTransaction.Name.Should().Be(TransactionName); payloadSender.FirstTransaction.Type.Should().Be(TransactionType); payloadSender.WaitForSpans(); payloadSender.SpansOnFirstTransaction.Should().NotBeEmpty(); payloadSender.SpansOnFirstTransaction[0].Name.Should().Be(SpanName); payloadSender.SpansOnFirstTransaction[0].Type.Should().Be(SpanType); var duration = payloadSender.FirstTransaction.Duration; duration.Should().BeGreaterOrEqualToMinimumSleepLength(3); return(payloadSender); }
/// <summary> /// Asserts on 1 transaction with 1 async Span /// </summary> private async Task <MockPayloadSender> AssertWith1TransactionAnd1SpanAsync(Func <ITransaction, Task> func) { var payloadSender = new MockPayloadSender(); var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender)); await agent.Tracer.CaptureTransaction(TransactionName, TransactionType, async t => { await WaitHelpers.DelayMinimum(); await func(t); }); payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().NotBeEmpty(); payloadSender.FirstTransaction.Name.Should().Be(TransactionName); payloadSender.FirstTransaction.Type.Should().Be(TransactionType); var duration = payloadSender.FirstTransaction.Duration; duration.Should().BeGreaterOrEqualToMinimumSleepLength(3); payloadSender.WaitForSpans(); payloadSender.SpansOnFirstTransaction.Should().NotBeEmpty(); payloadSender.SpansOnFirstTransaction[0].Name.Should().Be(SpanName); payloadSender.SpansOnFirstTransaction[0].Type.Should().Be(SpanType); return(payloadSender); }
/// <summary> /// Asserts on 1 transaction with 1 span and 1 error /// </summary> private void AssertWith1TransactionAnd1SpanAnd1ErrorOnSubSpan(Action <ISpan> action) { var payloadSender = new MockPayloadSender(); using (var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender))) { WaitHelpers.SleepMinimum(); agent.Tracer.CaptureTransaction(TransactionName, TransactionType, t => { WaitHelpers.SleepMinimum(); t.CaptureSpan("aa", "bb", s => { WaitHelpers.SleepMinimum(); action(s); }); }); } payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().NotBeEmpty(); payloadSender.FirstTransaction.Name.Should().Be(TransactionName); payloadSender.FirstTransaction.Type.Should().Be(TransactionType); var duration = payloadSender.FirstTransaction.Duration; duration.Should().BeGreaterOrEqualToMinimumSleepLength(3); payloadSender.WaitForSpans(); payloadSender.SpansOnFirstTransaction.Should().NotBeEmpty(); payloadSender.SpansOnFirstTransaction[0].Name.Should().Be(SpanName); payloadSender.SpansOnFirstTransaction[0].Type.Should().Be(SpanType); payloadSender.WaitForErrors(); payloadSender.Errors.Should().NotBeEmpty(); payloadSender.Errors.Should().NotBeEmpty(); payloadSender.FirstError.Exception.Type.Should().Be(typeof(InvalidOperationException).FullName); payloadSender.FirstError.Exception.Message.Should().Be(ExceptionMessage); var orderedSpans = payloadSender.Spans.OrderBy(n => n.Timestamp).ToList(); var firstSpan = orderedSpans.First(); var innerSpan = orderedSpans.Last(); firstSpan.ParentId.Should().Be(payloadSender.FirstTransaction.Id); innerSpan.ParentId.Should().Be(firstSpan.Id); firstSpan.TransactionId.Should().Be(payloadSender.FirstTransaction.Id); innerSpan.TransactionId.Should().Be(payloadSender.FirstTransaction.Id); }
private async Task <MockPayloadSender> AssertWith1TransactionAnd1ErrorAnd1SpanAsyncOnSubSpan(Func <ISpan, Task> func) { var payloadSender = new MockPayloadSender(); using var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender)); await agent.Tracer.CaptureTransaction(TransactionName, TransactionType, async t => { await WaitHelpers.DelayMinimum(); await t.CaptureSpan("TestSpan", "TestSpanType", async s => { await WaitHelpers.DelayMinimum(); await func(s); }); }); payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().NotBeEmpty(); payloadSender.FirstTransaction.Name.Should().Be(TransactionName); payloadSender.FirstTransaction.Type.Should().Be(TransactionType); var duration = payloadSender.FirstTransaction.Duration; duration.Should().BeGreaterOrEqualToMinimumSleepLength(3); payloadSender.WaitForSpans(); payloadSender.SpansOnFirstTransaction.Should().NotBeEmpty(); payloadSender.SpansOnFirstTransaction[0].Name.Should().Be(SpanName); payloadSender.SpansOnFirstTransaction[0].Type.Should().Be(SpanType); payloadSender.WaitForErrors(); payloadSender.Errors.Should().NotBeEmpty(); payloadSender.FirstError.Exception.Type.Should().Be(typeof(InvalidOperationException).FullName); payloadSender.FirstError.Exception.Message.Should().Be(ExceptionMessage); var orderedSpans = payloadSender.Spans.OrderBy(n => n.Timestamp).ToList(); var firstSpan = orderedSpans.First(); var innerSpan = orderedSpans.Last(); firstSpan.ParentId.Should().Be(payloadSender.FirstTransaction.Id); innerSpan.ParentId.Should().Be(firstSpan.Id); firstSpan.TransactionId.Should().Be(payloadSender.FirstTransaction.Id); innerSpan.TransactionId.Should().Be(payloadSender.FirstTransaction.Id); return(payloadSender); }
public async Task SubscribeUnsubscribe() { var mockPayloadSender = new MockPayloadSender(); var agent = new ApmAgent(new TestAgentComponents(payloadSender: mockPayloadSender)); var subscriber = new HttpDiagnosticsSubscriber(); using (var localServer = LocalServer.Create()) { var url = localServer.Uri; using (agent.Subscribe(subscriber)) //subscribe { await agent.Tracer.CaptureTransaction("TestTransaction", "TestType", async t => { Thread.Sleep(5); var httpClient = new HttpClient(); try { await httpClient.GetAsync(url); } catch (Exception e) { t.CaptureException(e); } }); } //and then unsubscribe mockPayloadSender.WaitForAny(); mockPayloadSender.Clear(); await agent.Tracer.CaptureTransaction("TestTransaction", "TestType", async t => { Thread.Sleep(5); var httpClient = new HttpClient(); try { await httpClient.GetAsync(url); } catch (Exception e) { t.CaptureException(e); } }); mockPayloadSender.WaitForTransactions(); mockPayloadSender.FirstTransaction.Should().NotBeNull(); mockPayloadSender.SignalEndSpans(); mockPayloadSender.WaitForSpans(); mockPayloadSender.SpansOnFirstTransaction.Should().BeEmpty(); } }
public void span_that_is_not_external_service_call_should_not_have_destination() { var payloadSender = new MockPayloadSender(); using (var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender))) { agent.Tracer.CaptureTransaction("test TX name", "test TX type", tx => { tx.CaptureSpan("test span name", "test_span_subtype", () => { }); }); } payloadSender.WaitForSpans(); payloadSender.Spans.Single().Context.Destination.Should().BeNull(); }
public void CallingEndMoreThanOnceIsNoop(bool isSampled) { var payloadSender = new MockPayloadSender(); var expectedSpansCount = isSampled ? 1 : 0; using (var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender, config: new MockConfigSnapshot(transactionSampleRate: isSampled ? "1" : "0")))) { var transaction = agent.Tracer.StartTransaction(TestTransaction, UnitTest); var span = transaction.StartSpan(TestSpan1, ApiConstants.TypeExternal); payloadSender.Spans.Should().HaveCount(0); span.End(); payloadSender.SignalEndSpans(); payloadSender.WaitForSpans(); payloadSender.Spans.Should().HaveCount(expectedSpansCount); if (isSampled) { payloadSender.FirstSpan.Name.Should().Be(TestSpan1); } span.End(); payloadSender.SignalEndSpans(); payloadSender.WaitForSpans(); payloadSender.Spans.Should().HaveCount(expectedSpansCount); payloadSender.Transactions.Should().HaveCount(0); transaction.End(); payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().HaveCount(1); payloadSender.FirstTransaction.Name.Should().Be(TestTransaction); transaction.End(); payloadSender.SignalEndTransactions(); payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().HaveCount(1); } }
private void AssertSpan(string action, string db = null, int count = 1) { if (!_sender.WaitForSpans()) throw new Exception("No span received in timeout"); _sender.Spans.Should().HaveCount(count); var span = _sender.Spans.Last(); span.Name.Should().Be($"Cosmos DB {action}"); span.Type.Should().Be(ApiConstants.TypeDb); span.Subtype.Should().Be(ApiConstants.SubTypeCosmosDb); if (db != null) span.Context.Db.Instance.Should().Be(db); }
public void LabelsOnTransactionAndSpan() { const string transactionName = TestTransaction; const string transactionType = UnitTest; const string spanName = "TestSpan"; const string exceptionMessage = "Foo!"; var payloadSender = new MockPayloadSender(); using (var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender))) { var transaction = agent.Tracer.StartTransaction(transactionName, transactionType); transaction.SetLabel("fooTransaction1", "barTransaction1"); transaction.SetLabel("fooTransaction2", "barTransaction2"); var span = transaction.StartSpan(spanName, ApiConstants.TypeExternal); span.SetLabel("fooSpan1", "barSpan1"); span.SetLabel("fooSpan2", "barSpan2"); Thread.Sleep(5); //Make sure we have duration > 0 try { throw new InvalidOperationException(exceptionMessage); } catch (Exception e) { span.CaptureException(e); } span.End(); transaction.End(); } payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().ContainSingle(); payloadSender.WaitForErrors(); payloadSender.Errors.Should().ContainSingle(); payloadSender.FirstError.Exception.Message.Should().Be(exceptionMessage); payloadSender.FirstTransaction.Context.InternalLabels.Value.MergedDictionary["fooTransaction1"].Value.Should().Be("barTransaction1"); payloadSender.FirstTransaction.Context.InternalLabels.Value.MergedDictionary["fooTransaction2"].Value.Should().Be("barTransaction2"); payloadSender.WaitForSpans(); payloadSender.SpansOnFirstTransaction[0].Context.InternalLabels.Value.MergedDictionary["fooSpan1"].Value.Should().Be("barSpan1"); payloadSender.SpansOnFirstTransaction[0].Context.InternalLabels.Value.MergedDictionary["fooSpan2"].Value.Should().Be("barSpan2"); }
protected void AssertSpan(string action, string resource, int count = 1) { if (!_sender.WaitForSpans()) { throw new Exception("No span received in timeout"); } _sender.Spans.Should().HaveCount(count); var span = _sender.FirstSpan; span.Name.Should().Be($"{AzureBlobStorage.SpanName} {action} {resource}"); span.Type.Should().Be(ApiConstants.TypeStorage); span.Subtype.Should().Be(AzureBlobStorage.SubType); span.Action.Should().Be(action); span.Context.Destination.Should().NotBeNull(); var destination = span.Context.Destination; destination.Address.Should().Be(Environment.StorageAccountConnectionStringProperties.BlobFullyQualifiedNamespace); destination.Service.Resource.Should().Be($"{AzureBlobStorage.SubType}/{Environment.StorageAccountConnectionStringProperties.AccountName}"); }
private void AssertSpan(string action, string queueName) { if (!_sender.WaitForSpans()) { throw new Exception("No span received in timeout"); } _sender.Spans.Should().HaveCount(1); var span = _sender.FirstSpan; span.Name.Should().Be($"{AzureQueueStorage.SpanName} {action} to {queueName}"); span.Type.Should().Be(ApiConstants.TypeMessaging); span.Subtype.Should().Be(AzureQueueStorage.SubType); span.Action.Should().Be(action.ToLowerInvariant()); span.Context.Destination.Should().NotBeNull(); var destination = span.Context.Destination; destination.Address.Should().Be(_environment.StorageAccountConnectionStringProperties.QueueFullyQualifiedNamespace); destination.Service.Resource.Should().Be($"{AzureQueueStorage.SubType}/{queueName}"); }
public void span_with_invalid_Context_Http_Url_should_not_have_destination() { var mockLogger = new TestLogger(LogLevel.Trace); var payloadSender = new MockPayloadSender(); using (var agent = new ApmAgent(new TestAgentComponents(mockLogger, payloadSender: payloadSender))) { agent.Tracer.CaptureTransaction("test TX name", "test TX type", tx => { tx.CaptureSpan("test span name", "test_span_type", span => { span.Context.Http = new Http { Method = "PUT", Url = "://" }; }); }); } payloadSender.WaitForSpans(); payloadSender.Spans.Single().Context.Destination.Should().BeNull(); mockLogger.Lines.Should() .Contain(line => line.Contains("destination") && line.Contains("URL")); }
[NetCoreFact] //see: https://github.com/elastic/apm-agent-dotnet/issues/516 public async Task SubscriptionOnlyRegistersSpansDuringItsLifeTime() { var payloadSender = new MockPayloadSender(); var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender)); StartTransaction(agent); var spans = payloadSender.Spans; using (var localServer = LocalServer.Create()) using (var httpClient = new HttpClient()) { spans.Should().BeEmpty(); using (agent.Subscribe(new HttpDiagnosticsSubscriber())) { var res = await httpClient.GetAsync(localServer.Uri); res.IsSuccessStatusCode.Should().BeTrue(); res = await httpClient.GetAsync(localServer.Uri); res.IsSuccessStatusCode.Should().BeTrue(); } payloadSender.WaitForSpans(); spans = payloadSender.Spans; spans.Should().NotBeEmpty().And.HaveCount(2); foreach (var _ in Enumerable.Range(0, 10)) { await httpClient.GetAsync(localServer.Uri); } localServer.SeenRequests.Should() .BeGreaterOrEqualTo(10, "Make sure we actually performed more than 1 request to our local server"); } spans.Should().HaveCount(2); }
public void destination_properties_set_manually_have_precedence_over_automatically_deduced() { var url = new Uri("http://elastic.co"); const string manualAddress = "manual.address"; const int manualPort = 1234; var payloadSender = new MockPayloadSender(); using (var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender))) { agent.Tracer.CaptureTransaction("test TX name", "test TX type", tx => { tx.CaptureSpan("manually set destination address", "test_span_type", span => { span.Context.Destination = new Destination { Address = manualAddress }; span.Context.Http = new Http { Method = "PUT", Url = url.ToString() }; }); tx.CaptureSpan("manually set destination port", "test_span_type", span => { span.Context.Destination = new Destination { Port = manualPort }; span.Context.Http = new Http { Method = "PUT", Url = url.ToString() }; }); tx.CaptureSpan("manually set destination address to null", "test_span_type", span => { span.Context.Destination = new Destination { Address = null }; span.Context.Http = new Http { Method = "PUT", Url = url.ToString() }; }); tx.CaptureSpan("manually set destination port to null", "test_span_type", span => { span.Context.Destination = new Destination { Port = null }; span.Context.Http = new Http { Method = "PUT", Url = url.ToString() }; }); }); } payloadSender.WaitForSpans(count: 4); var manualAddressSpan = payloadSender.Spans.Single(s => s.Name == "manually set destination address"); manualAddressSpan.Context.Destination.Address.Should().Be(manualAddress); manualAddressSpan.Context.Destination.Port.Should().Be(url.Port); var manualPortSpan = payloadSender.Spans.Single(s => s.Name == "manually set destination port"); manualPortSpan.Context.Destination.Address.Should().Be(url.Host); manualPortSpan.Context.Destination.Port.Should().Be(manualPort); var nullAddressSpan = payloadSender.Spans.Single(s => s.Name == "manually set destination address to null"); nullAddressSpan.Context.Destination.Address.Should().BeNull(); nullAddressSpan.Context.Destination.Port.Should().Be(url.Port); var nullPortSpan = payloadSender.Spans.Single(s => s.Name == "manually set destination port to null"); nullPortSpan.Context.Destination.Address.Should().Be(url.Host); nullPortSpan.Context.Destination.Port.Should().BeNull(); }