public async Task AddsTraceKeepRateMetricToRootSpan() { // Traces should be dropped when both buffers are full var calculator = new MovingAverageKeepRateCalculator(windowSize: 10, Timeout.InfiniteTimeSpan); var tracer = new Mock <IDatadogTracer>(); tracer.Setup(x => x.DefaultServiceName).Returns("Default"); var traceContext = new TraceContext(tracer.Object); var rootSpanContext = new SpanContext(null, traceContext, null); var rootSpan = new Span(rootSpanContext, DateTimeOffset.UtcNow); var childSpan = new Span(new SpanContext(rootSpanContext, traceContext, null), DateTimeOffset.UtcNow); traceContext.AddSpan(rootSpan); traceContext.AddSpan(childSpan); var trace = new[] { rootSpan, childSpan }; var sizeOfTrace = ComputeSizeOfTrace(trace); // Make the buffer size big enough for a single trace var api = new Mock <IApi>(); api.Setup(x => x.SendTracesAsync(It.IsAny <ArraySegment <byte> >(), It.IsAny <int>())) .ReturnsAsync(() => true); var agent = new AgentWriter(api.Object, statsd: null, calculator, automaticFlush: false, maxBufferSize: (sizeOfTrace * 2) + SpanBuffer.HeaderSize - 1, batchInterval: 100); // Fill both buffers agent.WriteTrace(trace); agent.WriteTrace(trace); // Drop one agent.WriteTrace(trace); await agent.FlushTracesAsync(); // Force a flush to make sure the trace is written to the API // Write another one agent.WriteTrace(trace); await agent.FlushTracesAsync(); // Force a flush to make sure the trace is written to the API api.Verify(); api.Invocations.Clear(); // Write trace and update keep rate calculator.UpdateBucket(); agent.WriteTrace(trace); await agent.FlushTracesAsync(); // Force a flush to make sure the trace is written to the API const double expectedTraceKeepRate = 0.75; rootSpan.SetMetric(Metrics.TracesKeepRate, expectedTraceKeepRate); var expectedData = Vendors.MessagePack.MessagePackSerializer.Serialize(trace, new FormatterResolverWrapper(SpanFormatterResolver.Instance)); await agent.FlushAndCloseAsync(); api.Verify(x => x.SendTracesAsync(It.Is <ArraySegment <byte> >(y => Equals(y, expectedData)), It.Is <int>(i => i == 1)), Times.Once); }
public async Task FlushBothBuffers() { // When the back buffer is full, both buffers should be flushed var api = new Mock <IApi>(); var sizeOfTrace = ComputeSizeOfTrace(CreateTrace(1)); // Make the buffer size big enough for a single trace var agent = new AgentWriter(api.Object, statsd: null, automaticFlush: false, maxBufferSize: (sizeOfTrace * 2) + SpanBuffer.HeaderSize - 1); agent.WriteTrace(CreateTrace(1)); agent.WriteTrace(CreateTrace(1)); Assert.True(agent.ActiveBuffer == agent.BackBuffer); Assert.True(agent.FrontBuffer.IsFull); Assert.Equal(1, agent.FrontBuffer.TraceCount); Assert.False(agent.BackBuffer.IsFull); Assert.Equal(1, agent.BackBuffer.TraceCount); await agent.FlushTracesAsync(); Assert.True(agent.FrontBuffer.IsEmpty); Assert.True(agent.BackBuffer.IsEmpty); api.Verify(a => a.SendTracesAsync(It.IsAny <ArraySegment <byte> >(), 1), Times.Exactly(2)); }
public async Task WriteTrace_2Traces_SendToApi() { // TODO:bertrand it is too complicated to setup such a simple test var trace = new[] { new Span(_spanContext, start: null) }; _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 <Span[][]>(y => y.Single().Equals(trace))), Times.Once); trace = new[] { new Span(_spanContext, start: null) }; _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 <Span[][]>(y => y.Single().Equals(trace))), Times.Once); }
public void AgentWriterEnqueueFlushTasks() { var api = new Mock <IApi>(); var agentWriter = new AgentWriter(api.Object, statsd: null, automaticFlush: false); var flushTcs = new TaskCompletionSource <bool>(); int invocation = 0; api.Setup(i => i.SendTracesAsync(It.IsAny <ArraySegment <byte> >(), It.IsAny <int>())) .Returns(() => { // One for the front buffer, one for the back buffer if (Interlocked.Increment(ref invocation) <= 2) { return(flushTcs.Task); } return(Task.FromResult(true)); }); var trace = new ArraySegment <Span>(new[] { new Span(new SpanContext(1, 1), DateTimeOffset.UtcNow) }); // Write trace to the front buffer agentWriter.WriteTrace(trace); // Flush front buffer var firstFlush = agentWriter.FlushTracesAsync(); // This will swap to the back buffer due front buffer is blocked. agentWriter.WriteTrace(trace); // Flush the second buffer var secondFlush = agentWriter.FlushTracesAsync(); // This trace will force other buffer swap and then a drop because both buffers are blocked agentWriter.WriteTrace(trace); // This will try to flush the front buffer again. var thirdFlush = agentWriter.FlushTracesAsync(); // Third flush should wait for the first flush to complete. Assert.False(thirdFlush.IsCompleted); }
public async Task WriteTrace_2Traces_SendToApi() { var trace = new[] { new Span(new SpanContext(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(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 Task FlushTracesAsync() { return(_agentWriter.FlushTracesAsync()); }