internal static object Run(string host, int port) { // Configure exporter to export traces to Jaeger var jaegerOptions = new JaegerExporterOptions() { ServiceName = "tracing-to-jaeger-service", AgentHost = host, AgentPort = port, }; var exporter = new JaegerTraceExporter( jaegerOptions); // Create a tracer. You may also need to register it as a global instance to make auto-collectors work.. var tracerFactory = new TracerFactory(new BatchingSpanProcessor(exporter)); var tracer = tracerFactory.GetTracer(string.Empty); // 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, tracer); } } // Gracefully shutdown the exporter so it'll flush queued traces to Jaeger. exporter.ShutdownAsync(CancellationToken.None).GetAwaiter().GetResult(); return(null); }
private bool disposedValue = false; // To detect redundant calls public JaegerUdpBatcher(JaegerExporterOptions options, TTransport clientTransport = null) { if (options is null) { throw new ArgumentNullException(nameof(options)); } if (options.MaxFlushInterval <= TimeSpan.Zero) { options.MaxFlushInterval = TimeSpan.FromSeconds(10); } this.maxPacketSize = (!options.MaxPacketSize.HasValue || options.MaxPacketSize <= 0) ? JaegerExporterOptions.DefaultMaxPacketSize : options.MaxPacketSize.Value; this.protocolFactory = new TCompactProtocol.Factory(); this.clientTransport = clientTransport ?? new JaegerThriftClientTransport(options.AgentHost, options.AgentPort); this.thriftClient = new JaegerThriftClient(this.protocolFactory.GetProtocol(this.clientTransport)); this.memoryTransport = new InMemoryTransport(16000); this.memoryProtocol = this.protocolFactory.GetProtocol(this.memoryTransport); this.Process = new Process(options.ServiceName, options.ProcessTags); this.maxFlushInterval = options.MaxFlushInterval; this.maxFlushIntervalTimer = new System.Timers.Timer { AutoReset = false, Enabled = false, Interval = this.maxFlushInterval.TotalMilliseconds, }; this.maxFlushIntervalTimer.Elapsed += async(sender, args) => { await this.FlushAsyncInternal(false, CancellationToken.None).ConfigureAwait(false); }; }
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))); } }
/// <summary> /// Registers Jaeger exporter. /// </summary> /// <param name="builder">Trace builder to use.</param> /// <param name="configure">Exporter configuration options.</param> /// <param name="processorConfigure">Span processor configuration.</param> /// <returns>The instance of <see cref="TracerBuilder"/> to chain the calls.</returns> public static TracerBuilder UseJaeger(this TracerBuilder builder, Action <JaegerExporterOptions> configure, Action <SpanProcessorPipelineBuilder> processorConfigure) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (configure == null) { throw new ArgumentNullException(nameof(configure)); } if (processorConfigure == null) { throw new ArgumentNullException(nameof(processorConfigure)); } var options = new JaegerExporterOptions(); configure(options); return(builder.AddProcessorPipeline(b => { b.SetExporter(new JaegerTraceExporter(options)); processorConfigure.Invoke(b); })); }
internal static object Run(string host, int port) { // Configure exporter to export traces to Jaeger var jaegerOptions = new JaegerExporterOptions() { ServiceName = "jaeger-test", AgentHost = host, AgentPort = port, }; // Create a tracer. using (var tracerFactory = TracerFactory.Create(builder => builder.SetExporter(new JaegerTraceExporter(jaegerOptions)))) { var tracer = tracerFactory.GetTracer("jaeger-test"); // Create a scoped span. It will end automatically when using statement ends using (tracer.WithSpan(tracer.StartSpan("Main"))) { tracer.CurrentSpan.SetAttribute("custom-attribute", 55); Console.WriteLine("About to do a busy work"); for (int i = 0; i < 10; i++) { DoWork(i, tracer); } } return(null); } }
public static TracerFactory GetTracerFactory(this JaegerExporterOptions options) { var tracerFactory = TracerFactory.Create(builder => builder .AddProcessorPipeline(c => c .SetExporter(new JaegerTraceExporter(options)))); return(tracerFactory); }
public void JaegerExporterOptions_InvalidPortEnvironmentVariableOverride() { Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelAgentPortEnvVarKey, "invalid"); var options = new JaegerExporterOptions(); Assert.Equal(6831, options.AgentPort); // use default }
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))); } }
public void JaegerExporterOptions_Defaults() { var options = new JaegerExporterOptions(); Assert.Equal("localhost", options.AgentHost); Assert.Equal(6831, options.AgentPort); Assert.Equal(4096, options.MaxPayloadSizeInBytes); Assert.Equal(ExportProcessorType.Batch, options.ExportProcessorType); }
public void JaegerExporterOptions_EnvironmentVariableOverride() { Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelAgentHostEnvVarKey, "jeager-host"); Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelAgentPortEnvVarKey, "123"); var options = new JaegerExporterOptions(); Assert.Equal("jeager-host", options.AgentHost); Assert.Equal(123, options.AgentPort); }
public void Constructor_EmptyServiceName_ThrowsArgumentNullException() { // Arrange var options = new JaegerExporterOptions(); // Act & Assert var exception = Assert.Throws <ArgumentException>(() => new JaegerTraceExporter(options)); Assert.Equal("ServiceName", exception.ParamName); }
private bool disposedValue = false; // To detect redundant calls public JaegerUdpBatcher(JaegerExporterOptions options) { this.maxPacketSize = options.MaxPacketSize == 0 ? DefaultMaxPacketSize : options.MaxPacketSize; this.protocolFactory = new TCompactProtocol.Factory(); this.clientTransport = new JaegerThriftClientTransport(options.AgentHost, options.AgentPort.Value); this.thriftClient = new JaegerThriftClient(this.protocolFactory.GetProtocol(this.clientTransport)); this.process = new Process(options.ServiceName, options.ProcessTags); this.processByteSize = this.GetSize(this.process); this.batchByteSize = this.processByteSize; }
public void JaegerExporterOptions_Defaults() { var options = new JaegerExporterOptions(); Assert.Equal("localhost", options.AgentHost); Assert.Equal(6831, options.AgentPort); Assert.Equal(4096, options.MaxPayloadSizeInBytes); Assert.Equal(ExportProcessorType.Batch, options.ExportProcessorType); Assert.Equal(JaegerExportProtocol.UdpCompactThrift, options.Protocol); Assert.Equal(JaegerExporterOptions.DefaultJaegerEndpoint, options.Endpoint.ToString()); }
public void JaegerExporterOptions_SetterOverridesEnvironmentVariable() { Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelAgentHostEnvVarKey, "envvar-host"); var options = new JaegerExporterOptions { AgentHost = "incode-host", }; Assert.Equal("incode-host", options.AgentHost); }
public void Constructor_ValidOptions_ReturnsInstance() { // Arrange var options = new JaegerExporterOptions { ServiceName = "test_service" }; // Act var exporter = new JaegerTraceExporter(options); // Assert Assert.NotNull(exporter); }
public void JaegerExporterOptions_EnvironmentVariableOverride() { Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelAgentHostEnvVarKey, "jaeger-host"); Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelAgentPortEnvVarKey, "123"); Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelProtocolEnvVarKey, "http/thrift.binary"); Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelEndpointEnvVarKey, "http://custom-endpoint:12345"); var options = new JaegerExporterOptions(); Assert.Equal("jaeger-host", options.AgentHost); Assert.Equal(123, options.AgentPort); Assert.Equal(JaegerExportProtocol.HttpBinaryThrift, options.Protocol); Assert.Equal(new Uri("http://custom-endpoint:12345"), options.Endpoint); }
/// <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))); }
/// <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); })); }
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); }); }
/// <summary> /// Registers a Jaeger exporter. /// </summary> /// <param name="builder">Trace builder to use.</param> /// <param name="configure">Exporter configuration options.</param> /// <returns>The instance of <see cref="TracerBuilder"/> to chain the calls.</returns> public static TracerBuilder UseJaeger(this TracerBuilder builder, Action <JaegerExporterOptions> configure) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (configure == null) { throw new ArgumentNullException(nameof(configure)); } var options = new JaegerExporterOptions(); configure(options); return(builder.AddProcessorPipeline(b => b .SetExporter(new JaegerTraceExporter(options)) .SetExportingProcessor(e => new BatchingSpanProcessor(e)))); }
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]); }
/// <summary> /// Registers a Jaeger exporter that will receive <see cref="System.Diagnostics.Activity"/> instances. /// </summary> /// <param name="builder"><see cref="OpenTelemetryBuilder"/> builder to use.</param> /// <param name="configure">Exporter configuration options.</param> /// <returns>The instance of <see cref="OpenTelemetryBuilder"/> to chain the calls.</returns> public static OpenTelemetryBuilder UseJaegerActivityExporter(this OpenTelemetryBuilder builder, Action <JaegerExporterOptions> configure) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (configure == null) { throw new ArgumentNullException(nameof(configure)); } return(builder.AddProcessorPipeline(pipeline => { var exporterOptions = new JaegerExporterOptions(); configure(exporterOptions); var activityExporter = new JaegerActivityExporter(exporterOptions); pipeline.SetExporter(activityExporter); })); }
public async Task JaegerUdpBatcherTests_BuildBatchesToTransmit_MultipleBatches() { // Arrange var options = new JaegerExporterOptions { ServiceName = "TestService", MaxFlushInterval = TimeSpan.FromHours(1) }; var jaegerUdpBatcher = new JaegerUdpBatcher(options); // Act await jaegerUdpBatcher.AppendAsync(JaegerSpanConverterTest.CreateTestSpan().ToJaegerSpan(), CancellationToken.None).ConfigureAwait(false); await jaegerUdpBatcher.AppendAsync( JaegerSpanConverterTest.CreateTestSpan( additionalAttributes : new Dictionary <string, object> { ["peer.service"] = "MySQL", }) .ToJaegerSpan(), CancellationToken.None).ConfigureAwait(false); await jaegerUdpBatcher.AppendAsync(JaegerSpanConverterTest.CreateTestSpan().ToJaegerSpan(), CancellationToken.None).ConfigureAwait(false); var batches = jaegerUdpBatcher.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().Spans.Count()); var MySQLBatch = batches.Where(b => b.Process.ServiceName == "MySQL"); Assert.Single(MySQLBatch); Assert.Single(MySQLBatch.First().Spans); }
public async Task JaegerUdpBatcherTests_BuildBatchesToTransmit_DefaultBatch() { // Arrange var options = new JaegerExporterOptions { ServiceName = "TestService", MaxFlushInterval = TimeSpan.FromHours(1) }; var jaegerUdpBatcher = new JaegerUdpBatcher(options); // Act await jaegerUdpBatcher.AppendAsync(CreateTestJaegerSpan(), CancellationToken.None).ConfigureAwait(false); await jaegerUdpBatcher.AppendAsync(CreateTestJaegerSpan(), CancellationToken.None).ConfigureAwait(false); await jaegerUdpBatcher.AppendAsync(CreateTestJaegerSpan(), CancellationToken.None).ConfigureAwait(false); var batches = jaegerUdpBatcher.CurrentBatches.Values; // Assert Assert.Single(batches); Assert.Equal("TestService", batches.First().Process.ServiceName); Assert.Equal(3, batches.First().SpanMessages.Count()); }
private static void AddExporter(this TracerProviderBuilder builder, ILogger logger, JaegerExporterOptions options, IApplicationNameService applicationNameService, HostBuilderContext hostContext) { try { Dns.GetHostEntry(options.AgentHost); builder.AddJaegerExporter(internalOptions => { var dictionary = options.ProcessTags.ToDictionary(pair => pair.Key, pair => pair.Value); dictionary.Add(AttributeMotorProduct, applicationNameService.GetProduct()); dictionary.Add(AttributeMotorEnvironment, hostContext.HostingEnvironment.EnvironmentName.ToLower()); internalOptions.ProcessTags = dictionary.ToList(); internalOptions.AgentHost = options.AgentHost; internalOptions.AgentPort = options.AgentPort; }); } catch (Exception ex) { logger.LogWarning(LogEvents.JaegerConfigurationFailed, ex, "Jaeger configuration failed, fallback to console."); builder.AddConsoleExporter(); } }
public async Task JaegerUdpBatcherTests_BuildBatchesToTransmit_FlushedBatch() { // Arrange var options = new JaegerExporterOptions { ServiceName = "TestService", MaxFlushInterval = TimeSpan.FromHours(1), MaxPacketSize = 750 }; var jaegerUdpBatcher = new JaegerUdpBatcher(options); // Act await jaegerUdpBatcher.AppendAsync(JaegerSpanConverterTest.CreateTestSpan().ToJaegerSpan(), CancellationToken.None).ConfigureAwait(false); await jaegerUdpBatcher.AppendAsync(JaegerSpanConverterTest.CreateTestSpan().ToJaegerSpan(), CancellationToken.None).ConfigureAwait(false); var flushCount = await jaegerUdpBatcher.AppendAsync(JaegerSpanConverterTest.CreateTestSpan().ToJaegerSpan(), CancellationToken.None).ConfigureAwait(false); var batches = jaegerUdpBatcher.CurrentBatches.Values; // Assert Assert.Equal(2, flushCount); Assert.Single(batches); Assert.Equal("TestService", batches.First().Process.ServiceName); Assert.Single(batches.First().Spans); }
public WeatherForecastController(IHttpClientFactory clientFactory, IConfiguration config, ILogger <WeatherForecastController> logger) { ClientFactory = clientFactory; jaegerOptions = config.GetOptions <JaegerExporterOptions>("Jaeger"); _logger = logger; }
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))); } }
private bool disposedValue = false; // To detect redundant dispose calls public JaegerTraceExporterHandler(JaegerExporterOptions options) : this(new JaegerUdpBatcher(options)) { }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGet("/products", async httpContext => { var jaegerOptions = new JaegerExporterOptions() { ServiceName = "product-service", AgentHost = "localhost", AgentPort = 6831, }; using var tracerFactory = TracerFactory.Create(builder => builder .AddProcessorPipeline(c => c .SetExporter(new JaegerTraceExporter(jaegerOptions)))); var tracer = tracerFactory.GetTracer("product-service-tracer"); var context = tracer.TextFormat.Extract(httpContext.Request.Headers, (headers, name) => headers[name]); var incomingSpan = tracer.StartSpan("HTTP GET get products", context, SpanKind.Server); var products = new List <Product>(); products.Add(new Product { Id = Guid.NewGuid(), Name = "Product Name" }); incomingSpan.SetAttribute("products", JsonConvert.SerializeObject(products)); incomingSpan.End(); await httpContext.Response.WriteAsync(JsonConvert.SerializeObject(products)); }); endpoints.MapGet("/summary", async httpContext => { var config = httpContext.RequestServices.GetService <IConfiguration>(); var jaegerOptions = config.GetOptions <JaegerExporterOptions>("Jaeger"); using var tracerFactory = jaegerOptions.GetTracerFactory(); var tracer = tracerFactory.GetTracer("product-service-tracer"); var context = tracer.TextFormat.Extract(httpContext.Request.Headers, (headers, name) => headers[name]); var incomingSpan = tracer.StartSpan("HTTP GET get summary", context, SpanKind.Server); string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; var rng = new Random(); var summary = Summaries[rng.Next(Summaries.Length)]; incomingSpan.End(); await httpContext.Response.WriteAsync(summary); }); }); }