Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(#16) udpate tracing library #17

Merged
merged 1 commit into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/Nuar.Tracing/src/Nuar.Tracing/DefaultTracer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Reflection;
using Jaeger;
using Jaeger.Reporters;
using Jaeger.Samplers;
using OpenTracing;

namespace Nuar.Tracing
{
public class DefaultTracer
{
public static ITracer Create()
=> new Tracer.Builder(Assembly.GetEntryAssembly().FullName)
.WithReporter(new NoopReporter())
.WithSampler(new ConstSampler(false))
.Build();
}
}
59 changes: 59 additions & 0 deletions src/Nuar.Tracing/src/Nuar.Tracing/JaegerHTTPMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using OpenTracing;
using OpenTracing.Tag;
using System.Collections.Generic;

namespace Nuar.Extensions.Tracing
{
internal sealed class JaegerHttpMiddleware
{
private readonly RequestDelegate _next;

public JaegerHttpMiddleware(RequestDelegate next)
{
_next = next;
}

public async Task Invoke(HttpContext context, ITracer tracer)
{
IScope scope = null;
var span = tracer.ActiveSpan;
var method = context.Request.Method;

if (span == null)
{
var spanBuilder = tracer.BuildSpan($"HTTP {method}");
scope = spanBuilder.StartActive(true);
span = scope.Span;
}

span.Log(new Dictionary<string, object>
{
{ "event", "request_processing" },
{ "method", method },
{ "path", context.Request.Path.ToString() }
});

try
{
await _next(context);
}
catch (Exception ex)
{
span.SetTag(Tags.Error, true);
span.Log(new Dictionary<string, object>
{
{ "event", "error" },
{ "message", ex.Message }
});
throw;
}
finally
{
scope?.Dispose();
}
}
}
}
14 changes: 7 additions & 7 deletions src/Nuar.Tracing/src/Nuar.Tracing/Nuar.Tracing.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
<!-- <PackageReference Include="Jaeger" Version="1.0.3" /> -->

<PackageReference Include="Jaeger" Version="1.0.3" />
<PackageReference Include="Nuar" Version="*" />
<PackageReference Include="OpenTelemetry" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Exporter.Jaeger" Version="1.5.1" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
<PackageReference Include="OpenTracing.Contrib.NetCore" Version="0.9.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging " Version="8.0.0" />

</ItemGroup>

</Project>
92 changes: 58 additions & 34 deletions src/Nuar.Tracing/src/Nuar.Tracing/TracingExtension.cs
Original file line number Diff line number Diff line change
@@ -1,63 +1,87 @@
using System;
using System.Linq;
using Jaeger;
using Jaeger.Reporters;
using Jaeger.Samplers;
using Jaeger.Senders;
using Jaeger.Senders.Thrift;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using OpenTelemetry.Exporter;

using Nuar.Tracing;
using OpenTracing;
using OpenTracing.Contrib.NetCore.Configuration;
using OpenTracing.Util;

namespace Nuar.Extensions.Tracing
{
public class TracingExtension : IExtension
{
public string Name => "tracing";
public string Description => "Distributed tracing using OpenTelemetry and Jaeger";
public string Description => "Open Tracing using Jaeger";
public string Version => "1.0.0";

public void Add(IServiceCollection services, IOptionsProvider optionsProvider)
{
var options = optionsProvider.GetForExtension<TracingOptions>(Name);

var options = optionsProvider.GetForExtension<TracingOptions>("tracing");
services.AddOpenTracing();
services.AddSingleton(options);

// Use empty tracer if specified in options
if (options.UseEmptyTracer)
{
services.AddOpenTelemetry();
var defaultTracer = DefaultTracer.Create();
services.AddSingleton(defaultTracer);
return;
}


// Handle path exclusions if specified
if (options.ExcludePaths is not null)
{
services.Configure<AspNetCoreDiagnosticOptions>(o =>
{
foreach (var path in options.ExcludePaths)
{
o.Hosting.IgnorePatterns.Add(x => x.Request.Path == path);
}
});
}

services.AddSingleton<ITracer>(sp =>
{
var loggerFactory = sp.GetRequiredService<ILoggerFactory>();

var reporter = new RemoteReporter.Builder()
.WithSender(new UdpSender(options.UdpHost, options.UdpPort, options.MaxPacketSize))
.WithLoggerFactory(loggerFactory)
.Build();

var sampler = GetSampler(options);

var tracer = new Tracer.Builder(options.ServiceName)
.WithLoggerFactory(loggerFactory)
.WithReporter(reporter)
.WithSampler(sampler)
.Build();

GlobalTracer.Register(tracer);

return tracer;
});
}

public void Use(IApplicationBuilder app, IOptionsProvider optionsProvider)
{
// Middleware to ensure tracing is active
var logger = app.ApplicationServices.GetRequiredService<ILogger<TracingExtension>>();
logger.LogInformation("Tracing with OpenTelemetry and Jaeger has been configured.");
app.UseMiddleware<JaegerHttpMiddleware>();
}

private void ConfigureSampler(TracerProviderBuilder builder, TracingOptions options)
private static ISampler GetSampler(TracingOptions options)
{
// Use OpenTelemetry samplers instead of Jaeger's samplers
switch (options.Sampler?.ToLower())
return options.Sampler switch
{
case "const":
// Always sample
builder.SetSampler(new AlwaysOnSampler());
break;
case "probabilistic":
// Use the provided sampling rate
builder.SetSampler(new TraceIdRatioBasedSampler(options.SamplingRate));
break;

default:
// Default sampler: sample based on configuration
builder.SetSampler(new ParentBasedSampler(new TraceIdRatioBasedSampler(options.SamplingRate)));
break;
}
"const" => new ConstSampler(true),
"rate" => new RateLimitingSampler(options.MaxTracesPerSecond),
"probabilistic" => new ProbabilisticSampler(options.SamplingRate),
_ => new ConstSampler(true),
};
}
}
}
Loading