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);
        }
Example #4
0
        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();
            }
        }
Example #5
0
        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);
        }
Example #6
0
        /// <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);
        }
Example #7
0
        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);
        }
Example #8
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();
            }
        }
Example #9
0
        [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);
                }
        }
Example #10
0
        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();
            }
        }
Example #11
0
        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);
            }
        }
Example #12
0
        [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);
            }
        }
Example #14
0
        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);
        }
Example #15
0
        /// <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);
        }
Example #16
0
        /// <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);
        }
Example #17
0
        /// <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);
        }
Example #18
0
        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);
        }
Example #19
0
        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();
            }
        }
Example #20
0
        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();
        }
Example #21
0
        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);
		}
Example #23
0
        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}");
        }
Example #25
0
        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}");
        }
Example #26
0
        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"));
        }
Example #27
0
        [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);
        }
Example #28
0
        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();
        }