async public Task SendDataAsyncThrowsHttpException()
        {
            const int expectedNumSendBatchAsyncCall = 1;

            var dataSender = new SpanDataSender(new TelemetryConfiguration().WithApiKey("123456"));

            dataSender.WithDelayFunction(async(uint milliSecondsDelay) =>
            {
                await Task.Delay(0);
                return;
            });

            var actualCountCallsSendData = 0;

            dataSender.WithCaptureSendDataAsyncDelegate((spanBatch, retryNum) =>
            {
                actualCountCallsSendData++;
            });

            dataSender.WithHttpHandlerImpl((json) =>
            {
                throw new Exception("Server Error", new Exception("Inner exception message"));
            });

            var spanBatch = SpanBatchBuilder.Create()
                            .WithSpan(SpanBuilder.Create("Test Span").Build())
                            .Build();

            var result = await dataSender.SendDataAsync(spanBatch);

            Assert.AreEqual(NewRelicResponseStatus.Failure, result.ResponseStatus);
            Assert.AreEqual("Inner exception message", result.Message);
            Assert.IsNull(result.HttpStatusCode);
            Assert.AreEqual(expectedNumSendBatchAsyncCall, actualCountCallsSendData, "Unexpected Number of SendDataAsync calls");
        }
        async public Task RetryOn429WithSpecificDate_429HappensOnce()
        {
            const int delayMs = 10000;
            // The actual retry delay will be slightly less than delayMs since UtcNow is recalculated in RetryWithServerDelay()
            var errorMargin = TimeSpan.FromMilliseconds(50).TotalMilliseconds;
            var actualResponseFromTestRun = new List <Response>();

            uint actualDelayFromTestRun = 0;

            var dataSender = new SpanDataSender(new TelemetryConfiguration().WithApiKey("123456").WithMaxRetryAttempts(1));

            dataSender.WithDelayFunction(async(uint milliSecondsDelay) =>
            {
                actualDelayFromTestRun = milliSecondsDelay;
                await Task.Delay(0);
                return;
            });

            dataSender.WithHttpHandlerImpl((json) =>
            {
                var httpResponse                = new HttpResponseMessage((HttpStatusCode)429);
                var retryOnSpecificTime         = DateTimeOffset.UtcNow + TimeSpan.FromMilliseconds(delayMs);
                httpResponse.Headers.RetryAfter = new System.Net.Http.Headers.RetryConditionHeaderValue(retryOnSpecificTime);

                return(Task.FromResult(httpResponse));
            });

            var spanBatch = SpanBatchBuilder.Create()
                            .WithSpan(SpanBuilder.Create("Test Span").Build())
                            .Build();

            var response = await dataSender.SendDataAsync(spanBatch);

            Assert.IsTrue(actualDelayFromTestRun >= delayMs - errorMargin && actualDelayFromTestRun <= delayMs + errorMargin, $"Expected delay: {delayMs}, margin: +/-{errorMargin}, actual delay: {actualDelayFromTestRun}");
        }
Exemplo n.º 3
0
        /// <summary>
        /// In this example, all of the spans are for the same trace.  Accordingly, the
        /// TraceId is set in the SpanBatchBuilder.
        /// </summary>
        private static async Task Example_SpanBatchForSingleTrace()
        {
            var traceId = System.Guid.NewGuid().ToString();

            // The SpanBatchBuilder manages a collection of Spans
            var spanBatchBuilder = SpanBatchBuilder.Create();

            // Since all of the spans in this batch represent a single
            // execution trace, set the TraceId on the SpanBatch instead
            // of on the individual spans.
            spanBatchBuilder.WithTraceId(traceId);

            // Perform 10 units of work as part of this trace/spanBatch
            for (var spanIdx = 0; spanIdx < 5; spanIdx++)
            {
                // The SpanBuilder is used to crate a new span.
                // Create a new SpanBuilder assigning it a random guid as the spanId
                var spanBuilder = SpanBuilder.Create(Guid.NewGuid().ToString());

                //Add a name to the span to better understand it in the New Relic UI.
                spanBuilder.WithName($"{traceId} - {spanIdx}");

                // Capture the start time for later use in calculating duration.
                var startTime = DateTime.UtcNow;

                try
                {
                    // Attempt to perform a unit of work
                    DoWork($"Hello World #{spanIdx}");
                }
                catch (Exception ex)
                {
                    // In the event of an exception, mark the span
                    // as having an error and record a custom attribute
                    // with the details about the exception.
                    spanBuilder.HasError(true);
                    spanBuilder.WithAttribute("Exception", ex);
                }
                finally
                {
                    // Calculate the duration of execution and record it
                    var endTime = DateTime.UtcNow;
                    spanBuilder.WithExecutionTimeInfo(startTime, endTime);

                    //Obtain the completed Span from the SpanBuilder
                    var span = spanBuilder.Build();

                    //Attach the span to the Span Batch.
                    spanBatchBuilder.WithSpan(span);
                }
            }

            // Obtain the SpanBatch from the SpanBatchBuilder
            var spanBatch = spanBatchBuilder.Build();

            // Send the SpanBatch to the New Relic endpoint.
            await SendDataToNewRelic(spanBatch);
        }
        async public Task RequestTooLarge_SplitFail()
        {
            const int    expectedCountCallsSendData         = 7;
            const int    expectedCountSuccessfulSpanBatches = 1;
            const string traceID_Success           = "OK";
            const string traceID_SplitBatch_Prefix = "TooLarge";

            var actualCountCallsSendData = 0;
            var successfulSpans          = new List <Span>();

            var dataSender = new SpanDataSender(new TelemetryConfiguration().WithApiKey("123456"));

            var shouldSplitJsons = new List <string>();

            // Mock the behavior to return EntityTooLarge for any span batch that has a span with an
            // id that starts with TooLarge.
            dataSender.WithCaptureSendDataAsyncDelegate((spanBatch, retryNum) =>
            {
                actualCountCallsSendData++;

                if (spanBatch.Spans.Any(x => x.Id.StartsWith(traceID_SplitBatch_Prefix)))
                {
                    shouldSplitJsons.Add(spanBatch.ToJson());
                }
                else
                {
                    successfulSpans.AddRange(spanBatch.Spans);
                }
            });

            dataSender.WithHttpHandlerImpl((json) =>
            {
                var response = shouldSplitJsons.Contains(json)
                    ? new HttpResponseMessage(System.Net.HttpStatusCode.RequestEntityTooLarge)
                    : new HttpResponseMessage(System.Net.HttpStatusCode.OK);

                return(Task.FromResult(response));
            });

            var spanBatchBuilder = SpanBatchBuilder.Create();

            spanBatchBuilder.WithSpan(SpanBuilder.Create($"{traceID_SplitBatch_Prefix}1").Build());
            spanBatchBuilder.WithSpan(SpanBuilder.Create($"{traceID_SplitBatch_Prefix}2").Build());
            spanBatchBuilder.WithSpan(SpanBuilder.Create($"{traceID_SplitBatch_Prefix}3").Build());
            spanBatchBuilder.WithSpan(SpanBuilder.Create(traceID_Success).Build());

            var spanBatch = spanBatchBuilder.Build();

            // Act
            var result = await dataSender.SendDataAsync(spanBatch);

            // Assert
            Assert.AreEqual(NewRelicResponseStatus.Failure, result.ResponseStatus);
            Assert.AreEqual(expectedCountCallsSendData, actualCountCallsSendData, "Unexpected number of calls");
            Assert.AreEqual(expectedCountSuccessfulSpanBatches, successfulSpans.Count, $"Only {expectedCountSuccessfulSpanBatches} span should have successfully sent");
            Assert.AreEqual(traceID_Success, successfulSpans[0].Id, "Incorrect span was sent");
        }
Exemplo n.º 5
0
        public void TraceIdIsSet()
        {
            var traceId   = "myId";
            var spanBatch = SpanBatchBuilder.Create()
                            .WithTraceId(traceId)
                            .Build();

            Assert.AreEqual(traceId, spanBatch.CommonProperties.TraceId);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Creates a new Trace (SpanBatch) and sets the TraceId
        /// to a Guid
        /// </summary>
        private static SpanBatchBuilder NewTrace()
        {
            var traceId = Guid.NewGuid().ToString();

            Console.WriteLine($"{"SIMPLE TRACER: Trace Started",-30}: {traceId}");

            return(SpanBatchBuilder.Create()
                   .WithTraceId(traceId));
        }
Exemplo n.º 7
0
        /// <summary>
        /// In this example, multiple traces will be reported in the same batch.
        /// Accordingly, the TraceId is applied to the individual spans, and NOT on
        /// the SpanBatch.
        /// </summary>
        private static async Task Example_SpanBatchForMultipleTraces()
        {
            var spanBatchBuilder = SpanBatchBuilder.Create();

            for (var traceIdx = 0; traceIdx < 3; traceIdx++)
            {
                var traceId = Guid.NewGuid().ToString();

                for (var spanIdx = 0; spanIdx < 5; spanIdx++)
                {
                    var spanBuilder = SpanBuilder.Create(Guid.NewGuid().ToString());

                    // Since multiple traces will be reported in the same SpanBatch,
                    // the TraceID needs to be attached to the individual spans.
                    spanBuilder.WithTraceId(traceId)
                    .WithName($"{traceId} - {spanIdx}");

                    // Capture the start time for later use in calculating duration.
                    var startTime = DateTime.UtcNow;

                    try
                    {
                        // Attempt to perform a unit of work
                        DoWork($"Hello Outer Space Trace={traceId}, Span={spanIdx}");
                    }
                    catch (Exception ex)
                    {
                        // In the event of an exception, mark the span
                        // as having an error and record a custom attribute
                        // with the details about the exception.
                        spanBuilder.HasError(true);
                        spanBuilder.WithAttribute("Exception", ex);
                    }
                    finally
                    {
                        // Calculate the duration of execution and record it
                        var endTime = DateTime.UtcNow;
                        spanBuilder.WithExecutionTimeInfo(startTime, endTime);

                        //Obtain the completed Span from the SpanBuilder
                        var span = spanBuilder.Build();

                        //Attach the span to the Span Batch.
                        spanBatchBuilder.WithSpan(span);
                    }
                }

                Console.WriteLine();
            }

            // Obtain the SpanBatch from the SpanBatchBuilder
            var spanBatch = spanBatchBuilder.Build();

            // Send the SpanBatch to the New Relic endpoint.
            await SendDataToNewRelic(spanBatch);
        }
        async public Task RetryOn429_RetriesExceeded()
        {
            const int delayMS = 10000;
            const int expectedNumSendBatchAsyncCall      = 9; // 1 first call + 3 calls from retries
            var       expectedBackoffSequenceFromTestRun = new List <int>()
            {
                delayMS,
                delayMS,
                delayMS,
                delayMS,
                delayMS,
                delayMS,
                delayMS,
                delayMS
            };

            var actualBackoffSequenceFromTestRun = new List <uint>();

            var dataSender = new SpanDataSender(new TelemetryConfiguration().WithApiKey("123456"));

            dataSender.WithDelayFunction(async(uint milliSecondsDelay) =>
            {
                actualBackoffSequenceFromTestRun.Add(milliSecondsDelay);
                await Task.Delay(0);
                return;
            });

            var actualCountCallsSendData = 0;

            dataSender.WithCaptureSendDataAsyncDelegate((spanBatch, retryNum) =>
            {
                actualCountCallsSendData++;
            });

            dataSender.WithHttpHandlerImpl((json) =>
            {
                var httpResponse = new HttpResponseMessage((HttpStatusCode)429);
                httpResponse.Headers.RetryAfter = new System.Net.Http.Headers.RetryConditionHeaderValue(TimeSpan.FromMilliseconds(delayMS));

                return(Task.FromResult(httpResponse));
            });

            var spanBatch = SpanBatchBuilder.Create()
                            .WithSpan(SpanBuilder.Create("Test Span").Build())
                            .Build();

            var result = await dataSender.SendDataAsync(spanBatch);

            Assert.AreEqual(NewRelicResponseStatus.Failure, result.ResponseStatus);
            Assert.AreEqual(expectedNumSendBatchAsyncCall, actualCountCallsSendData, "Unexpected Number of SendDataAsync calls");
            CollectionAssert.AreEqual(expectedBackoffSequenceFromTestRun, actualBackoffSequenceFromTestRun);
        }
        async public Task RetryBackoffSequence_IntermittentTimeoutEventuallySucceeds()
        {
            var expectedNumSendBatchAsyncCall      = 4; // 1 first call + 3 calls from retries
            var expectedBackoffSequenceFromTestRun = new List <int>()
            {
                5000,
                10000,
                20000,
            };

            var actualBackoffSequenceFromTestRun = new List <uint>();

            var dataSender = new SpanDataSender(new TelemetryConfiguration().WithApiKey("123456"));

            dataSender.WithDelayFunction(async(uint milliSecondsDelay) =>
            {
                actualBackoffSequenceFromTestRun.Add(milliSecondsDelay);
                await Task.Delay(0);
                return;
            });

            var actualCountCallsSendData = 0;

            dataSender.WithCaptureSendDataAsyncDelegate((spanBatch, retryNum) =>
            {
                actualCountCallsSendData++;
            });

            var callCount = 0;

            dataSender.WithHttpHandlerImpl((json) =>
            {
                callCount++;
                if (callCount < 4)
                {
                    return(Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.RequestTimeout)));
                }

                return(Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.OK)));
            });

            var spanBatch = SpanBatchBuilder.Create()
                            .WithSpan(SpanBuilder.Create("Test Span").Build())
                            .Build();

            var result = await dataSender.SendDataAsync(spanBatch);

            Assert.AreEqual(NewRelicResponseStatus.Success, result.ResponseStatus);
            Assert.AreEqual(expectedNumSendBatchAsyncCall, actualCountCallsSendData, "Unexpected Number of SendDataAsync calls");
            CollectionAssert.AreEqual(expectedBackoffSequenceFromTestRun, actualBackoffSequenceFromTestRun);
        }
        public void ToJson_NonEmptySpanBatch()
        {
            // Arrange
            var spanBatch = SpanBatchBuilder.Create()
                            .WithTraceId("traceId")
                            .WithSpan(SpanBuilder.Create("span1")
                                      .WithTraceId("traceId")
                                      .WithTimestamp(1L)
                                      .WithServiceName("serviceName")
                                      .WithDurationMs(67)
                                      .WithName("name")
                                      .WithParentId("parentId")
                                      .HasError(true).Build())
                            .Build();

            // Act
            var jsonString = spanBatch.ToJson();

            // Assert
            var resultSpanBatches = TestHelpers.DeserializeArray(jsonString);

            TestHelpers.AssertForCollectionLength(resultSpanBatches, 1);

            var resultSpanBatch = resultSpanBatches.First();

            var resultCommonProps = TestHelpers.DeserializeObject(resultSpanBatch["common"]);

            TestHelpers.AssertForAttribValue(resultCommonProps, "trace.id", "traceId");

            var resultSpans = TestHelpers.DeserializeArray(resultSpanBatch["spans"]);

            TestHelpers.AssertForCollectionLength(resultSpans, 1);

            var resultSpan = resultSpans.FirstOrDefault();

            TestHelpers.AssertForAttribValue(resultSpan, "id", "span1");
            TestHelpers.AssertForAttribValue(resultSpan, "trace.id", "traceId");
            TestHelpers.AssertForAttribValue(resultSpan, "timestamp", 1);
            TestHelpers.AssertForAttribCount(resultSpan, 4);

            var resultSpanAttribs = TestHelpers.DeserializeObject(resultSpan["attributes"]);

            TestHelpers.AssertForAttribValue(resultSpanAttribs, "duration.ms", 67);
            TestHelpers.AssertForAttribValue(resultSpanAttribs, "name", "name");
            TestHelpers.AssertForAttribValue(resultSpanAttribs, "service.name", "serviceName");
            TestHelpers.AssertForAttribValue(resultSpanAttribs, "parent.id", "parentId");
            TestHelpers.AssertForAttribValue(resultSpanAttribs, "error", true);
            TestHelpers.AssertForAttribCount(resultSpanAttribs, 5);
        }
        public void ToJson_EmptySpanBatch()
        {
            // Arrange
            var spanBatch = SpanBatchBuilder.Create()
                            .WithTraceId("traceId")
                            .Build();

            // Act
            var jsonString = spanBatch.ToJson();

            //Assert
            var resultSpanBatch   = TestHelpers.DeserializeArrayFirstOrDefault(jsonString);
            var resultCommonProps = TestHelpers.DeserializeObject(resultSpanBatch["common"]);

            TestHelpers.AssertForAttribValue(resultCommonProps, "trace.id", "traceId");
        }
        async public Task SendDataAsyncThrowsNonHttpException()
        {
            const int expectedNumSendBatchAsyncCall = 1;
            const int expectedNumHttpHandlerCall    = 0;

            var dataSender = new SpanDataSender(new TelemetryConfiguration().WithAPIKey("123456"));

            dataSender.WithDelayFunction(async(int milliSecondsDelay) =>
            {
                await Task.Delay(0);
                return;
            });

            var actualCountCallsSendData = 0;

            dataSender.WithCaptureSendDataAsyncDelegate((sb, retry) =>
            {
                actualCountCallsSendData++;
                throw new Exception("Test Exception");
            });

            var actualCallsHttpHandler = 0;

            dataSender.WithHttpHandlerImpl((json) =>
            {
                actualCallsHttpHandler++;
                return(Task.FromResult(new HttpResponseMessage()
                {
                    StatusCode = HttpStatusCode.OK
                }));
            });


            var spanBatch = SpanBatchBuilder.Create()
                            .WithSpan(SpanBuilder.Create("Test Span").Build())
                            .Build();

            var result = await dataSender.SendDataAsync(spanBatch);

            Assert.AreEqual(NewRelicResponseStatus.Failure, result.ResponseStatus);
            Assert.AreEqual("Test Exception", result.Message);
            Assert.IsNull(result.HttpStatusCode);

            Assert.AreEqual(expectedNumSendBatchAsyncCall, actualCountCallsSendData, "Unexpected Number of SendDataAsync calls");
            Assert.AreEqual(expectedNumHttpHandlerCall, actualCallsHttpHandler, "Unexpected Number of Http Handler calls");
        }
        public void SendAnEmptySpanBatch()
        {
            var traceId   = "123";
            var spanBatch = SpanBatchBuilder.Create()
                            .WithTraceId(traceId)
                            .Build();

            var dataSender = new SpanDataSender(new TelemetryConfiguration().WithAPIKey("123456"));

            dataSender.WithHttpHandlerImpl((serializedJson) =>
            {
                var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
                return(Task.FromResult(response));
            });

            var response = dataSender.SendDataAsync(spanBatch).Result;

            Assert.AreEqual(NewRelicResponseStatus.DidNotSend_NoData, response.ResponseStatus);
        }
        public void DateSpecificRetry_CorrectDelayDuration()
        {
            var traceId         = "123";
            var retryDuration   = TimeSpan.FromSeconds(10);
            var retryDurationMs = retryDuration.TotalMilliseconds;
            var errorMargin     = TimeSpan.FromMilliseconds(50).TotalMilliseconds;

            var spanBatch = SpanBatchBuilder.Create()
                            .WithTraceId(traceId)
                            .WithSpan(SpanBuilder.Create("TestSpan").Build())
                            .Build();

            var config = new TelemetryConfiguration().WithAPIKey("12345");

            var dataSender = new SpanDataSender(config);

            //Mock out the communication layer
            dataSender.WithHttpHandlerImpl((serializedJson) =>
            {
                var response                = new HttpResponseMessage((System.Net.HttpStatusCode) 429);
                var retryOnSpecificTime     = DateTimeOffset.Now + retryDuration;
                response.Headers.RetryAfter = new System.Net.Http.Headers.RetryConditionHeaderValue(retryOnSpecificTime);
                return(Task.FromResult(response));
            });

            var capturedDelays = new List <int>();

            dataSender.WithDelayFunction((delay) =>
            {
                capturedDelays.Add(delay);
                return(Task.Delay(0));
            });

            var response = dataSender.SendDataAsync(spanBatch).Result;

            Assert.AreEqual(NewRelicResponseStatus.Failure, response.ResponseStatus);
            Assert.AreEqual(config.MaxRetryAttempts, capturedDelays.Count);
            Assert.AreEqual(System.Net.HttpStatusCode.RequestTimeout, response.HttpStatusCode);
            Assert.IsTrue(capturedDelays.All(x => x >= retryDurationMs - errorMargin && x <= retryDurationMs + errorMargin),
                          "Expected duration out of range");
        }
        public void ToJson_DuplicatePropertyValuesKeepsLast()
        {
            //Arrange
            var spanBatch = SpanBatchBuilder.Create()
                            .WithTraceId("BadTraceID")
                            .WithTraceId("GoodTraceID")
                            .WithAttribute("customAtt1", "BadAttr1")
                            .WithAttribute("customAtt1", "GoodAttr1")
                            .WithAttribute("customAtt2", -1000)
                            .WithAttribute("customAtt2", 1000)
                            .WithSpan(SpanBuilder.Create("span1")
                                      .WithTraceId("BadTraceID")
                                      .WithTraceId("GoodTraceID")
                                      .WithTimestamp(-100)
                                      .WithTimestamp(100)
                                      .WithServiceName("BadserviceName")
                                      .WithServiceName("GoodServiceName")
                                      .WithDurationMs(-500)
                                      .WithDurationMs(500)
                                      .WithName("BadName")
                                      .WithName("GoodName")
                                      .WithParentId("BadParentId")
                                      .WithParentId("GoodParentId")
                                      .HasError(true)
                                      .HasError(false)
                                      .HasError(true)
                                      .Build())
                            .Build();

            // Act
            var jsonString = spanBatch.ToJson();

            // Assert
            var resultSpanBatches = TestHelpers.DeserializeArray(jsonString);

            TestHelpers.AssertForCollectionLength(resultSpanBatches, 1);

            var resultSpanBatch = resultSpanBatches.First();

            var resultCommonProps = TestHelpers.DeserializeObject(resultSpanBatch["common"]);

            TestHelpers.AssertForAttribValue(resultCommonProps, "trace.id", "GoodTraceID");

            var resultCommonPropAttribs = TestHelpers.DeserializeObject(resultCommonProps["attributes"]);

            TestHelpers.AssertForAttribCount(resultCommonPropAttribs, 2);
            TestHelpers.AssertForAttribValue(resultCommonPropAttribs, "customAtt1", "GoodAttr1");
            TestHelpers.AssertForAttribValue(resultCommonPropAttribs, "customAtt2", 1000);

            var resultSpans = TestHelpers.DeserializeArray(resultSpanBatch["spans"]);

            TestHelpers.AssertForCollectionLength(resultSpans, 1);

            var resultSpan = resultSpans.FirstOrDefault();

            TestHelpers.AssertForAttribValue(resultSpan, "id", "span1");
            TestHelpers.AssertForAttribValue(resultSpan, "trace.id", "GoodTraceID");
            TestHelpers.AssertForAttribValue(resultSpan, "timestamp", 100);
            TestHelpers.AssertForAttribCount(resultSpan, 4);

            var resultSpanAttribs = TestHelpers.DeserializeObject(resultSpan["attributes"]);

            TestHelpers.AssertForAttribValue(resultSpanAttribs, "duration.ms", 500);
            TestHelpers.AssertForAttribValue(resultSpanAttribs, "name", "GoodName");
            TestHelpers.AssertForAttribValue(resultSpanAttribs, "service.name", "GoodServiceName");
            TestHelpers.AssertForAttribValue(resultSpanAttribs, "parent.id", "GoodParentId");
            TestHelpers.AssertForAttribValue(resultSpanAttribs, "error", true);
            TestHelpers.AssertForAttribCount(resultSpanAttribs, 5);
        }
        public async Task <IEnumerable <WeatherForecast> > Get()
        {
            // The SpanBuilder is a tool to help Build spans.  Each span must have
            // a unique identifier.  In this example, we are using a Guid.
            var spanId = Guid.NewGuid().ToString();

            var spanBuilder = SpanBuilder.Create(spanId);

            // We can add additional attribution to a span using helper functions.
            // In this case a timestamp and the controller action name are recorded
            spanBuilder.WithTimestamp(DateTimeOffset.UtcNow)
            .WithName("WeatherForecast/Get");

            // Wrapping the unit of work inside a try/catch is helpful to ensure that
            // spans are always reported to the endpoint, even if they have exceptions.
            try
            {
                // This is the unit of work being tracked by the span.
                var rng    = new Random();
                var result = Enumerable.Range(1, 5)
                             .Select(index => new WeatherForecast()
                {
                    Date         = DateTime.Now.AddDays(index),
                    TemperatureC = rng.Next(-20, 55),
                    Summary      = Summaries[rng.Next(Summaries.Length)]
                })
                             .ToArray();

                return(result);
            }
            // If an unhandled exception occurs, it can be denoted on the span.
            catch (Exception ex)
            {
                // In the event of an exception
                spanBuilder.HasError(true);
                spanBuilder.WithAttribute("Exception", ex);

                //This ensures that tracking of spans doesn't interfere with the normal execution flow
                throw;
            }
            // In all cases, the span is sent up to the New Relic endpoint.
            finally
            {
                // Obtain the span from the SpanBuilder.
                var span = spanBuilder.Build();

                // The SpanBatchBuilder is a tool to help create SpanBatches
                // Create a new SpanBatchBuilder and associate the span to it.
                var spanBatchBuilder = SpanBatchBuilder.Create()
                                       .WithSpan(span);

                // Since this SpanBatch represents a single trace, identify
                // the TraceId for the entire batch.
                spanBatchBuilder.WithTraceId(Guid.NewGuid().ToString());

                // Obtain the spanBatch from the builder
                var spanBatch = spanBatchBuilder.Build();

                // Send it to the New Relic endpoint.
                var newRelicResult = await _spanDataSender.SendDataAsync(spanBatch);

                if (newRelicResult.ResponseStatus == NewRelicResponseStatus.Failure)
                {
                    _logger.LogWarning("There was a problem sending the SpanBatch to New Relic endpoint");
                }
            }
        }
        public void ToJson_SpanBatchWithMultipleSpans()
        {
            // Arrange
            var spanBatchBuilder = SpanBatchBuilder.Create()
                                   .WithTraceId("traceId")
                                   .WithAttribute("customAtt1", "hello")
                                   .WithAttribute("customAtt2", 1)
                                   .WithAttribute("customAtt3", (decimal)1.2)
                                   .WithAttribute("customAtt4", true);



            spanBatchBuilder.WithSpan(SpanBuilder.Create("span1")
                                      .WithTraceId("traceId1")
                                      .WithTimestamp(1)
                                      .WithServiceName("serviceName1")
                                      .WithDurationMs(100)
                                      .WithName("name1")
                                      .WithParentId("parentId1")
                                      .HasError(true)
                                      .Build());

            spanBatchBuilder.WithSpan(SpanBuilder.Create("span2")
                                      .WithTraceId("traceId2")
                                      .WithTimestamp(2)
                                      .WithServiceName("serviceName2")
                                      .WithDurationMs(200)
                                      .WithName("name2")
                                      .WithParentId("parentId2")
                                      .HasError(false)
                                      .Build());

            var spanBatch = spanBatchBuilder.Build();

            // Act
            var jsonString = spanBatch.ToJson();

            //Assert
            var resultSpanBatches = TestHelpers.DeserializeArray(jsonString);

            TestHelpers.AssertForCollectionLength(resultSpanBatches, 1);

            var resultSpanBatch = resultSpanBatches.First();

            var resultCommonProps = TestHelpers.DeserializeObject(resultSpanBatch["common"]);

            TestHelpers.AssertForAttribValue(resultCommonProps, "trace.id", "traceId");

            var resultCommonPropAttribs = TestHelpers.DeserializeObject(resultCommonProps["attributes"]);

            TestHelpers.AssertForAttribCount(resultCommonPropAttribs, 4);
            TestHelpers.AssertForAttribValue(resultCommonPropAttribs, "customAtt1", "hello");
            TestHelpers.AssertForAttribValue(resultCommonPropAttribs, "customAtt2", 1);
            TestHelpers.AssertForAttribValue(resultCommonPropAttribs, "customAtt3", (decimal)1.2);
            TestHelpers.AssertForAttribValue(resultCommonPropAttribs, "customAtt4", true);

            var resultSpans = TestHelpers.DeserializeArray(resultSpanBatch["spans"]);

            TestHelpers.AssertForCollectionLength(resultSpans, 2);

            var firstSpan = resultSpans[0];

            TestHelpers.AssertForAttribValue(firstSpan, "id", "span1");
            TestHelpers.AssertForAttribValue(firstSpan, "trace.id", "traceId1");
            TestHelpers.AssertForAttribValue(firstSpan, "timestamp", 1);
            TestHelpers.AssertForAttribCount(firstSpan, 4);

            var firstSpanAttribs = TestHelpers.DeserializeObject(firstSpan["attributes"]);

            TestHelpers.AssertForAttribValue(firstSpanAttribs, "duration.ms", 100);
            TestHelpers.AssertForAttribValue(firstSpanAttribs, "name", "name1");
            TestHelpers.AssertForAttribValue(firstSpanAttribs, "service.name", "serviceName1");
            TestHelpers.AssertForAttribValue(firstSpanAttribs, "parent.id", "parentId1");
            TestHelpers.AssertForAttribValue(firstSpanAttribs, "error", true);

            TestHelpers.AssertForAttribCount(firstSpanAttribs, 5);

            var secondSpan = resultSpans[1];

            TestHelpers.AssertForAttribValue(secondSpan, "id", "span2");
            TestHelpers.AssertForAttribValue(secondSpan, "trace.id", "traceId2");
            TestHelpers.AssertForAttribValue(secondSpan, "timestamp", 2);
            TestHelpers.AssertForAttribCount(secondSpan, 4);

            var secondSpanAttribs = TestHelpers.DeserializeObject(secondSpan["attributes"]);

            TestHelpers.AssertForAttribValue(secondSpanAttribs, "duration.ms", 200);
            TestHelpers.AssertForAttribValue(secondSpanAttribs, "name", "name2");
            TestHelpers.AssertForAttribValue(secondSpanAttribs, "service.name", "serviceName2");
            TestHelpers.AssertForAttribValue(secondSpanAttribs, "parent.id", "parentId2");
            TestHelpers.AssertForAttribCount(secondSpanAttribs, 4);
        }
Exemplo n.º 18
0
        public void TraceIdIsNotSet()
        {
            var spanBatch = SpanBatchBuilder.Create().Build();

            Assert.Null(spanBatch.CommonProperties?.TraceId);
        }
        async public Task RequestTooLarge_SplitSuccess()
        {
            const int    expectedCountSpans                 = 9;
            const int    expectedCountCallsSendData         = 7;
            const int    expectedCountSuccessfulSpanBatches = 4;
            const int    expectedCountDistinctTraceIds      = 1;
            const int    expectedCountSpanBatchAttribSets   = 1;
            const string expectedTraceID = "TestTrace";

            var actualCountCallsSendData = 0;

            // Arrange
            var successfulSpanBatches = new List <SpanBatch>();

            var dataSender = new SpanDataSender(new TelemetryConfiguration().WithApiKey("123456"));

            var okJsons = new List <string>();

            // Mock the behavior to return EntityTooLarge for any span batch with 4 or more spans.
            // Anything with less than 4 will return success.
            dataSender.WithCaptureSendDataAsyncDelegate((spanBatch, retryNum) =>
            {
                actualCountCallsSendData++;

                if (spanBatch.Spans.Count < 4)
                {
                    okJsons.Add(spanBatch.ToJson());
                    successfulSpanBatches.Add(spanBatch);
                }
            });

            dataSender.WithHttpHandlerImpl((json) =>
            {
                var response = okJsons.Contains(json)
                    ? new HttpResponseMessage(System.Net.HttpStatusCode.OK)
                    : new HttpResponseMessage(System.Net.HttpStatusCode.RequestEntityTooLarge);

                return(Task.FromResult(response));
            });

            var attribs = new Dictionary <string, object>()
            {
                { "testAttrib1", "testAttribValue1" }
            };

            var spanBatchBuilder = SpanBatchBuilder.Create()
                                   .WithTraceId(expectedTraceID)
                                   .WithAttributes(attribs);

            for (var i = 0; i < expectedCountSpans; i++)
            {
                spanBatchBuilder.WithSpan(SpanBuilder.Create(i.ToString()).Build());
            }

            var spanBatch = spanBatchBuilder.Build();

            // Act
            await dataSender.SendDataAsync(spanBatch);

            // Assert
            Assert.AreEqual(expectedCountCallsSendData, actualCountCallsSendData);

            //Test the Spans
            Assert.AreEqual(expectedCountSuccessfulSpanBatches, successfulSpanBatches.Count, "Unexpected number of calls");
            Assert.AreEqual(expectedCountSpans, successfulSpanBatches.SelectMany(x => x.Spans).Count(), "Unexpected number of successful Spans");
            Assert.AreEqual(expectedCountSpans, successfulSpanBatches.SelectMany(x => x.Spans).Select(x => x.Id).Distinct().Count(), "All Spans should be unique (spanId)");

            //Test the attributes on the spanbatch
            Assert.AreEqual(expectedCountDistinctTraceIds, successfulSpanBatches.Select(x => x.CommonProperties.TraceId).Distinct().Count(), "The traceId on split batches are not the same");
            Assert.AreEqual(expectedTraceID, successfulSpanBatches.FirstOrDefault().CommonProperties.TraceId, "The traceId on split batches does not match the original traceId");
            Assert.AreEqual(expectedCountSpanBatchAttribSets, successfulSpanBatches.Select(x => x.CommonProperties.Attributes).Distinct().Count(), "The attributes on all span batches should be the same");
            Assert.AreEqual(attribs, successfulSpanBatches.Select(x => x.CommonProperties.Attributes).FirstOrDefault(), "The Span Batch attribute values on split batches do not match the attributes of the original span batch.");
        }