コード例 #1
0
        public void SendANonEmptySpanBatch()
        {
            var traceId = "123";

            var span = new NewRelicSpan(
                traceId: null,
                spanId: "Span1",
                timestamp: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                parentSpanId: null,
                attributes: new Dictionary <string, object>()
            {
                { NewRelicConsts.Tracing.AttribNameName, "TestSpan" },
            });

            var spanBatch = new NewRelicSpanBatch(
                spans: new[] { span },
                commonProperties: new NewRelicSpanBatchCommonProperties(traceId));

            var dataSender = new TraceDataSender(new TelemetryConfiguration()
            {
                ApiKey = "123456"
            }, null);

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

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

            Assert.Equal(NewRelicResponseStatus.Success, response.ResponseStatus);
        }
コード例 #2
0
        public async Task RetryBackoffSequence_RetriesExceeded()
        {
            var expectedNumSendBatchAsyncCall      = 9; // 1 first call + 8 calls from retries
            var expectedBackoffSequenceFromTestRun = new List <uint>()
            {
                5000,
                10000,
                20000,
                40000,
                80000,
                80000,
                80000,
                80000,
            };
            var actualBackoffSequenceFromTestRun = new List <uint>();
            var actualCountCallsSendData         = 0;

            var dataSender = new TraceDataSender(new TelemetryConfiguration()
            {
                ApiKey = "123456"
            }, null);

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

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

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

            var spans = new List <NewRelicSpan>()
            {
                new NewRelicSpan(
                    traceId: null,
                    spanId: "Test Span",
                    timestamp: 12345,
                    parentSpanId: null,
                    attributes: null),
            };

            var spanBatch = new NewRelicSpanBatch(spans);

            var result = await dataSender.SendDataAsync(spanBatch);

            Assert.Equal(NewRelicResponseStatus.Failure, result.ResponseStatus);
            Assert.Equal(HttpStatusCode.RequestTimeout, result.HttpStatusCode);
            Assert.Equal(expectedNumSendBatchAsyncCall, actualCountCallsSendData);
            Assert.Equal(expectedBackoffSequenceFromTestRun, actualBackoffSequenceFromTestRun);
        }
コード例 #3
0
        /// <summary>
        /// Sends the data to New Relic endpoint.
        /// </summary>
        /// <param name="spanBatch"></param>
        /// <returns></returns>
        private static async Task SendDataToNewRelic(NewRelicSpanBatch spanBatch)
        {
            var result = await _dataSvc.SendDataAsync(spanBatch);

            Console.WriteLine("Send Data to New Relic");
            Console.WriteLine($"{"Result",-20}: {result.ResponseStatus}");
            Console.WriteLine($"{"Http Status",-20}: {result.HttpStatusCode}");
            Console.WriteLine($"{"Message",-20}: {result.Message}");
        }
コード例 #4
0
        public async Task SendDataAsyncThrowsNonHttpException()
        {
            const int expectedNumSendBatchAsyncCall = 1;
            const int expectedNumHttpHandlerCall    = 0;

            var dataSender = new TraceDataSender(new TelemetryConfiguration()
            {
                ApiKey = "123456"
            }, null);

            dataSender.WithDelayFunction(async(uint 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 spans = new List <NewRelicSpan>()
            {
                new NewRelicSpan(
                    traceId: null,
                    spanId: "Test Span",
                    timestamp: 12345,
                    parentSpanId: null,
                    attributes: null),
            };

            var spanBatch = new NewRelicSpanBatch(spans);

            var result = await dataSender.SendDataAsync(spanBatch);

            Assert.Equal(NewRelicResponseStatus.Failure, result.ResponseStatus);
            Assert.Equal("Test Exception", result.Message);
            Assert.Null(result.HttpStatusCode);

            Assert.Equal(expectedNumSendBatchAsyncCall, actualCountCallsSendData);
            Assert.Equal(expectedNumHttpHandlerCall, actualCallsHttpHandler);
        }
コード例 #5
0
        public async Task <IEnumerable <WeatherForecast> > Get()
        {
            // Each span must have a unique identifier.  In this example, we are using a Guid.
            var spanId        = Guid.NewGuid().ToString();
            var spanTimeStamp = DateTimeOffset.UtcNow;
            var spanAttribs   = new Dictionary <string, object>();

            // 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)
            {
                spanAttribs[NewRelicConsts.Tracing.AttribNameErrorMsg] = 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
            {
                spanAttribs[NewRelicConsts.Tracing.AttribNameName]       = "WeatherForecast/Get";
                spanAttribs[NewRelicConsts.Tracing.AttribNameDurationMs] = DateTimeOffset.UtcNow.Subtract(spanTimeStamp).TotalMilliseconds;


                var span = new NewRelicSpan(
                    traceId: Guid.NewGuid().ToString(),
                    spanId: spanId,
                    timestamp: spanTimeStamp.ToUnixTimeMilliseconds(),
                    parentSpanId: null,
                    attributes: spanAttribs);

                // Send it to the New Relic endpoint.
                var newRelicResult = await _spanDataSender.SendDataAsync(new[] { span });

                if (newRelicResult.ResponseStatus == NewRelicResponseStatus.Failure)
                {
                    _logger.LogWarning("There was a problem sending the SpanBatch to New Relic endpoint");
                }
            }
        }
コード例 #6
0
        public async 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(1000).TotalMilliseconds;
            var actualResponseFromTestRun = new List <Response>();

            uint actualDelayFromTestRun = 0;

            var dataSender = new TraceDataSender(new TelemetryConfiguration()
            {
                ApiKey = "123456", MaxRetryAttempts = 1
            }, null);

            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 spans = new List <NewRelicSpan>()
            {
                new NewRelicSpan(
                    traceId: null,
                    spanId: "Test Span",
                    timestamp: 12345,
                    parentSpanId: null,
                    attributes: null),
            };

            var spanBatch = new NewRelicSpanBatch(spans);

            var result = await dataSender.SendDataAsync(spanBatch);

            Assert.True(actualDelayFromTestRun >= delayMs - errorMargin && actualDelayFromTestRun <= delayMs + errorMargin, $"Expected delay: {delayMs}, margin: +/-{errorMargin}, actual delay: {actualDelayFromTestRun}");
        }
コード例 #7
0
        public void SendAnEmptySpanBatch()
        {
            var traceId   = "123";
            var spanBatch = new NewRelicSpanBatch(
                spans: new NewRelicSpan[0],
                commonProperties: new NewRelicSpanBatchCommonProperties(traceId));

            var dataSender = new TraceDataSender(new TelemetryConfiguration()
            {
                ApiKey = "123456"
            }, null);

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

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

            Assert.Equal(NewRelicResponseStatus.DidNotSend_NoData, response.ResponseStatus);
        }
コード例 #8
0
        public async Task RetryOn429WithDuration_429HappensOnce()
        {
            const int delayMS = 10000;
            const int expectedNumSendBatchAsyncCall      = 2;
            var       expectedBackoffSequenceFromTestRun = new List <uint>()
            {
                delayMS,
            };

            var actualBackoffSequenceFromTestRun = new List <uint>();

            var dataSender = new TraceDataSender(new TelemetryConfiguration()
            {
                ApiKey = "123456"
            }, null);

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

            var actualCountCallsSendData = 0;

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

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

                    return(Task.FromResult(httpResponse));
                }

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

            var spans = new List <NewRelicSpan>()
            {
                new NewRelicSpan(
                    traceId: null,
                    spanId: "Test Span",
                    timestamp: 12345,
                    parentSpanId: null,
                    attributes: null),
            };

            var spanBatch = new NewRelicSpanBatch(spans);

            var result = await dataSender.SendDataAsync(spanBatch);

            Assert.Equal(NewRelicResponseStatus.Success, result.ResponseStatus);
            Assert.Equal(expectedNumSendBatchAsyncCall, actualCountCallsSendData);
            Assert.Equal(expectedBackoffSequenceFromTestRun, actualBackoffSequenceFromTestRun);
        }
コード例 #9
0
        public async Task RequestTooLarge_SplitSuccess()
        {
            const int    expectedCountSpans                 = 9;
            const int    expectedCountCallsSendData         = 7;
            const int    expectedCountSuccessfulSpanBatches = 4;
            const string expectedTraceID = "TestTrace";

            var actualCountCallsSendData = 0;

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

            var dataSender = new TraceDataSender(new TelemetryConfiguration()
            {
                ApiKey = "123456"
            }, null);

            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 spans = new List <NewRelicSpan>();

            for (var i = 0; i < expectedCountSpans; i++)
            {
                spans.Add(new NewRelicSpan(null, i.ToString(), i, null, null));
            }

            var spanBatch = new NewRelicSpanBatch(spans, new NewRelicSpanBatchCommonProperties(expectedTraceID, attribs));

            // Act
            await dataSender.SendDataAsync(spanBatch);

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

            // Test the Spans
            Assert.Equal(expectedCountSuccessfulSpanBatches, successfulSpanBatches.Count);
            Assert.Equal(expectedCountSpans, successfulSpanBatches.SelectMany(x => x.Spans).Count());
            Assert.Equal(expectedCountSpans, successfulSpanBatches.SelectMany(x => x.Spans).Select(x => x.Id).Distinct().Count());

            // Test the attributes on the NewRelicSpanBatch
            Assert.Single(successfulSpanBatches.Select(x => x.CommonProperties.TraceId).Distinct());
            Assert.Equal(expectedTraceID, successfulSpanBatches.FirstOrDefault().CommonProperties.TraceId);
            Assert.Single(successfulSpanBatches.Select(x => x.CommonProperties.Attributes).Distinct());
            Assert.Equal(attribs, successfulSpanBatches.Select(x => x.CommonProperties.Attributes).FirstOrDefault());
        }
コード例 #10
0
        public async Task RequestTooLarge_SplitFail()
        {
            const int    expectedCountCallsSendData = 7;
            const string traceID_Success            = "OK";
            const string traceID_SplitBatch_Prefix  = "TooLarge";

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

            var dataSender = new TraceDataSender(new TelemetryConfiguration()
            {
                ApiKey = "123456"
            }, null);

            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((newRelicSpanBatch, retryNum) =>
            {
                actualCountCallsSendData++;

                if (newRelicSpanBatch.Spans == null)
                {
                    return;
                }

                if (newRelicSpanBatch.Spans.Any(x => x.Id.StartsWith(traceID_SplitBatch_Prefix)))
                {
                    shouldSplitJsons.Add(newRelicSpanBatch.ToJson());
                }
                else
                {
                    successfulSpans.AddRange(newRelicSpanBatch.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 spans = new List <NewRelicSpan>();

            spans.Add(new NewRelicSpan(null, $"{traceID_SplitBatch_Prefix}1", 0, null, null));
            spans.Add(new NewRelicSpan(null, $"{traceID_SplitBatch_Prefix}2", 0, null, null));
            spans.Add(new NewRelicSpan(null, $"{traceID_SplitBatch_Prefix}3", 0, null, null));
            spans.Add(new NewRelicSpan(null, traceID_Success, 0, null, null));

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

            // Assert
            Assert.Equal(NewRelicResponseStatus.Failure, result.ResponseStatus);
            Assert.Equal(expectedCountCallsSendData, actualCountCallsSendData);
            Assert.Single(successfulSpans);
            Assert.Equal(traceID_Success, successfulSpans[0].Id);
        }