public void StartChildSpan_SampledLinkedParent()
        {
            var rootSpanUnsampled =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions)
                .SetSampler(Samplers.NeverSample)
                .StartSpan();

            Assert.False(rootSpanUnsampled.Context.TraceOptions.IsSampled);
            var rootSpanSampled =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions)
                .SetSampler(Samplers.AlwaysSample)
                .StartSpan();

            Assert.True(rootSpanSampled.Context.TraceOptions.IsSampled);
            // Sampled because the linked parent is sampled.
            ISpan childSpan =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, rootSpanUnsampled, spanBuilderOptions)
                .SetParentLinks(new List <ISpan>()
            {
                rootSpanSampled
            })
                .StartSpan();

            Assert.True(childSpan.Context.IsValid);
            Assert.Equal(rootSpanUnsampled.Context.TraceId, childSpan.Context.TraceId);
            Assert.True(childSpan.Context.TraceOptions.IsSampled);
        }
        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");
        }
Example #3
0
        public void BuildSpan()
        {
            var attributes = new Dictionary <string, object>
            {
                { "attrKey", "attrValue" }
            };

            var spanBuilder = SpanBuilder.Create("spanId")
                              .WithTraceId("traceId")
                              .WithTimestamp(1L)
                              .WithServiceName("serviceName")
                              .WithDurationMs(67)
                              .WithName("name")
                              .WithParentId("parentId")
                              .HasError(true)
                              .WithAttribute("adsfasdf", 12)
                              .WithAttributes(attributes);

            var span = spanBuilder.Build();

            Assert.AreEqual("spanId", span.Id);
            Assert.AreEqual("traceId", span.TraceId);
            Assert.AreEqual(1L, span.Timestamp);
            Assert.AreEqual("serviceName", span.Attributes["service.name"]);
            Assert.AreEqual(true, span.Attributes["error"]);
            Assert.AreEqual(67, span.Attributes["duration.ms"]);
            Assert.AreEqual("name", span.Attributes["name"]);
            Assert.AreEqual("parentId", span.Attributes["parent.id"]);
            Assert.AreEqual("attrValue", span.Attributes["attrKey"]);
        }
        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}");
        }
Example #5
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);
        }
        public void StartRootSpan_WithoutSpecifiedSampler()
        {
            // Apply default sampler (always true in the tests) for root spans.
            var rootSpan =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions).StartSpan();

            Assert.True(rootSpan.Context.IsValid);
            Assert.True(rootSpan.Context.TraceOptions.IsSampled);
        }
        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");
        }
Example #8
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);
        }
        public void StartSpanNullParentNoRecordOptions()
        {
            var span =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions)
                .SetSampler(Samplers.NeverSample)
                .StartSpan();

            Assert.True(span.Context.IsValid);
            Assert.False(span.IsRecordingEvents);
            Assert.False(span.Context.TraceOptions.IsSampled);
        }
        public void StartRootSpan_WithSpecifiedSampler()
        {
            // Apply given sampler before default sampler for root spans.
            var rootSpan =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions)
                .SetSampler(Samplers.NeverSample)
                .StartSpan();

            Assert.True(rootSpan.Context.IsValid);
            Assert.False(rootSpan.Context.TraceOptions.IsSampled);
        }
        public void StartSpan_NullParent()
        {
            var span =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (SpanContext)null, spanBuilderOptions).StartSpan();

            Assert.True(span.Context.IsValid);
            Assert.True(span.IsRecordingEvents);
            Assert.True(span.Context.TraceOptions.IsSampled);
            ISpanData spanData = ((Span)span).ToSpanData();

            Assert.Null(spanData.ParentSpanId);
        }
        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);
        }
Example #13
0
        public void SimpleStrongAndItalicSpan()
        {
            Span builded = SpanBuilder
                           .Create()
                           .Write("Lorem ")
                           .Strong("ipsum")
                           .Write(" ")
                           .Italic("dolor")
                           .Write(" sit amet.")
                           .Span;

            Assert.Equal("Lorem **ipsum** *dolor* sit amet.", builded.ToString());
        }
Example #14
0
 /// <example>
 /// SpanBuilder
 ///     .Create()
 ///     .Write("Lorem ipsum ")
 ///     .StartStrongContext()
 ///     .Write("dolor sit amet, ")
 ///     .Strikethrough("consectetur")
 ///     .Write(" adipiscing ")
 ///     .Italic("elit")
 ///     .EndContext()
 ///     .Write(".");
 /// </example>
 public static ISpanBuilder FluentWay()
 {
     return(SpanBuilder
            .Create()
            .Write("Lorem ipsum ")
            .StartStrongContext()
            .Write("dolor sit amet, ")
            .Strikethrough("consectetur")
            .Write(" adipiscing ")
            .Italic("elit")
            .EndContext()
            .Write("."));
 }
        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 StartSpanNullParent()
        {
            var span =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions).StartSpan();

            Assert.True(span.Context.IsValid);
            Assert.True(span.IsRecordingEvents);
            Assert.True(span.Context.TraceOptions.IsSampled);
            ISpanData spanData = ((Span)span).ToSpanData();

            Assert.Null(spanData.ParentSpanId);
            Assert.InRange(spanData.StartTimestamp, Timestamp.FromDateTimeOffset(DateTimeOffset.Now).AddDuration(Duration.Create(-1, 0)), Timestamp.FromDateTimeOffset(DateTimeOffset.Now).AddDuration(Duration.Create(1, 0)));
            Assert.Equal(SPAN_NAME, spanData.Name);
        }
        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 StartSpanNullParentWithRecordEvents()
        {
            var span =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions)
                .SetSampler(Samplers.NeverSample)
                .SetRecordEvents(true)
                .StartSpan();

            Assert.True(span.Context.IsValid);
            Assert.True(span.IsRecordingEvents);
            Assert.False(span.Context.TraceOptions.IsSampled);
            ISpanData spanData = ((Span)span).ToSpanData();

            Assert.Null(spanData.ParentSpanId);
        }
        public void StartChildSpan()
        {
            var rootSpan =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions).StartSpan();

            Assert.True(rootSpan.Context.IsValid);
            Assert.True(rootSpan.IsRecordingEvents);
            Assert.True(rootSpan.Context.TraceOptions.IsSampled);
            ISpan childSpan =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, rootSpan, spanBuilderOptions).StartSpan();

            Assert.True(childSpan.Context.IsValid);
            Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId);
            Assert.Equal(rootSpan.Context.SpanId, ((Span)childSpan).ToSpanData().ParentSpanId);
            Assert.Equal(((Span)rootSpan).TimestampConverter, ((Span)childSpan).TimestampConverter);
        }
        public void StartChildSpan_WithoutSpecifiedSampler()
        {
            var rootSpan =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions)
                .SetSampler(Samplers.NeverSample)
                .StartSpan();

            Assert.True(rootSpan.Context.IsValid);
            Assert.False(rootSpan.Context.TraceOptions.IsSampled);
            // Don't apply the default sampler (always true) for child spans.
            ISpan childSpan =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, rootSpan, spanBuilderOptions).StartSpan();

            Assert.True(childSpan.Context.IsValid);
            Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId);
            Assert.False(childSpan.Context.TraceOptions.IsSampled);
        }
        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 StartRemoteChildSpan_WithoutSpecifiedSampler()
        {
            var rootSpan =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, (ISpan)null, spanBuilderOptions)
                .SetSampler(Samplers.NeverSample)
                .StartSpan();

            Assert.True(rootSpan.Context.IsValid);
            Assert.False(rootSpan.Context.TraceOptions.IsSampled);
            // Apply default sampler (always true in the tests) for spans with remote parent.
            ISpan childSpan =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, rootSpan.Context, spanBuilderOptions)
                .StartSpan();

            Assert.True(childSpan.Context.IsValid);
            Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId);
            Assert.False(childSpan.Context.TraceOptions.IsSampled);
        }
        public void StartRemoteSpan()
        {
            SpanContext spanContext =
                SpanContext.Create(
                    TraceId.GenerateRandomId(randomHandler),
                    SpanId.GenerateRandomId(randomHandler),
                    TraceOptions.Default, Tracestate.Empty);
            ISpan span =
                SpanBuilder.Create(SPAN_NAME, SpanKind.Internal, spanContext, spanBuilderOptions)
                .SetRecordEvents(true)
                .StartSpan();

            Assert.True(span.Context.IsValid);
            Assert.Equal(spanContext.TraceId, span.Context.TraceId);
            Assert.False(span.Context.TraceOptions.IsSampled);
            ISpanData spanData = ((Span)span).ToSpanData();

            Assert.Equal(spanContext.SpanId, spanData.ParentSpanId);
        }
Example #24
0
        private static IBlock BuildParameterInfo(Parameter parameter)
        {
            Section result = new Section(
                new Header(parameter.Documentation.Title ?? parameter.Key));

            if (!string.IsNullOrEmpty(parameter.ArgumentTemplate))
            {
                result = result.AddChild(new Paragraph(
                                             SpanBuilder.Create()
                                             .Write("Regular expression: ")
                                             .Italic($"/{parameter.ArgumentTemplate}/")));
            }

            if (!string.IsNullOrEmpty(parameter.Documentation?.Description))
            {
                result = result.AddChild(new Paragraph(parameter.Documentation.Description));
            }

            return(result);
        }
        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 SendANonEmptySpanBatch()
        {
            var traceId = "123";

            var spanBatch = SpanBatchBuilder.Create()
                            .WithTraceId(traceId)
                            .WithSpan(SpanBuilder.Create("TestSpan").Build())
                            .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.Success, response.ResponseStatus);
        }
Example #27
0
 public void ThrowExceptionIfNullId()
 {
     Assert.Throws <NullReferenceException>(new TestDelegate(() => SpanBuilder.Create(null)));
 }
Example #28
0
        /// <summary>
        /// Wraps a unit of work and records it as a span.  It tracking calculates duration and handles exceptions.
        /// Upon completion, if this the topmost unit of work, the spans will be sent to the New Relic endpoint as
        /// a SpanBatch/Trace.
        /// </summary>
        /// <param name="action">The work to be executed and tracked as a span</param>
        public static void TrackWork(string name, Action action)
        {
            //If Tracing is not enabled, just invoke action and return
            if (!_isTracingEnabled)
            {
                action.Invoke();
                return;
            }

            var parentSpan = _currentSpan.Value;

            var newSpanId = Guid.NewGuid().ToString();

            var thisSpan = SpanBuilder.Create(newSpanId);

            if (!string.IsNullOrWhiteSpace(name))
            {
                thisSpan.WithAttribute("Name", name);
            }

            _currentSpan.Value = thisSpan;

            Console.WriteLine($"{"SIMPLE TRACER: Span Started",-30}: Span={newSpanId}, Parent={(parentSpan == null ? "<TOPMOST ITEM>": parentSpan.SpanId)} - {name??"No Name"}");

            // If this unit of work is part of a larger unit of work,
            // this will associate it as a child span of the larger span.
            if (parentSpan != null)
            {
                thisSpan.WithParentId(parentSpan.SpanId);
            }

            // collect the start timestamp
            var startTime = DateTime.UtcNow;

            try
            {
                action?.Invoke();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"{"SIMPLE TRACER: Error Detected",-30}: Span={newSpanId}, Parent={(parentSpan == null ? "<TOPMOST ITEM>" : parentSpan.SpanId)} - {name ?? "No Name"} - {ex.Message}");

                // In the event an unhandled exception occurs, mark the span as "HasError"
                // and record the exception.
                thisSpan.HasError(true);
                thisSpan.WithAttribute("Exception", ex);

                // Rethrow the exception for the caller so as to not change the execution path of the application.
                throw;
            }
            finally
            {
                // In all cases, record the execution duration
                thisSpan.WithExecutionTimeInfo(startTime, DateTime.UtcNow);

                // Attach the span to the SpanBatch (Trace).
                var spanBatch = _currentSpanBatch.Value.WithSpan(thisSpan.Build());

                Console.WriteLine($"{"SIMPLE TRACER: Span Completed",-30}: Span={newSpanId}, Parent={(parentSpan == null ? "<TOPMOST ITEM>" : parentSpan.SpanId)} - {name ?? "No Name"}");

                // If this is a topmost unit of work, send the trace to the New Relic endpoint.
                if (parentSpan == null)
                {
                    _currentSpan.Value      = null;
                    _currentSpanBatch.Value = null;

                    var sb = spanBatch.Build();

                    Console.WriteLine($"{"SIMPLE TRACER: Trace Completed",-30}: {sb.CommonProperties.TraceId}");

                    SendDataToNewRelic(sb).Wait();
                }
                else
                {
                    _currentSpan.Value = parentSpan;
                }
            }
        }
        public void StartRemoteChildSpan_WithProbabilitySamplerDefaultSampler()
        {
            var configMock = Mock.Get <ITraceConfig>(traceConfig);

            configMock.Setup((c) => c.ActiveTraceParams).Returns(TraceParams.Default);
            // This traceId will not be sampled by the ProbabilitySampler because the first 8 bytes as long
            // is not less than probability * Long.MAX_VALUE;
            ITraceId traceId =
                TraceId.FromBytes(
                    new byte[]
            {
                0x8F,
                0xFF,
                0xFF,
                0xFF,
                0xFF,
                0xFF,
                0xFF,
                0xFF,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
            });

            // If parent is sampled then the remote child must be sampled.
            ISpan childSpan =
                SpanBuilder.Create(
                    SPAN_NAME,
                    SpanKind.Internal,
                    SpanContext.Create(
                        traceId,
                        SpanId.GenerateRandomId(randomHandler),
                        TraceOptions.Builder().SetIsSampled(true).Build(), Tracestate.Empty),
                    spanBuilderOptions)
                .StartSpan();

            Assert.True(childSpan.Context.IsValid);
            Assert.Equal(traceId, childSpan.Context.TraceId);
            Assert.True(childSpan.Context.TraceOptions.IsSampled);
            childSpan.End();

            Assert.Equal(TraceParams.Default, traceConfig.ActiveTraceParams);

            // If parent is not sampled then the remote child must be not sampled.
            childSpan =
                SpanBuilder.Create(
                    SPAN_NAME,
                    SpanKind.Internal,
                    SpanContext.Create(
                        traceId,
                        SpanId.GenerateRandomId(randomHandler),
                        TraceOptions.Default, Tracestate.Empty),
                    spanBuilderOptions)
                .StartSpan();
            Assert.True(childSpan.Context.IsValid);
            Assert.Equal(traceId, childSpan.Context.TraceId);
            Assert.False(childSpan.Context.TraceOptions.IsSampled);
            childSpan.End();
        }
        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");
                }
            }
        }