Пример #1
0
        public void JaegerTraceExporter_BuildBatchesToTransmit_MultipleBatches()
        {
            // Arrange
            using var jaegerExporter = new JaegerExporter(new JaegerExporterOptions { ServiceName = "TestService" });
            jaegerExporter.ApplyLibraryResource(Resource.Empty);

            // Act
            jaegerExporter.AppendSpan(CreateTestJaegerSpan());
            jaegerExporter.AppendSpan(
                CreateTestJaegerSpan(
                    additionalAttributes: new Dictionary <string, object>
            {
                ["peer.service"] = "MySQL",
            }));
            jaegerExporter.AppendSpan(CreateTestJaegerSpan());

            var batches = jaegerExporter.CurrentBatches.Values;

            // Assert
            Assert.Equal(2, batches.Count());

            var primaryBatch = batches.Where(b => b.Process.ServiceName == "TestService");

            Assert.Single(primaryBatch);
            Assert.Equal(2, primaryBatch.First().Count);

            var mySQLBatch = batches.Where(b => b.Process.ServiceName == "MySQL");

            Assert.Single(mySQLBatch);
            Assert.Equal(1, mySQLBatch.First().Count);
        }
Пример #2
0
        public static TracerProviderBuilder AddJaegerExporter(this TracerProviderBuilder builder, Action <JaegerExporterOptions> configure = null)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            var exporterOptions = new JaegerExporterOptions();

            configure?.Invoke(exporterOptions);
            var jaegerExporter = new JaegerExporter(exporterOptions);

            if (exporterOptions.ExportProcessorType == ExportProcessorType.Simple)
            {
                return(builder.AddProcessor(new SimpleActivityExportProcessor(jaegerExporter)));
            }
            else
            {
                return(builder.AddProcessor(new BatchActivityExportProcessor(
                                                jaegerExporter,
                                                exporterOptions.BatchExportProcessorOptions.MaxQueueSize,
                                                exporterOptions.BatchExportProcessorOptions.ScheduledDelayMilliseconds,
                                                exporterOptions.BatchExportProcessorOptions.ExporterTimeoutMilliseconds,
                                                exporterOptions.BatchExportProcessorOptions.MaxExportBatchSize)));
            }
        }
Пример #3
0
 public void JaegerTraceExporter_ctor_NullServiceNameAllowed()
 {
     using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions
     {
         ServiceName = null,
     });
     Assert.NotNull(jaegerTraceExporter);
 }
Пример #4
0
        private static TracerProviderBuilder AddJaegerExporter(
            TracerProviderBuilder builder,
            JaegerExporterOptions options,
            Action <JaegerExporterOptions> configure,
            IServiceProvider serviceProvider)
        {
            configure?.Invoke(options);

            if (options.Protocol == JaegerExportProtocol.HttpBinaryThrift && options.HttpClientFactory == null)
            {
                if (serviceProvider != null)
                {
                    options.HttpClientFactory = () =>
                    {
                        Type httpClientFactoryType = Type.GetType("System.Net.Http.IHttpClientFactory, Microsoft.Extensions.Http", throwOnError: false);
                        if (httpClientFactoryType != null)
                        {
                            object httpClientFactory = serviceProvider.GetService(httpClientFactoryType);
                            if (httpClientFactory != null)
                            {
                                MethodInfo createClientMethod = httpClientFactoryType.GetMethod(
                                    "CreateClient",
                                    BindingFlags.Public | BindingFlags.Instance,
                                    binder: null,
                                    new Type[] { typeof(string) },
                                    modifiers: null);
                                if (createClientMethod != null)
                                {
                                    return((HttpClient)createClientMethod.Invoke(httpClientFactory, new object[] { "JaegerExporter" }));
                                }
                            }
                        }

                        return(new HttpClient());
                    };
                }
                else
                {
                    options.HttpClientFactory = () => new HttpClient();
                }
            }

            var jaegerExporter = new JaegerExporter(options);

            if (options.ExportProcessorType == ExportProcessorType.Simple)
            {
                return(builder.AddProcessor(new SimpleActivityExportProcessor(jaegerExporter)));
            }
            else
            {
                return(builder.AddProcessor(new BatchActivityExportProcessor(
                                                jaegerExporter,
                                                options.BatchExportProcessorOptions.MaxQueueSize,
                                                options.BatchExportProcessorOptions.ScheduledDelayMilliseconds,
                                                options.BatchExportProcessorOptions.ExporterTimeoutMilliseconds,
                                                options.BatchExportProcessorOptions.MaxExportBatchSize)));
            }
        }
Пример #5
0
        public void JaegerTraceExporter_SetResource_IgnoreServiceResources()
        {
            using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
            var process = jaegerTraceExporter.Process;

            jaegerTraceExporter.SetResource(new Resource(new Dictionary <string, object>
            {
                [Resource.ServiceNameKey]      = "servicename",
                [Resource.ServiceNamespaceKey] = "servicenamespace",
            }));

            Assert.Null(process.Tags);
        }
        public void JaegerTraceExporter_SetResource_IgnoreServiceResources()
        {
            using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
            var process = jaegerTraceExporter.Process;

            jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddAttributes(new Dictionary <string, object>
            {
                [ResourceSemanticConventions.AttributeServiceName]      = "servicename",
                [ResourceSemanticConventions.AttributeServiceNamespace] = "servicenamespace",
            }).Build());

            Assert.Null(process.Tags);
        }
Пример #7
0
        public void JaegerTraceExporter_ApplyLibraryResource_IgnoreLibraryResources()
        {
            using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
            var process = jaegerTraceExporter.Process;

            jaegerTraceExporter.ApplyLibraryResource(new Resource(new Dictionary <string, object>
            {
                [Resource.LibraryNameKey]    = "libname",
                [Resource.LibraryVersionKey] = "libversion",
            }));

            Assert.Null(process.Tags);
        }
        public void JaegerTraceExporter_SetResource_CreatesTags()
        {
            using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
            var process = jaegerTraceExporter.Process;

            jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddAttributes(new Dictionary <string, object>
            {
                ["Tag"] = "value",
            }).Build());

            Assert.NotNull(process.Tags);
            Assert.Single(process.Tags);
            Assert.Equal("value", process.Tags["Tag"].VStr);
        }
        public void JaegerTraceExporter_BuildBatchesToTransmit_FlushedBatch()
        {
            // Arrange
            using var jaegerExporter = new JaegerExporter(new JaegerExporterOptions { MaxPayloadSizeInBytes = 1500 });
            jaegerExporter.SetResourceAndInitializeBatch(Resource.Empty);

            // Act
            jaegerExporter.AppendSpan(CreateTestJaegerSpan());
            jaegerExporter.AppendSpan(CreateTestJaegerSpan());
            jaegerExporter.AppendSpan(CreateTestJaegerSpan());

            // Assert
            Assert.Equal(1U, jaegerExporter.NumberOfSpansInCurrentBatch);
        }
Пример #10
0
        public void JaegerTraceExporter_ApplyLibraryResource_CreatesTags()
        {
            using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
            var process = jaegerTraceExporter.Process;

            jaegerTraceExporter.ApplyLibraryResource(new Resource(new Dictionary <string, object>
            {
                ["Tag"] = "value",
            }));

            Assert.NotNull(process.Tags);
            Assert.Single(process.Tags);
            Assert.Equal("value", process.Tags["Tag"].VStr);
        }
Пример #11
0
        /// <summary>
        /// Adds Jaeger exporter to the TracerProvider.
        /// </summary>
        /// <param name="builder"><see cref="TracerProviderBuilder"/> builder to use.</param>
        /// <param name="configure">Exporter configuration options.</param>
        /// <returns>The instance of <see cref="TracerProviderBuilder"/> to chain the calls.</returns>
        public static TracerProviderBuilder AddJaegerExporter(this TracerProviderBuilder builder, Action <JaegerExporterOptions> configure = null)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            var exporterOptions = new JaegerExporterOptions();

            configure?.Invoke(exporterOptions);
            var jaegerExporter = new JaegerExporter(exporterOptions);

            // TODO: Pick Simple vs Batching based on JaegerExporterOptions
            return(builder.AddProcessor(new BatchExportActivityProcessor(jaegerExporter)));
        }
        public void JaegerTraceExporter_BuildBatchesToTransmit_FlushedBatch()
        {
            // Arrange
            using var jaegerExporter = new JaegerExporter(new JaegerExporterOptions { ServiceName = "TestService", MaxPacketSize = 1500 });

            // Act
            jaegerExporter.AppendSpan(CreateTestJaegerSpan());
            jaegerExporter.AppendSpan(CreateTestJaegerSpan());
            jaegerExporter.AppendSpan(CreateTestJaegerSpan());

            var batches = jaegerExporter.CurrentBatches.Values;

            // Assert
            Assert.Single(batches);
            Assert.Equal("TestService", batches.First().Process.ServiceName);
            Assert.Equal(1, batches.First().Count);
        }
Пример #13
0
        /// <summary>
        /// Registers a Jaeger exporter that will receive <see cref="System.Diagnostics.Activity"/> instances.
        /// </summary>
        /// <param name="builder"><see cref="TracerProviderBuilder"/> builder to use.</param>
        /// <param name="configure">Exporter configuration options.</param>
        /// <param name="processorConfigure">Activity processor configuration.</param>
        /// <returns>The instance of <see cref="TracerProviderBuilder"/> to chain the calls.</returns>
        public static TracerProviderBuilder UseJaegerExporter(this TracerProviderBuilder builder, Action <JaegerExporterOptions> configure = null, Action <ActivityProcessorPipelineBuilder> processorConfigure = null)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            return(builder.AddProcessorPipeline(pipeline =>
            {
                var exporterOptions = new JaegerExporterOptions();
                configure?.Invoke(exporterOptions);

                var activityExporter = new JaegerExporter(exporterOptions);
                processorConfigure?.Invoke(pipeline);
                pipeline.SetExporter(activityExporter);
            }));
        }
Пример #14
0
        public void JaegerTraceExporter_SetResource_CombinesTags()
        {
            using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
            var process = jaegerTraceExporter.Process;

            process.Tags = new Dictionary<string, JaegerTag> { ["Tag1"] = new KeyValuePair<string, object>("Tag1", "value1").ToJaegerTag() };

            jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddAttributes(new Dictionary<string, object>
            {
                ["Tag2"] = "value2",
            }).Build());

            Assert.NotNull(process.Tags);
            Assert.Equal(2, process.Tags.Count);
            Assert.Equal("value1", process.Tags["Tag1"].VStr);
            Assert.Equal("value2", process.Tags["Tag2"].VStr);
        }
Пример #15
0
        public void JaegerTraceExporter_BuildBatchesToTransmit_DefaultBatch()
        {
            // Arrange
            using var jaegerExporter = new JaegerExporter(new JaegerExporterOptions { ServiceName = "TestService" });
            jaegerExporter.ApplyLibraryResource(Resource.Empty);

            // Act
            jaegerExporter.AppendSpan(CreateTestJaegerSpan());
            jaegerExporter.AppendSpan(CreateTestJaegerSpan());
            jaegerExporter.AppendSpan(CreateTestJaegerSpan());

            var batches = jaegerExporter.CurrentBatches.Values;

            // Assert
            Assert.Single(batches);
            Assert.Equal("TestService", batches.First().Process.ServiceName);
            Assert.Equal(3, batches.First().Count);
        }
        public void JaegerTraceExporter_BuildBatchesToTransmit_FlushedBatch()
        {
            // Arrange
            using var jaegerExporter = new JaegerExporter(new JaegerExporterOptions { MaxPayloadSizeInBytes = 1500 });
            jaegerExporter.SetResource(Resource.Empty);

            // Act
            jaegerExporter.AppendSpan(CreateTestJaegerSpan());
            jaegerExporter.AppendSpan(CreateTestJaegerSpan());
            jaegerExporter.AppendSpan(CreateTestJaegerSpan());

            var batches = jaegerExporter.CurrentBatches.Values;

            // Assert
            Assert.Single(batches);
            Assert.Equal(DefaultServiceName, batches.First().Process.ServiceName);
            Assert.Equal(1, batches.First().Count);
        }
        public void JaegerTraceExporter_SetResource_UpdatesServiceName()
        {
            using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
            var process = jaegerTraceExporter.Process;

            process.ServiceName = "TestService";

            jaegerTraceExporter.SetResourceAndInitializeBatch(Resource.Empty);

            Assert.Equal("TestService", process.ServiceName);

            jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddService("MyService").Build());

            Assert.Equal("MyService", process.ServiceName);

            jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddService("MyService", "MyNamespace").Build());

            Assert.Equal("MyNamespace.MyService", process.ServiceName);
        }
        public void UserHttpFactoryCalled()
        {
            JaegerExporterOptions options = new JaegerExporterOptions();

            var defaultFactory = options.HttpClientFactory;

            int invocations = 0;

            options.Protocol          = JaegerExportProtocol.HttpBinaryThrift;
            options.HttpClientFactory = () =>
            {
                invocations++;
                return(defaultFactory());
            };

            using (var exporter = new JaegerExporter(options))
            {
                Assert.Equal(1, invocations);
            }

            using (var provider = Sdk.CreateTracerProviderBuilder()
                                  .AddJaegerExporter(o =>
            {
                o.Protocol = JaegerExportProtocol.HttpBinaryThrift;
                o.HttpClientFactory = options.HttpClientFactory;
            })
                                  .Build())
            {
                Assert.Equal(2, invocations);
            }

            options.HttpClientFactory = null;
            Assert.Throws <InvalidOperationException>(() =>
            {
                using var exporter = new JaegerExporter(options);
            });

            options.HttpClientFactory = () => null;
            Assert.Throws <InvalidOperationException>(() =>
            {
                using var exporter = new JaegerExporter(options);
            });
        }
Пример #19
0
        internal static object Run(string host, int port)
        {
            // 1. Configure exporter to export traces to Jaeger
            var exporter = new JaegerExporter(
                new JaegerExporterOptions
            {
                ServiceName = "tracing-to-jaeger-service",
                AgentHost   = host,
                AgentPort   = port,
            },
                Tracing.SpanExporter);

            exporter.Start();

            // 2. Configure 100% sample rate for the purposes of the demo
            ITraceConfig traceConfig   = Tracing.TraceConfig;
            ITraceParams currentConfig = traceConfig.ActiveTraceParams;
            var          newConfig     = currentConfig.ToBuilder()
                                         .SetSampler(Samplers.AlwaysSample)
                                         .Build();

            traceConfig.UpdateActiveTraceParams(newConfig);

            // 3. Tracer is global singleton. You can register it via dependency injection if it exists
            // but if not - you can use it as follows:
            var tracer = Tracing.Tracer;

            // 4. Create a scoped span. It will end automatically when using statement ends
            using (tracer.WithSpan(tracer.SpanBuilder("Main").StartSpan()))
            {
                tracer.CurrentSpan.SetAttribute("custom-attribute", 55);
                Console.WriteLine("About to do a busy work");
                for (int i = 0; i < 10; i++)
                {
                    DoWork(i);
                }
            }

            // 5. Gracefully shutdown the exporter so it'll flush queued traces to Zipkin.
            Tracing.SpanExporter.Dispose();

            return(null);
        }
Пример #20
0
        public void JaegerTraceExporter_ApplyLibraryResource_CombinesTags()
        {
            using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
            var process = jaegerTraceExporter.Process;

            process.Tags = new Dictionary <string, JaegerTag> {
                ["Tag1"] = new KeyValuePair <string, object>("Tag1", "value1").ToJaegerTag()
            };

            jaegerTraceExporter.ApplyLibraryResource(new Resource(new Dictionary <string, object>
            {
                ["Tag2"] = "value2",
            }));

            Assert.NotNull(process.Tags);
            Assert.Equal(2, process.Tags.Count);
            Assert.Equal("value1", process.Tags["Tag1"].VStr);
            Assert.Equal("value2", process.Tags["Tag2"].VStr);
        }
Пример #21
0
        public void JaegerTraceExporter_ApplyLibraryResource_UpdatesServiceName()
        {
            using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
            var process = jaegerTraceExporter.Process;

            process.ServiceName = "TestService";

            jaegerTraceExporter.ApplyLibraryResource(Resource.Empty);

            Assert.Equal("TestService", process.ServiceName);

            jaegerTraceExporter.ApplyLibraryResource(Resources.Resources.CreateServiceResource("MyService"));

            Assert.Equal("MyService", process.ServiceName);

            jaegerTraceExporter.ApplyLibraryResource(Resources.Resources.CreateServiceResource("MyService", serviceNamespace: "MyNamespace"));

            Assert.Equal("MyNamespace.MyService", process.ServiceName);
        }
        public void HttpClient_Posts_To_Configured_Endpoint(string uriPath)
        {
            // Arrange
            ConcurrentDictionary <Guid, string> responses = new ConcurrentDictionary <Guid, string>();

            using var testServer = TestHttpServer.RunServer(
                      context =>
            {
                context.Response.StatusCode = 200;

                using StreamReader readStream = new StreamReader(context.Request.InputStream);

                string requestContent = readStream.ReadToEnd();

                responses.TryAdd(
                    Guid.Parse(context.Request.QueryString["requestId"]),
                    context.Request.Url.LocalPath);

                context.Response.OutputStream.Close();
            },
                      out var testServerHost,
                      out var testServerPort);

            var requestId = Guid.NewGuid();
            var options   = new JaegerExporterOptions
            {
                Endpoint            = new Uri($"http://{testServerHost}:{testServerPort}{uriPath}?requestId={requestId}"),
                Protocol            = JaegerExportProtocol.HttpBinaryThrift,
                ExportProcessorType = ExportProcessorType.Simple,
            };

            using var jaegerExporter = new JaegerExporter(options);

            // Act
            jaegerExporter.SetResourceAndInitializeBatch(Resource.Empty);
            jaegerExporter.AppendSpan(CreateTestJaegerSpan());
            jaegerExporter.SendCurrentBatch();

            // Assert
            Assert.True(responses.ContainsKey(requestId));
            Assert.Equal(uriPath, responses[requestId]);
        }
Пример #23
0
        private static TracerProviderBuilder AddJaegerExporter(TracerProviderBuilder builder, JaegerExporterOptions options, Action <JaegerExporterOptions> configure = null)
        {
            configure?.Invoke(options);

            var jaegerExporter = new JaegerExporter(options);

            if (options.ExportProcessorType == ExportProcessorType.Simple)
            {
                return(builder.AddProcessor(new SimpleActivityExportProcessor(jaegerExporter)));
            }
            else
            {
                return(builder.AddProcessor(new BatchActivityExportProcessor(
                                                jaegerExporter,
                                                options.BatchExportProcessorOptions.MaxQueueSize,
                                                options.BatchExportProcessorOptions.ScheduledDelayMilliseconds,
                                                options.BatchExportProcessorOptions.ExporterTimeoutMilliseconds,
                                                options.BatchExportProcessorOptions.MaxExportBatchSize)));
            }
        }
Пример #24
0
        public void JaegerExporter_Batching()
        {
            using JaegerExporter exporter = new JaegerExporter(
                      new JaegerExporterOptions(),
                      new BlackHoleTransport())
                  {
                      Process = new Jaeger.Process("TestService"),
                  };

            for (int i = 0; i < this.NumberOfBatches; i++)
            {
                for (int c = 0; c < this.NumberOfSpans; c++)
                {
                    this.activityBatch.Add(this.activity);
                }

                exporter.Export(new Batch <Activity>(this.activityBatch, this.NumberOfSpans));
            }

            exporter.Shutdown();
        }
        public void JaegerExporter_Batching()
        {
            using JaegerExporter exporter = new JaegerExporter(
                      new JaegerExporterOptions(),
                      new TCompactProtocol.Factory(),
                      new NoopJaegerClient())
                  {
                      Process = new Jaeger::OpenTelemetry.Exporter.Jaeger.Implementation.Process("TestService"),
                  };

            for (int i = 0; i < this.NumberOfBatches; i++)
            {
                for (int c = 0; c < this.NumberOfSpans; c++)
                {
                    this.activityBatch.Add(this.activity);
                }

                exporter.Export(new Batch <Activity>(this.activityBatch, this.NumberOfSpans));
            }

            exporter.Shutdown();
        }
Пример #26
0
        private static void ConsfigExporter()
        {
            // 1. Configure exporter to export traces to Jaeger
            var exporter = new JaegerExporter(
                new JaegerExporterOptions
            {
                ServiceName = "OpenTelemetrySample",
                AgentHost   = "localhost",
                AgentPort   = 5775,
            },
                Tracing.SpanExporter);

            exporter.Start();

            // 2. Configure 100% sample rate for the purposes of the demo
            ITraceConfig traceConfig   = Tracing.TraceConfig;
            ITraceParams currentConfig = traceConfig.ActiveTraceParams;
            var          newConfig     = currentConfig.ToBuilder()
                                         .SetSampler(Samplers.AlwaysSample)
                                         .Build();

            traceConfig.UpdateActiveTraceParams(newConfig);
        }
Пример #27
0
        public void JaegerTraceExporter_SpansSplitToBatches_SpansIncludedInBatches()
        {
            // Arrange
            var memoryTransport = new InMemoryTransport();
            using var jaegerExporter = new JaegerExporter(
                new JaegerExporterOptions { MaxPayloadSizeInBytes = 1500 }, memoryTransport);
            jaegerExporter.SetResourceAndInitializeBatch(Resource.Empty);

            var tempTransport = new InMemoryTransport(initialCapacity: 3000);
            var protocol = new TCompactProtocol(tempTransport);

            // Create six spans, each taking more space than the previous one
            var spans = new JaegerSpan[6];
            for (int i = 0; i < 6; i++)
            {
                spans[i] = CreateTestJaegerSpan(
                    additionalAttributes: new Dictionary<string, object>
                    {
                        ["foo"] = new string('_', 10 * i),
                    });
            }

            var serializedSpans = spans.Select(s =>
            {
                s.Write(protocol);
                return tempTransport.ToArray();
            }).ToArray();

            // Act
            var sentBatches = new List<byte[]>();
            foreach (var span in spans)
            {
                jaegerExporter.AppendSpan(span);
                var sentBatch = memoryTransport.ToArray();
                if (sentBatch.Length > 0)
                {
                    sentBatches.Add(sentBatch);
                }
            }

            // Assert

            // Appending the six spans will send two batches with the first four spans
            Assert.Equal(2, sentBatches.Count);
            Assert.True(
                ContainsSequence(sentBatches[0], serializedSpans[0]),
                "Expected span data not found in sent batch");
            Assert.True(
                ContainsSequence(sentBatches[0], serializedSpans[1]),
                "Expected span data not found in sent batch");

            Assert.True(
                ContainsSequence(sentBatches[1], serializedSpans[2]),
                "Expected span data not found in sent batch");
            Assert.True(
                ContainsSequence(sentBatches[1], serializedSpans[3]),
                "Expected span data not found in sent batch");

            // jaegerExporter.Batch should contain the two remaining spans
            Assert.Equal(2, jaegerExporter.Batch.Count);
            jaegerExporter.Batch.Write(protocol);
            var serializedBatch = tempTransport.ToArray();
            Assert.True(
                ContainsSequence(serializedBatch, serializedSpans[4]),
                "Expected span data not found in unsent batch");
            Assert.True(
                ContainsSequence(serializedBatch, serializedSpans[5]),
                "Expected span data not found in unsent batch");
        }
        public void JaegerTraceExporter_SpansSplitToBatches_SpansIncludedInBatches(string protocolType, int maxPayloadSizeInBytes)
        {
            TProtocolFactory protocolFactory = protocolType == "Compact"
                ? new TCompactProtocol.Factory()
                : new TBinaryProtocol.Factory();
            var client = new TestJaegerClient();

            // Arrange
            using var jaegerExporter = new JaegerExporter(
                      new JaegerExporterOptions { MaxPayloadSizeInBytes = maxPayloadSizeInBytes },
                      protocolFactory,
                      client);
            jaegerExporter.SetResourceAndInitializeBatch(Resource.Empty);

            // Create six spans, each taking more space than the previous one
            var spans = new JaegerSpan[6];

            for (int i = 0; i < 6; i++)
            {
                spans[i] = CreateTestJaegerSpan(
                    additionalAttributes: new Dictionary <string, object>
                {
                    ["foo"] = new string('_', 10 * i),
                });
            }

            var protocol        = protocolFactory.GetProtocol();
            var serializedSpans = spans.Select(s =>
            {
                s.Write(protocol);
                var data = protocol.WrittenData.ToArray();
                protocol.Clear();
                return(data);
            }).ToArray();

            // Act
            var sentBatches = new List <byte[]>();

            foreach (var span in spans)
            {
                jaegerExporter.AppendSpan(span);
                var sentBatch = client.LastWrittenData;
                if (sentBatch != null)
                {
                    sentBatches.Add(sentBatch);
                    client.LastWrittenData = null;
                }
            }

            // Assert

            // Appending the six spans will send two batches with the first four spans
            Assert.Equal(2, sentBatches.Count);
            Assert.True(
                ContainsSequence(sentBatches[0], serializedSpans[0]),
                "Expected span data not found in sent batch");
            Assert.True(
                ContainsSequence(sentBatches[0], serializedSpans[1]),
                "Expected span data not found in sent batch");

            Assert.True(
                ContainsSequence(sentBatches[1], serializedSpans[2]),
                "Expected span data not found in sent batch");
            Assert.True(
                ContainsSequence(sentBatches[1], serializedSpans[3]),
                "Expected span data not found in sent batch");

            // jaegerExporter.Batch should contain the two remaining spans
            Assert.Equal(2U, jaegerExporter.NumberOfSpansInCurrentBatch);
            jaegerExporter.SendCurrentBatch();
            Assert.True(client.LastWrittenData != null);
            var serializedBatch = client.LastWrittenData;

            Assert.True(
                ContainsSequence(serializedBatch, serializedSpans[4]),
                "Expected span data not found in unsent batch");
            Assert.True(
                ContainsSequence(serializedBatch, serializedSpans[5]),
                "Expected span data not found in unsent batch");
        }