public void SerializeSpans(int traceCount, int spanCount, bool resizeExpected) { var buffer = new Ci.Agent.Payloads.EventsBuffer <Ci.IEvent>(10 * 1024 * 1024, Ci.Agent.MessagePack.CIFormatterResolver.Instance); var events = new List <Ci.IEvent>(); for (int i = 0; i < traceCount; i++) { for (int j = 0; j < spanCount; j++) { events.Add(new SpanEvent(new Span(new SpanContext(TraceId.CreateFromInt(i), (ulong)i), DateTimeOffset.UtcNow))); } } foreach (var @event in events) { Assert.True(buffer.TryWrite(@event)); } buffer.Lock(); Assert.Equal(traceCount * spanCount, buffer.Count); var content = buffer.Data; var resized = content.Count > Ci.Agent.Payloads.EventsBuffer <Ci.IEvent> .InitialBufferSize; // We want to test the case where the buffer is big enough from the start, and the case where it has to be resized // Make sure that the span/trace count assumptions are correct to test the scenario Assert.True(resizeExpected == resized, $"Total serialized size was {content.Count}"); }
static AgentWriterBenchmark() { var settings = TracerSettings.FromDefaultSources(); settings.StartupDiagnosticLogEnabled = false; settings.TraceEnabled = false; var api = new Api(settings.AgentUri, new FakeApiRequestFactory(), statsd: null); AgentWriter = new AgentWriter(api, new NullMetrics(), automaticFlush: false); Spans = new Span[SpanCount]; EnrichedSpans = new Span[SpanCount]; var now = DateTimeOffset.UtcNow; for (int i = 0; i < SpanCount; i++) { Spans[i] = new Span(new SpanContext(TraceId.CreateFromInt(i), (ulong)i, SamplingPriority.UserReject, "Benchmark", null), now); EnrichedSpans[i] = new Span(new SpanContext(TraceId.CreateFromInt(i), (ulong)i, SamplingPriority.UserReject, "Benchmark", null), now); EnrichedSpans[i].SetTag(Tags.Env, "Benchmark"); EnrichedSpans[i].SetMetric(Metrics.SamplingRuleDecision, 1.0); } // Run benchmarks once to reduce noise new AgentWriterBenchmark().WriteAndFlushTraces().GetAwaiter().GetResult(); new AgentWriterBenchmark().WriteAndFlushEnrichedTraces().GetAwaiter().GetResult(); }
public void ClearingBuffer() { var buffer = new SpanBuffer(10 * 1024 * 1024, SpanFormatterResolver.Instance); var trace = new[] { new Span(new SpanContext(TraceId.CreateFromInt(1), 1), DateTimeOffset.UtcNow), new Span(new SpanContext(TraceId.CreateFromInt(2), 2), DateTimeOffset.UtcNow), new Span(new SpanContext(TraceId.CreateFromInt(3), 3), DateTimeOffset.UtcNow), }; Assert.True(buffer.TryWrite(trace, ref _temporaryBuffer)); Assert.Equal(1, buffer.TraceCount); Assert.Equal(3, buffer.SpanCount); buffer.Clear(); Assert.Equal(0, buffer.TraceCount); Assert.Equal(0, buffer.SpanCount); buffer.Lock(); var innerBuffer = buffer.Data; Assert.Equal(SpanBuffer.HeaderSize, innerBuffer.Count); }
public void Extract_UnknownFormat_Throws() { const ulong parentId = 10; var traceId = TraceId.CreateFromInt(42); var headers = new MockTextMap(); headers.Set(DDHttpHeaderNames.ParentId, parentId.ToString()); headers.Set(DDHttpHeaderNames.TraceId, traceId.ToString()); var mockFormat = new Mock <IFormat <ITextMap> >(); Assert.Throws <NotSupportedException>(() => _tracer.Extract(mockFormat.Object, headers)); }
public void Extract_TextMapFormat_HeadersProperlySet_SpanContext() { const ulong parentId = 10; var traceId = TraceId.CreateFromInt(42); var headers = new MockTextMap(); headers.Set(DDHttpHeaderNames.ParentId, parentId.ToString()); headers.Set(DDHttpHeaderNames.TraceId, traceId.ToString()); var otSpanContext = (OpenTracingSpanContext)_tracer.Extract(BuiltinFormats.TextMap, headers); Assert.Equal(parentId, otSpanContext.Context.SpanId); Assert.Equal(traceId, otSpanContext.Context.TraceId); }
public void KeyParsing(string key, string expectedService, string expectedEnv, float expectedRate) { var rule = new DefaultSamplingRule(); rule.SetDefaultSampleRates(new[] { new KeyValuePair <string, float>(key, .5f) }); var span = new Span(new SpanContext(TraceId.CreateFromInt(1), 1, null, serviceName: expectedService), DateTimeOffset.Now); span.SetTag(Tags.Env, expectedEnv); var samplingRate = rule.GetSamplingRate(span); Assert.Equal(expectedRate, samplingRate); }
public void Extract_ValidParentAndTraceId_ProperSpanContext() { var traceId = TraceId.CreateFromInt(10); const ulong parentId = 120; var headers = new MockTextMap(); headers.Set(HttpHeaderTraceId, traceId.ToString()); headers.Set(HttpHeaderParentId, parentId.ToString()); var spanContext = _codec.Extract(headers) as OpenTracingSpanContext; Assert.NotNull(spanContext); Assert.Equal(traceId, spanContext.Context.TraceId); Assert.Equal(parentId, spanContext.Context.SpanId); }
public void Inject_SpanContext_HeadersWithCorrectInfo() { const ulong spanId = 10; var traceId = TraceId.CreateFromInt(7); const SamplingPriority samplingPriority = SamplingPriority.UserKeep; var ddSpanContext = new SpanContext(traceId, spanId, samplingPriority); var spanContext = new OpenTracingSpanContext(ddSpanContext); var headers = new MockTextMap(); _codec.Inject(spanContext, headers); Assert.Equal(spanId.ToString(), headers.Get(HttpHeaderParentId)); Assert.Equal(traceId.ToString(), headers.Get(HttpHeaderTraceId)); Assert.Equal(((int)samplingPriority).ToString(), headers.Get(HttpHeaderSamplingPriority)); }
public void LockingBuffer() { var buffer = new SpanBuffer(10 * 1024 * 1024, SpanFormatterResolver.Instance); var trace = new[] { new Span(new SpanContext(TraceId.CreateFromInt(1), 1), DateTimeOffset.UtcNow) }; Assert.True(buffer.TryWrite(trace, ref _temporaryBuffer)); buffer.Lock(); Assert.False(buffer.TryWrite(trace, ref _temporaryBuffer)); buffer.Clear(); Assert.True(buffer.TryWrite(trace, ref _temporaryBuffer)); }
public void StartActive_SetParentManuallyFromExternalContext_ParentIsSet() { var traceId = TraceId.CreateFromInt(11); const ulong parentId = 7; const SamplingPriority samplingPriority = SamplingPriority.UserKeep; var parent = new SpanContext(traceId, parentId, samplingPriority); var child = _tracer.StartActive("Child", parent); Assert.True(child.Span.IsRootSpan); Assert.Equal(traceId, parent.TraceId); Assert.Equal(parentId, parent.SpanId); Assert.Null(parent.TraceContext); Assert.Equal(parent, child.Span.Context.Parent); Assert.Equal(parentId, child.Span.Context.ParentId); Assert.NotNull(child.Span.Context.TraceContext); Assert.Equal(samplingPriority, child.Span.Context.TraceContext.SamplingPriority); }
public void Extract_WrongHeaderCase_ExtractionStillWorks() { var traceId = TraceId.CreateFromInt(10); const ulong parentId = 120; const SamplingPriority samplingPriority = SamplingPriority.UserKeep; var headers = new MockTextMap(); headers.Set(HttpHeaderTraceId.ToUpper(), traceId.ToString()); headers.Set(HttpHeaderParentId.ToUpper(), parentId.ToString()); headers.Set(HttpHeaderSamplingPriority.ToUpper(), ((int)samplingPriority).ToString()); var spanContext = _codec.Extract(headers) as OpenTracingSpanContext; Assert.NotNull(spanContext); Assert.Equal(traceId, spanContext.Context.TraceId); Assert.Equal(parentId, spanContext.Context.SpanId); }
internal void InjectExtract_Identity(IHeadersCollection headers) { var traceId = TraceId.CreateFromInt(9); const int spanId = 7; const SamplingPriority samplingPriority = SamplingPriority.UserKeep; const string origin = "synthetics"; var context = new SpanContext(traceId, spanId, samplingPriority, null, origin); _propagator.Inject(context, headers); var resultContext = _propagator.Extract(headers); Assert.NotNull(resultContext); Assert.Equal(context.SpanId, resultContext.SpanId); Assert.Equal(context.TraceId, resultContext.TraceId); Assert.Equal(context.SamplingPriority, resultContext.SamplingPriority); Assert.Equal(context.Origin, resultContext.Origin); }
public void WebRequest_InjectExtract_Identity() { var propagator = new B3SpanContextPropagator(); var traceId = TraceId.CreateFromInt(9); const int spanId = 7; const SamplingPriority samplingPriority = SamplingPriority.UserKeep; IHeadersCollection headers = WebRequest.CreateHttp("http://localhost").Headers.Wrap(); var context = new SpanContext(traceId, spanId, samplingPriority); propagator.Inject(context, headers); var resultContext = propagator.Extract(headers); Assert.NotNull(resultContext); Assert.Equal(context.SpanId, resultContext.SpanId); Assert.Equal(context.TraceId, resultContext.TraceId); Assert.Equal(context.SamplingPriority, resultContext.SamplingPriority); }
public void Extract_InvalidSamplingPriority(string samplingPriority) { var propagator = new B3SpanContextPropagator(); var traceId = TraceId.CreateFromInt(9); const ulong spanId = 7; var headers = InjectContext( traceId.ToString(), spanId.ToString("x16", CultureInfo.InvariantCulture), samplingPriority); var resultContext = propagator.Extract(headers); Assert.NotNull(resultContext); Assert.Equal(traceId, resultContext.TraceId); Assert.Equal(spanId, resultContext.SpanId); Assert.Null(resultContext.SamplingPriority); }
public void Extract_InvalidSpanId(string spanId) { var propagator = new B3SpanContextPropagator(); var traceId = TraceId.CreateFromInt(9); const SamplingPriority samplingPriority = SamplingPriority.UserKeep; var headers = InjectContext( traceId.ToString(), spanId, ((int)samplingPriority).ToString(CultureInfo.InvariantCulture)); var resultContext = propagator.Extract(headers); Assert.NotNull(resultContext); Assert.Equal(traceId, resultContext.TraceId); Assert.Equal(default(ulong), resultContext.SpanId); Assert.Equal(samplingPriority, resultContext.SamplingPriority); }
public void SerializeSpans(int traceCount, int spanCount, bool resizeExpected) { var buffer = new SpanBuffer(10 * 1024 * 1024, SpanFormatterResolver.Instance); var traces = new List <Span[]>(); for (int i = 0; i < traceCount; i++) { var spans = new Span[spanCount]; for (int j = 0; j < spanCount; j++) { spans[j] = new Span(new SpanContext(TraceId.CreateFromInt(i), (ulong)i), DateTimeOffset.UtcNow); } traces.Add(spans); } foreach (var trace in traces) { Assert.True(buffer.TryWrite(trace, ref _temporaryBuffer)); } buffer.Lock(); Assert.Equal(traceCount, buffer.TraceCount); Assert.Equal(traceCount * spanCount, buffer.SpanCount); var content = buffer.Data; var result = MessagePack.MessagePackSerializer.Deserialize <FakeSpan[][]>(content); var resized = content.Count > SpanBuffer.InitialBufferSize; // We want to test the case where the buffer is big enough from the start, and the case where it has to be resized // Make sure that the span/trace count assumptions are correct to test the scenario Assert.True(resizeExpected == resized, $"Total serialized size was {content.Count}"); Assert.Equal(traceCount, result.Length); Assert.Equal(traceCount * spanCount, result.Sum(t => t.Length)); }
public void OriginHeader_RootSpanTag() { var traceId = TraceId.CreateFromInt(9); const ulong spanId = 7; const SamplingPriority samplingPriority = SamplingPriority.UserKeep; const string origin = "synthetics"; var propagatedContext = new SpanContext(traceId, spanId, samplingPriority, null, origin); Assert.Equal(origin, propagatedContext.Origin); using var firstSpan = _tracer.StartActive("First Span", propagatedContext); Assert.True(firstSpan.Span.IsRootSpan); Assert.Equal(origin, firstSpan.Span.Context.Origin); Assert.Equal(origin, firstSpan.Span.GetTag(Tags.Origin)); using var secondSpan = _tracer.StartActive("Child", firstSpan.Span.Context); Assert.False(secondSpan.Span.IsRootSpan); Assert.Equal(origin, secondSpan.Span.Context.Origin); Assert.Null(secondSpan.Span.GetTag(Tags.Origin)); }
internal void Extract_InvalidSamplingPriority(IHeadersCollection headers, string samplingPriority) { var traceId = TraceId.CreateFromInt(9); const ulong spanId = 7; const string origin = "synthetics"; InjectContext( headers, traceId.ToString(), spanId.ToString(CultureInfo.InvariantCulture), samplingPriority, origin); var resultContext = _propagator.Extract(headers); Assert.NotNull(resultContext); Assert.Equal(traceId, resultContext.TraceId); Assert.Equal(spanId, resultContext.SpanId); Assert.Null(resultContext.SamplingPriority); Assert.Equal(origin, resultContext.Origin); }
public async Task WriteTrace_2Traces_SendToApi() { var trace = new[] { new Span(new SpanContext(TraceId.CreateFromInt(1), 1), DateTimeOffset.UtcNow) }; var expectedData1 = Vendors.MessagePack.MessagePackSerializer.Serialize(trace, new FormatterResolverWrapper(SpanFormatterResolver.Instance)); _agentWriter.WriteTrace(trace); await _agentWriter.FlushTracesAsync(); // Force a flush to make sure the trace is written to the API _api.Verify(x => x.SendTracesAsync(It.Is <ArraySegment <byte> >(y => Equals(y, expectedData1)), It.Is <int>(i => i == 1)), Times.Once); _api.Invocations.Clear(); trace = new[] { new Span(new SpanContext(TraceId.CreateFromInt(2), 2), DateTimeOffset.UtcNow) }; var expectedData2 = Vendors.MessagePack.MessagePackSerializer.Serialize(trace, new FormatterResolverWrapper(SpanFormatterResolver.Instance)); _agentWriter.WriteTrace(trace); await _agentWriter.FlushTracesAsync(); // Force a flush to make sure the trace is written to the API _api.Verify(x => x.SendTracesAsync(It.Is <ArraySegment <byte> >(y => Equals(y, expectedData2)), It.Is <int>(i => i == 1)), Times.Once); await _agentWriter.FlushAndCloseAsync(); }
public void OriginHeader_InjectFromChildSpan() { var traceId = TraceId.CreateFromInt(9); const ulong spanId = 7; const SamplingPriority samplingPriority = SamplingPriority.UserKeep; const string origin = "synthetics"; var propagatedContext = new SpanContext(traceId, spanId, samplingPriority, null, origin); var propagator = new DDSpanContextPropagator(new DatadogTraceIdConvention()); using var firstSpan = _tracer.StartActive("First Span", propagatedContext); using var secondSpan = _tracer.StartActive("Child", firstSpan.Span.Context); IHeadersCollection headers = WebRequest.CreateHttp("http://localhost").Headers.Wrap(); propagator.Inject(secondSpan.Span.Context, headers); var resultContext = propagator.Extract(headers); Assert.NotNull(resultContext); Assert.Equal(firstSpan.Span.Context.Origin, resultContext.Origin); Assert.Equal(secondSpan.Span.Context.Origin, resultContext.Origin); Assert.Equal(origin, resultContext.Origin); }
public void Overflow() { var buffer = new SpanBuffer(10, SpanFormatterResolver.Instance); Assert.False(buffer.IsFull); var trace = new[] { new Span(new SpanContext(TraceId.CreateFromInt(1), 1), DateTimeOffset.UtcNow) }; var result = buffer.TryWrite(trace, ref _temporaryBuffer); Assert.False(result); Assert.Equal(0, buffer.TraceCount); Assert.True(buffer.IsFull); buffer.Lock(); var innerBuffer = buffer.Data; Assert.True(innerBuffer.Array.Skip(SpanBuffer.HeaderSize).All(b => b == 0x0), "No data should have been written to the buffer"); buffer.Clear(); Assert.False(buffer.IsFull); }
private static RateLimitResult RunTest(int?intervalLimit, RateLimitLoadTest test) { var parallelism = test.NumberPerBurst; if (parallelism > Environment.ProcessorCount) { parallelism = Environment.ProcessorCount; } var clock = new SimpleClock(); var limiter = new RateLimiter(maxTracesPerInterval: intervalLimit); var barrier = new Barrier(parallelism + 1, _ => clock.UtcNow += test.TimeBetweenBursts); var numberPerThread = test.NumberPerBurst / parallelism; var workers = new Task[parallelism]; int totalAttempted = 0; int totalAllowed = 0; for (int i = 0; i < workers.Length; i++) { workers[i] = Task.Factory.StartNew( () => { using var lease = Clock.SetForCurrentThread(clock); for (var i = 0; i < test.NumberOfBursts; i++) { // Wait for every worker to be ready for next burst barrier.SignalAndWait(); for (int j = 0; j < numberPerThread; j++) { // trace id and span id are not used in rate-limiting var spanContext = new SpanContext(TraceId.CreateFromInt(1), spanId: 1, serviceName: "Weeeee"); // pass a specific start time since there is no TraceContext var span = new Span(spanContext, DateTimeOffset.UtcNow); Interlocked.Increment(ref totalAttempted); if (limiter.Allowed(span)) { Interlocked.Increment(ref totalAllowed); } } } }, TaskCreationOptions.LongRunning); } // Wait for all workers to be ready barrier.SignalAndWait(); // We do not need to synchronize with workers anymore barrier.RemoveParticipant(); // Wait for workers to finish Task.WaitAll(workers); var result = new RateLimitResult { RateLimiter = limiter, ReportedRate = limiter.GetEffectiveRate(), TotalAttempted = totalAttempted, TotalAllowed = totalAllowed }; return(result); }
private static Span[] CreateTrace(int numberOfSpans) { return(Enumerable.Range(0, numberOfSpans) .Select(i => new Span(new SpanContext(TraceId.CreateFromInt(i + 1), (ulong)i + 1), DateTimeOffset.UtcNow)) .ToArray()); }
public void FlushPartialTraces(bool partialFlush) { var tracer = new Mock <IDatadogTracer>(); tracer.Setup(t => t.Settings).Returns(new Trace.Configuration.TracerSettings { PartialFlushEnabled = partialFlush, PartialFlushMinSpans = 5 }); var traceContext = new TraceContext(tracer.Object); void AddAndCloseSpan() { var span = new Span(new SpanContext(TraceId.CreateFromInt(42), SpanIdGenerator.ThreadInstance.CreateNew()), DateTimeOffset.UtcNow); traceContext.AddSpan(span); traceContext.CloseSpan(span); } var rootSpan = new Span(new SpanContext(TraceId.CreateFromInt(42), SpanIdGenerator.ThreadInstance.CreateNew()), DateTimeOffset.UtcNow); traceContext.AddSpan(rootSpan); for (int i = 0; i < 4; i++) { AddAndCloseSpan(); } // At this point in time, we have 4 closed spans in the trace tracer.Verify(t => t.Write(It.IsAny <Span[]>()), Times.Never); AddAndCloseSpan(); // Now we have 5 closed spans, partial flush should kick-in if activated if (partialFlush) { tracer.Verify(t => t.Write(It.Is <Span[]>(s => s.Length == 5)), Times.Once); } else { tracer.Verify(t => t.Write(It.IsAny <Span[]>()), Times.Never); } for (int i = 0; i < 5; i++) { AddAndCloseSpan(); } // We have 5 more closed spans, partial flush should kick-in a second time if activated if (partialFlush) { tracer.Verify(t => t.Write(It.Is <Span[]>(s => s.Length == 5)), Times.Exactly(2)); } else { tracer.Verify(t => t.Write(It.IsAny <Span[]>()), Times.Never); } traceContext.CloseSpan(rootSpan); // Now the remaining spans are flushed if (partialFlush) { tracer.Verify(t => t.Write(It.Is <Span[]>(s => s.Length == 1)), Times.Once); } else { tracer.Verify(t => t.Write(It.Is <Span[]>(s => s.Length == 11)), Times.Once); } }
public void CreateFromInt_CreatesIdCorrectly() { var traceId = TraceId.CreateFromInt(123); traceId.ToString().Should().Be("123"); }
public void Serialization(bool topLevelSpan) { var tags = new CommonTags(); Span span; if (topLevelSpan) { span = new Span(new SpanContext(TraceId.CreateFromInt(42), 41), DateTimeOffset.UtcNow, tags); } else { // Assign a parent to prevent the span from being considered as top-level var traceContext = new TraceContext(Mock.Of <IDatadogTracer>()); var parent = new SpanContext(TraceId.CreateFromInt(42), 41); span = new Span(new SpanContext(parent, traceContext, null), DateTimeOffset.UtcNow, tags); } // The span has 1 "common" tag and 15 additional tags (and same number of metrics) // Those numbers are picked to test the variable-size header of MessagePack // The header is resized when there are 16 or more elements in the collection // Neither common or additional tags have enough elements, but put together they will cause to use a bigger header tags.Environment = "Test"; tags.SamplingLimitDecision = 0.5; for (int i = 0; i < 15; i++) { span.SetTag(i.ToString(), i.ToString()); } for (int i = 0; i < 15; i++) { span.SetMetric(i.ToString(), i); } var buffer = new byte[0]; var resolver = new FormatterResolverWrapper(SpanFormatterResolver.Instance); MessagePackSerializer.Serialize(ref buffer, 0, span, resolver); var deserializedSpan = MessagePack.MessagePackSerializer.Deserialize <FakeSpan>(buffer); Assert.Equal(16, deserializedSpan.Tags.Count); // For top-level spans, there is one metric added during serialization Assert.Equal(topLevelSpan ? 17 : 16, deserializedSpan.Metrics.Count); Assert.Equal("Test", deserializedSpan.Tags[Tags.Env]); Assert.Equal(0.5, deserializedSpan.Metrics[Metrics.SamplingLimitDecision]); for (int i = 0; i < 15; i++) { Assert.Equal(i.ToString(), deserializedSpan.Tags[i.ToString()]); Assert.Equal((double)i, deserializedSpan.Metrics[i.ToString()]); } if (topLevelSpan) { Assert.Equal(1.0, deserializedSpan.Metrics[Metrics.TopLevelSpan]); } }