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}"); }
/// <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"); }
public void TraceIdIsSet() { var traceId = "myId"; var spanBatch = SpanBatchBuilder.Create() .WithTraceId(traceId) .Build(); Assert.AreEqual(traceId, spanBatch.CommonProperties.TraceId); }
/// <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)); }
/// <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); }
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."); }