public void TraceIdIsNotSet()
        {
            var spanBatch = new NewRelicSpanBatch(
                spans: new NewRelicSpan[0]);

            Assert.Null(spanBatch.CommonProperties.TraceId);
        }
Ejemplo n.º 2
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);
        }
Ejemplo n.º 3
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);
        }
        /// <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}");
        }
Ejemplo n.º 5
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);
        }
        public void TraceIdIsSet()
        {
            var traceId = "myId";

            var spanBatch = new NewRelicSpanBatch(
                commonProperties: new NewRelicSpanBatchCommonProperties(traceId: traceId),
                spans: new NewRelicSpan[0]);

            Assert.Equal(traceId, spanBatch.CommonProperties.TraceId);
        }
Ejemplo n.º 7
0
        public void ToJson_NonEmptySpanBatch()
        {
            // Arrange
            var spanBatch = new NewRelicSpanBatch(
                commonProperties: new NewRelicSpanBatchCommonProperties(
                    traceId: "traceId"),
                spans: new NewRelicSpan[]
            {
                new NewRelicSpan(
                    spanId: "span1",
                    traceId: "traceId",
                    timestamp: 1L,
                    parentSpanId: "parentId",
                    attributes: new Dictionary <string, object>()
                {
                    { NewRelicConsts.Tracing.AttribNameDurationMs, 67 },
                    { NewRelicConsts.Tracing.AttribNameServiceName, "serviceName" },
                    { NewRelicConsts.Tracing.AttribNameName, "name" },
                }),
            });

            // 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.First();

            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.AssertForAttribCount(resultSpanAttribs, 4);
        }
        /// <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()
        {
            // The collection of Spans
            var spans = new List <NewRelicSpan>();

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

                // Perform 10 units of work as part of this trace/spanBatch
                for (var spanIdx = 0; spanIdx < 5; spanIdx++)
                {
                    var spanStartTime = DateTime.UtcNow;
                    var spanAttribs   = new Dictionary <string, object>();

                    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.
                        spanAttribs[NewRelicConsts.Tracing.AttribNameErrorMsg] = ex.Message;
                    }
                    finally
                    {
                        spanAttribs[NewRelicConsts.Tracing.AttribNameName]       = $"{traceId} - {spanIdx}";
                        spanAttribs[NewRelicConsts.Tracing.AttribNameDurationMs] = DateTime.UtcNow.Subtract(spanStartTime).TotalMilliseconds;

                        // Create a new Span assigning it a random guid as the spanId
                        var span = new NewRelicSpan(
                            traceId: traceId,         //Since we're mixing traces in the same batch, the trace id is supplied on each span
                            spanId: Guid.NewGuid().ToString(),
                            parentSpanId: null,
                            timestamp: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                            attributes: spanAttribs);

                        spans.Add(span);
                    }
                }
            }

            var spanBatch = new NewRelicSpanBatch(spans);

            // Send the SpanBatch to the New Relic endpoint.
            await SendDataToNewRelic(spanBatch);
        }
Ejemplo n.º 9
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}");
        }
Ejemplo n.º 10
0
        public void ToJson_EmptySpanBatch()
        {
            // Arrange
            var spanBatch = new NewRelicSpanBatch(
                spans: new NewRelicSpan[0],
                commonProperties: new NewRelicSpanBatchCommonProperties(
                    traceId: "traceId"));

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

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

            TestHelpers.AssertForAttribValue(resultCommonProps, "trace.id", "traceId");
        }
Ejemplo n.º 11
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);
        }
Ejemplo n.º 12
0
        public void ToJson_SpanBatchWithMultipleSpans()
        {
            var spanBatch = new NewRelicSpanBatch(
                commonProperties: new NewRelicSpanBatchCommonProperties(
                    traceId: "traceId",
                    attributes: new Dictionary <string, object>()
            {
                { "customAtt1", "hello" },
                { "customAtt2", 1 },
                { "customAtt3", 1.2 },
                { "customAtt4", true },
            }),
                spans: new NewRelicSpan[]
            {
                new NewRelicSpan(
                    spanId: "span1",
                    traceId: "traceId1",
                    timestamp: 1L,
                    parentSpanId: "parentId1",
                    attributes: new Dictionary <string, object>()
                {
                    { NewRelicConsts.Tracing.AttribNameDurationMs, 100 },
                    { NewRelicConsts.Tracing.AttribNameServiceName, "serviceName1" },
                    { NewRelicConsts.Tracing.AttribNameName, "name1" },
                }),
                new NewRelicSpan(
                    spanId: "span2",
                    traceId: "traceId2",
                    timestamp: 2L,
                    parentSpanId: "parentId2",
                    attributes: new Dictionary <string, object>()
                {
                    { NewRelicConsts.Tracing.AttribNameDurationMs, 200 },
                    { NewRelicConsts.Tracing.AttribNameServiceName, "serviceName2" },
                    { NewRelicConsts.Tracing.AttribNameName, "name2" },
                }),
            });

            // 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", 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.AssertForAttribCount(firstSpanAttribs, 4);

            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);
        }
Ejemplo n.º 13
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);
        }
Ejemplo n.º 14
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());
        }