public async Task ShutdownOnNotEmptyQueueFullFlush() { const int batchSize = 2; int exportCalledCount = 0; var spanExporter = new TestSpanExporter(_ => Interlocked.Increment(ref exportCalledCount)); using var spanProcessor = new BatchingSpanProcessor(spanExporter, 128, TimeSpan.FromMilliseconds(100), batchSize); var spans = new List <SpanSdk>(); for (int i = 0; i < 100; i++) { spans.Add(this.CreateSampledEndedSpan(i.ToString(), spanProcessor)); } Assert.True(spanExporter.ExportedSpans.Length < spans.Count); using (var cts = new CancellationTokenSource(DefaultTimeout)) { await spanProcessor.ShutdownAsync(cts.Token); } Assert.True(spanExporter.WasShutDown); Assert.Equal(spans.Count, spanExporter.ExportedSpans.Length); Assert.InRange(exportCalledCount, spans.Count / batchSize, spans.Count); }
public void ExportMoreSpansThanTheMaxBatchSize() { var exporterCalled = new ManualResetEvent(false); int exportCalledCount = 0; var spanExporter = new TestSpanExporter(_ => { exporterCalled.Set(); Interlocked.Increment(ref exportCalledCount); }); using var spanProcessor = new BatchingSpanProcessor(spanExporter, 128, DefaultDelay, 3); var span1 = this.CreateSampledEndedSpan(SpanName1, spanProcessor); var span2 = this.CreateSampledEndedSpan(SpanName1, spanProcessor); var span3 = this.CreateSampledEndedSpan(SpanName1, spanProcessor); var span4 = this.CreateSampledEndedSpan(SpanName1, spanProcessor); var span5 = this.CreateSampledEndedSpan(SpanName1, spanProcessor); var span6 = this.CreateSampledEndedSpan(SpanName1, spanProcessor); // wait for exporter to be called to stabilize tests on the build server exporterCalled.WaitOne(TimeSpan.FromSeconds(10)); var exported = this.WaitForSpans(spanExporter, 6, DefaultTimeout); Assert.InRange(exportCalledCount, 2, 6); Assert.Equal(6, exported.Count()); Assert.Contains(new SpanData(span1), exported); Assert.Contains(new SpanData(span2), exported); Assert.Contains(new SpanData(span3), exported); Assert.Contains(new SpanData(span4), exported); Assert.Contains(new SpanData(span5), exported); Assert.Contains(new SpanData(span6), exported); }
public void ProcessorDoesNotBlockOnExporter() { var resetEvent = new ManualResetEvent(false); var spanExporter = new TestSpanExporter(_ => resetEvent.WaitOne(TimeSpan.FromSeconds(10))); using var factory = TracerFactory.Create(b => b .AddProcessorPipeline(p => p .SetExporter(spanExporter) .SetExportingProcessor(e => new BatchingSpanProcessor(e, 128, DefaultDelay, 128)))); var tracer = factory.GetTracer(null); var context = new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded); var span = (SpanSdk)tracer.StartSpan("foo", context); // does not block var sw = Stopwatch.StartNew(); span.End(); sw.Stop(); Assert.InRange(sw.Elapsed, TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); resetEvent.Set(); var exported = this.WaitForSpans(spanExporter, 1, DefaultTimeout); Assert.Single(exported); }
public async Task ShutdownOnNotEmptyQueueNotFullFlush() { const int batchSize = 2; int exportCalledCount = 0; // we'll need about 1.5 sec to export all spans // we export 100 spans in batches of 2, each export takes 30ms, in one thread var spanExporter = new TestSpanExporter(_ => { Interlocked.Increment(ref exportCalledCount); Thread.Sleep(30); }); using var spanProcessor = new BatchingSpanProcessor(spanExporter, 128, TimeSpan.FromMilliseconds(100), batchSize); var spans = new List <SpanSdk>(); for (int i = 0; i < 100; i++) { spans.Add(this.CreateSampledEndedSpan(i.ToString(), spanProcessor)); } Assert.True(spanExporter.ExportedSpans.Length < spans.Count); // we won't bs able to export all before cancellation will fire using (var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(200))) { await spanProcessor.ShutdownAsync(cts.Token); } var exportedCount = spanExporter.ExportedSpans.Length; Assert.True(exportedCount < spans.Count); }
public void ExporterIsSlowerThanDelay() { var exportStartTimes = new List <long>(); var exportEndTimes = new List <long>(); var spanExporter = new TestSpanExporter(_ => { exportStartTimes.Add(Stopwatch.GetTimestamp()); Thread.Sleep(50); exportEndTimes.Add(Stopwatch.GetTimestamp()); }); using var spanProcessor = new BatchingSpanProcessor(spanExporter, 128, TimeSpan.FromMilliseconds(30), 2); var spans = new List <SpanSdk>(); for (int i = 0; i < 20; i++) { spans.Add(this.CreateSampledEndedSpan(i.ToString(), spanProcessor)); } var exported = this.WaitForSpans(spanExporter, 20, TimeSpan.FromSeconds(2)); Assert.Equal(spans.Count, exported.Length); Assert.InRange(exportStartTimes.Count, 10, 20); for (int i = 1; i < exportStartTimes.Count - 1; i++) { Assert.InRange(exportStartTimes[i], exportEndTimes[i - 1] + 1, exportStartTimes[i + 1] - 1); } }
public SimpleSpanProcessorTest() { this.spanExporter = new TestSpanExporter(null); this.tracer = TracerFactory.Create(b => b .AddProcessorPipeline(p => p .SetExporter(this.spanExporter) .SetExportingProcessor(e => new SimpleSpanProcessor(e))) .SetSampler(new AlwaysParentSampler())) .GetTracer(null); }
private SpanData[] WaitForSpans(TestSpanExporter exporter, int spanCount, TimeSpan timeout) { Assert.True( SpinWait.SpinUntil( () => { Thread.Sleep(0); return(exporter.ExportedSpans.Length >= spanCount); }, timeout + TimeSpan.FromMilliseconds(20))); return(exporter.ExportedSpans); }
public void TracerBuilder_ValidArgs() { var builder = new TracerBuilder(); bool processorFactoryCalled = false; bool instrumentationFactoryCalled = true; var sampler = new ProbabilitySampler(0.1); var exporter = new TestSpanExporter(_ => { }); var options = new TracerConfiguration(1, 1, 1); builder .SetSampler(sampler) .AddProcessorPipeline(p => p .SetExporter(exporter) .SetExportingProcessor(e => { processorFactoryCalled = true; Assert.Same(e, exporter); return(new SimpleSpanProcessor(e)); })) .SetTracerOptions(options) .AddInstrumentation(t => { Assert.NotNull(t); return(new TestInstrumentation(t)); }); Assert.Same(sampler, builder.Sampler); Assert.NotNull(builder.ProcessingPipelines); Assert.Single(builder.ProcessingPipelines); Assert.Same(exporter, builder.ProcessingPipelines[0].Exporter); Assert.NotNull(builder.ProcessingPipelines[0].Build()); Assert.True(processorFactoryCalled); Assert.Same(options, builder.TracerConfigurationOptions); Assert.Single(builder.InstrumentationFactories); var instrumentationFactory = builder.InstrumentationFactories.Single(); Assert.Equal(nameof(TestInstrumentation), instrumentationFactory.Name); Assert.Equal("semver:" + typeof(TestInstrumentation).Assembly.GetName().Version, instrumentationFactory.Version); Assert.NotNull(instrumentationFactory.Factory); instrumentationFactory.Factory(new TracerSdk(new SimpleSpanProcessor(exporter), new AlwaysOnSampler(), options, Resource.Empty)); Assert.True(instrumentationFactoryCalled); }
public void ExportDifferentSampledSpans() { var spanExporter = new TestSpanExporter(null); using var spanProcessor = new BatchingSpanProcessor(spanExporter, 128, DefaultDelay, 128); var span1 = this.CreateSampledEndedSpan(SpanName1, spanProcessor); var span2 = this.CreateSampledEndedSpan(SpanName2, spanProcessor); var exported = this.WaitForSpans(spanExporter, 2, DefaultTimeout); Assert.Equal(2, exported.Length); Assert.Contains(new SpanData(span1), exported); Assert.Contains(new SpanData(span2), exported); }
private SpanData[] WaitForSpans(TestSpanExporter exporter, int spanCount, TimeSpan timeout) { var sw = Stopwatch.StartNew(); while (exporter.ExportedSpans.Length < spanCount && sw.Elapsed <= timeout) { Thread.Sleep(10); } Assert.True( exporter.ExportedSpans.Length >= spanCount, $"Expected at least {spanCount}, got {exporter.ExportedSpans.Length}"); return(exporter.ExportedSpans); }
public void ThrowsInExporter() { this.spanExporter = new TestSpanExporter(_ => throw new ArgumentException("123")); this.tracer = TracerFactory.Create(b => b .AddProcessorPipeline(p => p .SetExporter(this.spanExporter) .SetExportingProcessor(e => new SimpleSpanProcessor(e)))) .GetTracer(null); var context = new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded); var span = (SpanSdk)this.tracer.StartSpan("foo", context); // does not throw span.End(); }
public void PipelineBuilder_AddExporter() { var builder = new SpanProcessorPipelineBuilder(); var exporter = new TestSpanExporter(null); builder.SetExporter(exporter); Assert.Same(exporter, builder.Exporter); var processor = builder.Build(); Assert.Single(builder.Processors); Assert.IsType <BatchingSpanProcessor>(builder.Processors.Single()); Assert.Same(processor, builder.Processors[0]); }
public void AddSpanAfterQueueIsExhausted() { int exportCalledCount = 0; var spanExporter = new TestSpanExporter(_ => Interlocked.Increment(ref exportCalledCount)); using var spanProcessor = new BatchingSpanProcessor(spanExporter, 1, TimeSpan.FromMilliseconds(100), 1); var spans = new List <SpanSdk>(); for (int i = 0; i < 20; i++) { spans.Add(this.CreateSampledEndedSpan(i.ToString(), spanProcessor)); } var exported = this.WaitForSpans(spanExporter, 1, DefaultTimeout); Assert.Equal(1, exportCalledCount); Assert.InRange(exported.Length, 1, 2); Assert.Contains(new SpanData(spans.First()), exported); }
public void DisposeFlushes() { const int batchSize = 2; int exportCalledCount = 0; var spanExporter = new TestSpanExporter(_ => Interlocked.Increment(ref exportCalledCount)); var spans = new List <SpanSdk>(); using (var spanProcessor = new BatchingSpanProcessor(spanExporter, 128, TimeSpan.FromMilliseconds(100), batchSize)) { for (int i = 0; i < 100; i++) { spans.Add(this.CreateSampledEndedSpan(i.ToString(), spanProcessor)); } Assert.True(spanExporter.ExportedSpans.Length < spans.Count); } Assert.True(spanExporter.WasShutDown); Assert.Equal(spans.Count, spanExporter.ExportedSpans.Length); Assert.Equal(spans.Count / batchSize, exportCalledCount); }
public void CreateFactory_BuilderWithMultiplePipelines() { var exporterCalledCount = 0; var testExporter = new TestSpanExporter(spans => { exporterCalledCount++; Assert.Single(spans); Assert.IsType <SpanSdk>(spans.Single()); }); var processCalledCount = 0; TestProcessor testProcessor1 = null; var testProcessor2 = new TestProcessor(_ => processCalledCount++); var tracerFactory = TracerFactory.Create(b => b .AddProcessorPipeline(p => p .SetExporter(testExporter) .SetExportingProcessor(e => { testProcessor1 = new TestProcessor(e); return(testProcessor1); })) .AddProcessorPipeline(p => p .AddProcessor(_ => testProcessor2))); var tracer = tracerFactory.GetTracer("my-app"); var span = tracer.StartSpan("foo"); span.End(); Assert.Equal(1, exporterCalledCount); Assert.Equal(1, processCalledCount); tracerFactory.Dispose(); Assert.True(testProcessor1.IsDisposed); Assert.True(testProcessor2.IsDisposed); }
public void ExportNotSampledSpans() { int exportCalledCount = 0; var spanExporter = new TestSpanExporter(_ => Interlocked.Increment(ref exportCalledCount)); using var spanProcessor = new BatchingSpanProcessor(spanExporter, 128, DefaultDelay, 3); var span1 = this.CreateNotSampledEndedSpan(SpanName1, spanProcessor); var span2 = this.CreateSampledEndedSpan(SpanName2, spanProcessor); // Spans are recorded and exported in the same order as they are ended, we test that a non // sampled span is not exported by creating and ending a sampled span after a non sampled span // and checking that the first exported span is the sampled span (the non sampled did not get // exported). var exported = this.WaitForSpans(spanExporter, 1, DefaultTimeout); Assert.Equal(1, exportCalledCount); // Need to check this because otherwise the variable span1 is unused, other option is to not // have a span1 variable. Assert.Single(exported); Assert.Contains(new SpanData(span2), exported); }
public void PipelineBuilder_AddExporterAndExportingProcessor() { var builder = new SpanProcessorPipelineBuilder(); var exporter = new TestSpanExporter(null); builder.SetExporter(exporter); bool processorFactoryCalled = false; builder.SetExportingProcessor(e => { processorFactoryCalled = true; return(new SimpleSpanProcessor(e)); }); var processor = builder.Build(); Assert.Single(builder.Processors); Assert.True(processorFactoryCalled); Assert.IsType <SimpleSpanProcessor>(builder.Processors.Single()); Assert.Same(processor, builder.Processors[0]); }
public void ProcessorDoesNotBlockOnExporter() { this.spanExporter = new TestSpanExporter(async _ => await Task.Delay(500)); this.tracer = TracerFactory.Create(b => b .AddProcessorPipeline(p => p .SetExporter(this.spanExporter) .SetExportingProcessor(e => new SimpleSpanProcessor(e)))) .GetTracer(null); var context = new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded); var span = (SpanSdk)this.tracer.StartSpan("foo", context); // does not block var sw = Stopwatch.StartNew(); span.End(); sw.Stop(); Assert.InRange(sw.Elapsed, TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); var exported = this.WaitForSpans(this.spanExporter, 1, TimeSpan.FromMilliseconds(600)); Assert.Single(exported); }
public void CreateFactory_BuilderWithArgs() { var exporterCalledCount = 0; var testExporter = new TestSpanExporter(spans => { exporterCalledCount++; Assert.Single(spans); Assert.IsType <SpanData>(spans.Single()); }); TestInstrumentation instrumentation1 = null; TestInstrumentation instrumentation2 = null; TestProcessor processor = null; var tracerFactory = TracerFactory.Create(b => b .AddProcessorPipeline(p => p .SetExporter(testExporter) .SetExportingProcessor(e => { processor = new TestProcessor(e); return(processor); })) .AddInstrumentation(t => { instrumentation1 = new TestInstrumentation(t); return(instrumentation1); }) .AddInstrumentation(t => { instrumentation2 = new TestInstrumentation(t); return(instrumentation2); })); var tracer = tracerFactory.GetTracer("my-app"); var span = tracer.StartSpan("foo"); span.End(); // default sampler is always sample Assert.True(span.IsRecording); Assert.Equal(1, exporterCalledCount); Assert.Single(((SpanSdk)span).LibraryResource.Attributes); Assert.Single(((SpanSdk)span).LibraryResource.Attributes.Where(kvp => kvp.Key == "name" && kvp.Value.ToString() == "my-app")); Assert.NotNull(instrumentation1); Assert.NotNull(instrumentation2); Assert.NotNull(processor); var span1 = instrumentation1.Collect(); var span2 = instrumentation1.Collect(); Assert.Equal(3, exporterCalledCount); Assert.Equal(2, span1.LibraryResource.Attributes.Count()); Assert.Equal(2, span2.LibraryResource.Attributes.Count()); Assert.Single(span1.LibraryResource.Attributes.Where(kvp => kvp.Key == "name" && kvp.Value is string sv && sv == "TestInstrumentation")); Assert.Single(span2.LibraryResource.Attributes.Where(kvp => kvp.Key == "name" && kvp.Value is string sv && sv == "TestInstrumentation")); Assert.Single(span1.LibraryResource.Attributes.Where(kvp => kvp.Key == "version" && kvp.Value is string sv && sv == "semver:1.0.0.0")); Assert.Single(span2.LibraryResource.Attributes.Where(kvp => kvp.Key == "version" && kvp.Value is string sv && sv == "semver:1.0.0.0")); tracerFactory.Dispose(); Assert.True(instrumentation1.IsDisposed); Assert.True(instrumentation2.IsDisposed); Assert.True(processor.IsDisposed); }