Exemplo n.º 1
0
        public async Task DefaultWithRequestBodyNoError(string formName, bool useOnlyDiagnosticSource)
        {
            CreateAgent(useOnlyDiagnosticSource);

            var nvc = new List <KeyValuePair <string, string> >
            {
                new KeyValuePair <string, string>("Input1", "test1"), new KeyValuePair <string, string>(formName, "test2")
            };

            var req = new HttpRequestMessage(HttpMethod.Post, "api/Home/Post")
            {
                Content = new FormUrlEncodedContent(nvc)
            };
            var res = await _client.SendAsync(req);

            res.IsSuccessStatusCode.Should().BeTrue();

            _capturedPayload.WaitForTransactions();
            _capturedPayload.Transactions.Should().ContainSingle();

            _capturedPayload.WaitForErrors(TimeSpan.FromSeconds(1));
            _capturedPayload.Errors.Should().BeNullOrEmpty();

            _capturedPayload.FirstTransaction.Context.Request.Body.Should().Be($"Input1=test1&{formName}=[REDACTED]");
        }
        public async Task CaptureErrorLogsAsApmError()
        {
            var payloadSender = new MockPayloadSender();

            using var hostBuilder = CreateHostBuilder(payloadSender).Build();

            await hostBuilder.StartAsync();

            payloadSender.WaitForErrors();
            payloadSender.Errors.Should().NotBeEmpty();

            payloadSender.FirstError.Log.Message.Should().Be("This is a sample error log message, with a sample value: 42");
            payloadSender.FirstError.Log.ParamMessage.Should().Be("This is a sample error log message, with a sample value: {intParam}");

            // Test a log with exception
            var logger = (ILogger)hostBuilder.Services.GetService(typeof(ILogger <object>));

            try
            {
                throw new Exception();
            }
            catch (Exception e)
            {
                logger.LogError(e, "error log with exception");
            }

            payloadSender.WaitForErrors();
            payloadSender.Errors.Should().NotBeEmpty();
            payloadSender.Errors.Where(n => n.Log.Message == "error log with exception" &&
                                       n.Log.StackTrace != null && n.Log.StackTrace.Count > 0)
            .Should()
            .NotBeNullOrEmpty();

            await hostBuilder.StopAsync();
        }
        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();
        }
Exemplo n.º 4
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);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Asserts on 1 transaction with 1 async span and 1 error
        /// </summary>
        private async Task <MockPayloadSender> AssertWith1TransactionAnd1ErrorAnd1SpanAsync(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);

            payloadSender.WaitForErrors();
            payloadSender.Errors.Should().NotBeEmpty();

            payloadSender.FirstError.Exception.Type.Should().Be(typeof(InvalidOperationException).FullName);
            payloadSender.FirstError.Exception.Message.Should().Be(ExceptionMessage);

            return(payloadSender);
        }
Exemplo n.º 6
0
        public void ErrorOnSpan()
        {
            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);

                var span = transaction.StartSpan(spanName, ApiConstants.TypeExternal);

                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);
        }
Exemplo n.º 7
0
        public void Includes_Cause_When_Exception_Has_InnerException()
        {
            var mockPayloadSender = new MockPayloadSender();

            using var agent = new ApmAgent(new TestAgentComponents(payloadSender: mockPayloadSender));

            agent.Tracer.CaptureTransaction("Test", "Test", t =>
            {
                var exception = new Exception(
                    "Outer exception",
                    new Exception("Inner exception", new Exception("Inner inner exception")));

                t.CaptureException(exception);
            });

            mockPayloadSender.WaitForErrors();
            var error = mockPayloadSender.FirstError;

            error.Should().NotBeNull();
            var capturedException = error.Exception;

            capturedException.Should().NotBeNull();
            capturedException.Message.Should().Be("Outer exception");
            capturedException.Cause.Should().NotBeNull().And.HaveCount(2);

            var firstCause = capturedException.Cause[0];

            firstCause.Message.Should().Be("Inner exception");
            firstCause.Type.Should().Be("System.Exception");

            var secondCause = capturedException.Cause[1];

            secondCause.Message.Should().Be("Inner inner exception");
            secondCause.Type.Should().Be("System.Exception");
        }
Exemplo n.º 8
0
        public void ErrorOnTransactionWithEmptyHeaders()
        {
            var mockPayloadSender = new MockPayloadSender();

            using var agent = new ApmAgent(new TestAgentComponents(payloadSender: mockPayloadSender));

            agent.Tracer.CaptureTransaction("Test", "Test", t =>
            {
                t.Context.Request = new Request("GET", new Url {
                    Full = "http://localhost"
                });
                t.Context.Response = new Response();

                t.CaptureError("Test Error", "Test", new StackTrace().GetFrames());
            });

            mockPayloadSender.WaitForErrors();
            mockPayloadSender.FirstError.Should().NotBeNull();
            mockPayloadSender.FirstError.Context.Should().NotBeNull();
            mockPayloadSender.FirstError.Context.Request.Should().NotBeNull();
            mockPayloadSender.FirstError.Context.Request.Headers.Should().BeNull();
            mockPayloadSender.FirstError.Context.Response.Should().NotBeNull();
            mockPayloadSender.FirstError.Context.Response.Headers.Should().BeNull();
            mockPayloadSender.FirstError.Context.InternalLabels.Value.InnerDictionary.Should().BeEmpty();
        }
        public async Task SanitizeHeadersOnError(string headerName, bool useOnlyDiagnosticSource)
        {
            CreateAgent(useOnlyDiagnosticSource);
            _client.DefaultRequestHeaders.Add(headerName, "123");
            await _client.GetAsync("/Home/TriggerError");

            _capturedPayload.WaitForTransactions();
            _capturedPayload.Transactions.Should().ContainSingle();
            _capturedPayload.FirstTransaction.Context.Should().NotBeNull();
            _capturedPayload.FirstTransaction.Context.Request.Should().NotBeNull();
            _capturedPayload.FirstTransaction.Context.Request.Headers.Should().NotBeNull();
            _capturedPayload.FirstTransaction.Context.Request.Headers[headerName].Should().Be("[REDACTED]");

            _capturedPayload.WaitForErrors();
            _capturedPayload.Errors.Should().ContainSingle();
            _capturedPayload.FirstError.Context.Should().NotBeNull();
            _capturedPayload.FirstError.Context.Request.Should().NotBeNull();
            _capturedPayload.FirstError.Context.Request.Headers.Should().NotBeNull();
            _capturedPayload.FirstError.Context.Request.Headers[headerName].Should().Be("[REDACTED]");
        }
Exemplo n.º 10
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);
        }
Exemplo n.º 11
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);
        }
        public async Task CaptureErrorLogsAsApmError()
        {
            var payloadSender = new MockPayloadSender();

            using var hostBuilder = CreateHostBuilder(payloadSender).Build();

            await hostBuilder.StartAsync();

            payloadSender.WaitForErrors();
            payloadSender.Errors.Should().NotBeEmpty();

            payloadSender.FirstError.Log.Message.Should().Be("This is a sample error log message, with a sample value: 42");
            payloadSender.FirstError.Log.ParamMessage.Should().Be("This is a sample error log message, with a sample value: {intParam}");

            await hostBuilder.StopAsync();
        }
Exemplo n.º 13
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");
        }
Exemplo n.º 14
0
        public void ErrorOnEmptyTransaction()
        {
            var mockPayloadSender = new MockPayloadSender();

            using var agent = new ApmAgent(new TestAgentComponents(payloadSender: mockPayloadSender));

            agent.Tracer.CaptureTransaction("Test", "Test", t =>
            {
                t.CaptureError("Test Error", "Test", new StackTrace().GetFrames());

                mockPayloadSender.WaitForErrors();
                mockPayloadSender.FirstError.Should().NotBeNull("error should not be null");
                mockPayloadSender.FirstError.Context.Should().NotBeNull("error context should not be null");
                mockPayloadSender.FirstError.Context.Request.Should().BeNull();
                mockPayloadSender.FirstError.Context.Response.Should().BeNull();
            });
        }
Exemplo n.º 15
0
        /// <summary>
        /// Shared between ErrorOnTransaction and ErrorOnTransactionWithCulprit
        /// </summary>
        /// <param name="culprit">Culprit.</param>
        private static void ErrorOnTransactionCommon(string culprit = null)
        {
            const string transactionName  = TestTransaction;
            const string transactionType  = UnitTest;
            const string exceptionMessage = "Foo!";
            var          payloadSender    = new MockPayloadSender();

            using (var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender)))
            {
                var transaction = agent.Tracer.StartTransaction(transactionName, transactionType);

                Thread.Sleep(5);                 //Make sure we have duration > 0
                try
                {
                    throw new InvalidOperationException(exceptionMessage);
                }
                catch (Exception e)
                {
                    if (string.IsNullOrEmpty(culprit))
                    {
                        transaction.CaptureException(e);
                    }
                    else
                    {
                        transaction.CaptureException(e, culprit);
                    }
                }

                transaction.End();
            }

            payloadSender.WaitForTransactions();
            payloadSender.Transactions.Should().ContainSingle();
            payloadSender.WaitForErrors();
            payloadSender.Errors.Should().ContainSingle();
            payloadSender.FirstError.Exception.Message.Should().Be(exceptionMessage);
            payloadSender.FirstError.Exception.Message.Should().Be(exceptionMessage);

            payloadSender.FirstError.Culprit.Should().Be(!string.IsNullOrEmpty(culprit) ? culprit : "Elastic.Apm.Tests.ApiTests.ApiTests");
        }
Exemplo n.º 16
0
        public void ErrorShouldContainTransactionData(bool isSampled, bool captureOnSpan, bool captureAsError)
        {
            var payloadSender        = new MockPayloadSender();
            var expectedErrorContext = new Context();

            expectedErrorContext.InternalLabels.Value.InnerDictionary["one"]        = 1;
            expectedErrorContext.InternalLabels.Value.InnerDictionary["twenty two"] = "22";
            expectedErrorContext.InternalLabels.Value.InnerDictionary["true"]       = true;

            ITransaction      capturedTransaction            = null;
            IExecutionSegment errorCapturingExecutionSegment = null;
            var mockConfig = new MockConfigSnapshot(transactionSampleRate: isSampled ? "1" : "0");

            using (var agent = new ApmAgent(new TestAgentComponents(config: mockConfig, payloadSender: payloadSender)))
            {
                agent.Tracer.CaptureTransaction(TestTransaction, CustomTransactionTypeForTests, transaction =>
                {
                    capturedTransaction = transaction;

                    foreach (var item in expectedErrorContext.InternalLabels.Value.MergedDictionary)
                    {
                        transaction.Context.InternalLabels.Value.MergedDictionary[item.Key] = item.Value;
                    }
                    ISpan span = null;
                    if (captureOnSpan)
                    {
                        span = transaction.StartSpan(TestSpan1, ApiConstants.TypeExternal);
                        errorCapturingExecutionSegment = span;
                    }
                    else
                    {
                        errorCapturingExecutionSegment = transaction;
                    }

                    if (captureAsError)
                    {
                        errorCapturingExecutionSegment.CaptureError("Test error message", "Test error culprit", new StackTrace(true).GetFrames());
                    }
                    else
                    {
                        errorCapturingExecutionSegment.CaptureException(new TestException("test exception"));
                    }

                    // Immutable snapshot of the context should be captured instead of reference to a mutable object
                    // transaction.Context.Labels["three hundred thirty three"] = "333";

                    span?.End();
                });
            }

            payloadSender.WaitForErrors();
            payloadSender.Errors.Count.Should().Be(1);
            payloadSender.FirstError.Transaction.IsSampled.Should().Be(isSampled);
            payloadSender.FirstError.Transaction.Type.Should().Be(CustomTransactionTypeForTests);
            payloadSender.FirstError.TransactionId.Should().Be(capturedTransaction.Id);
            payloadSender.FirstError.TraceId.Should().Be(capturedTransaction.TraceId);
            payloadSender.FirstError.ParentId.Should()
            .Be(errorCapturingExecutionSegment.IsSampled ? errorCapturingExecutionSegment.Id : capturedTransaction.Id);

            payloadSender.FirstError.Transaction.IsSampled.Should().Be(isSampled);
            if (isSampled)
            {
                payloadSender.FirstError.Context.Should().NotBeNull().And.BeEquivalentTo(expectedErrorContext);
            }
            else
            {
                payloadSender.FirstError.Context.Should().BeNull();
            }
        }
Exemplo n.º 17
0
        public void ChangeTransactionContextAfterError()
        {
            var mockPayloadSender = new MockPayloadSender();

            using var agent = new ApmAgent(new TestAgentComponents(payloadSender: mockPayloadSender));

            agent.Tracer.CaptureTransaction("Test", "Test", t =>
            {
                t.Context.Request = new Request("GET", new Url {
                    Full = "http://localhost", Protocol = "http", Search = "abc"
                })
                {
                    Body = "abc", Headers = new Dictionary <string, string> {
                        { "header1", "headerValue" }
                    }
                };
                t.Context.Response = new Response {
                    StatusCode = 404, Finished = false
                };

                t.SetLabel("foo", "bar");
                // Let's capture an error
                t.CaptureError("Test Error", "Test", new StackTrace().GetFrames());

                // Let's change CurrentTransaction.Context after the error is captured
                t.Context.Request.Method             = "PUT";
                t.Context.Request.Body               = "cde";
                t.Context.Request.Headers["header2"] = "headerValue";
                t.Context.Request.Url.Full           = "http://elastic.co";
                t.Context.Request.Url.Protocol       = "tcp";
                t.Context.Request.Url.Search         = "cde";
                t.Context.Response.StatusCode        = 500;
                t.Context.Response.Finished          = true;
                t.Context.InternalLabels.Value.InnerDictionary["foo"].Value.Should().Be("bar");

                // Asserts on the captured error
                mockPayloadSender.WaitForErrors();
                mockPayloadSender.FirstError.Should().NotBeNull("first error should not be null");
                mockPayloadSender.FirstError.Context.Should().NotBeNull("context should not be null");
                mockPayloadSender.FirstError.Context.Request.Method.Should().Be("GET");
                mockPayloadSender.FirstError.Context.Request.Body.Should().Be("abc");
                mockPayloadSender.FirstError.Context.Request.Headers.Count.Should().Be(1);
                mockPayloadSender.FirstError.Context.Request.Headers["header1"].Should().Be("headerValue");
                mockPayloadSender.FirstError.Context.Request.Url.Full.Should().Be("http://localhost");
                mockPayloadSender.FirstError.Context.Request.Url.Protocol.Should().Be("http");
                mockPayloadSender.FirstError.Context.Request.Url.Search.Should().Be("abc");
                mockPayloadSender.FirstError.Context.Response.StatusCode.Should().Be(404);
                mockPayloadSender.FirstError.Context.Response.Finished.Should().BeFalse();
                mockPayloadSender.FirstError.Context.InternalLabels.Value.InnerDictionary["foo"].Value.Should().Be("bar");
                mockPayloadSender.FirstError.Context.Response.Headers.Should().BeNull();
            });

            // Asserts on the captured transaction
            mockPayloadSender.WaitForTransactions();
            mockPayloadSender.FirstTransaction.Context.Request.Method.Should().Be("PUT");
            mockPayloadSender.FirstTransaction.Context.Request.Body.Should().Be("cde");
            mockPayloadSender.FirstTransaction.Context.Request.Headers.Count.Should().Be(2);
            mockPayloadSender.FirstTransaction.Context.Request.Headers["header1"].Should().Be("headerValue");
            mockPayloadSender.FirstTransaction.Context.Request.Headers["header2"].Should().Be("headerValue");
            mockPayloadSender.FirstTransaction.Context.Request.Url.Full.Should().Be("http://elastic.co");
            mockPayloadSender.FirstTransaction.Context.Request.Url.Protocol.Should().Be("tcp");
            mockPayloadSender.FirstTransaction.Context.Request.Url.Search.Should().Be("cde");
            mockPayloadSender.FirstTransaction.Context.Response.StatusCode.Should().Be(500);
            mockPayloadSender.FirstTransaction.Context.Response.Finished.Should().BeTrue();
            mockPayloadSender.FirstTransaction.Context.InternalLabels.Value.InnerDictionary["foo"].Value.Should().Be("bar");
            mockPayloadSender.FirstTransaction.Context.Response.Headers.Should().BeNull();
        }