Example #1
0
        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);
        }
Example #2
0
        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);
        }
Example #3
0
        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);
        }
Example #4
0
        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);
        }
Example #5
0
        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);
            }
        }
Example #6
0
 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);
 }
Example #7
0
        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);
        }
Example #9
0
        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);
        }
Example #10
0
        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);
        }
Example #11
0
        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]);
        }
Example #13
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);
        }
Example #14
0
        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);
        }
Example #15
0
        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);
        }
Example #16
0
        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]);
        }
Example #18
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);
        }
Example #19
0
        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);
        }