How to integrate Opentelemetry with Quartz.net in Worker
2024-05-08 05:57:49
#Opentelemetry
在 .NET Core 的 Worker 类型项目中,Opentelemetry 并没有为其提供标准的 Instrumentation
,如果我们的项目中以 Quartz.net
作为我们默认的 Schedule Engine 的话,这个时候就需要考虑需要如何将两者即成到一起。
安装依赖包 1 2 3 4 dotnet add package Quartz.Extensions.Hosting dotnet add package OpenTelemetry.Extensions.Hosting dotnet add package OpenTelemetry.Exporter.Console dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
集成示例
下面是完整的示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class JobListener : IJobListener { private readonly ActivitySource _activitySource; private readonly IDatetimeProvider _datetimeProvider; public string Name { get ; } public JobListener ( IOptions<DiagnosticsConfiguration> configuration, IHostEnvironment hostEnvironment, IDatetimeProvider datetimeProvider ) { var envName = hostEnvironment.EnvironmentName; var serviceName = $"{envName} -{configuration.Value.ServiceName} " ; _activitySource = new ActivitySource(serviceName); _datetimeProvider = datetimeProvider; Name = GetType().Name; } public Task JobToBeExecuted (IJobExecutionContext context, CancellationToken cancellationToken = new CancellationToken( )) { using var activity = _activitySource.StartActivity($"{context.JobDetail.JobType.Name} .JobToBeExecuted" ); activity?.SetStatus(ActivityStatusCode.Unset); activity?.SetStartTime(_datetimeProvider.Now()); return Task.CompletedTask; } public Task JobExecutionVetoed (IJobExecutionContext context, CancellationToken cancellationToken = new CancellationToken( )) { return Task.CompletedTask; } public Task JobWasExecuted (IJobExecutionContext context, JobExecutionException? jobException, CancellationToken cancellationToken = new CancellationToken( )) { using var activity = _activitySource.StartActivity($"{context.JobDetail.JobType.Name} .JobWasExecuted" ); activity?.SetStatus(jobException == null ? ActivityStatusCode.Ok : ActivityStatusCode.Error); activity?.SetEndTime(_datetimeProvider.Now()); return Task.CompletedTask; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public static class QuartzJobExtensions { public static void AddJobWithTrigger <T >(this IServiceCollectionQuartzConfigurator configurator, string cronExpression ) where T : IJob { var jobKey = new JobKey(typeof (T).Name); configurator.AddJob<T>(opts => opts.WithIdentity(jobKey)); configurator.AddTrigger(opts => opts .ForJob(jobKey) .WithIdentity($"{jobKey.Name} -trigger" ) .WithCronSchedule(cronExpression)); } }
1 2 3 4 5 6 7 8 9 10 11 builder.Services.AddQuartz(q => { q.UseJobFactory<MicrosoftDependencyInjectionJobFactory>(); q.AddJobListener<JobListener>(); q.AddJobWithTrigger<HelloWorldJob>("0/2 * * * * ?" ); }).AddQuartzHostedService( q => { q.WaitForJobsToComplete = true ; q.StartDelay = TimeSpan.FromSeconds(0 ); });
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 private static void AddOpenTelemetry ( this IServiceCollection services, IConfiguration configuration, IHostEnvironment environment ){ services.AddOpenTelemetry() .WithTracing(tracerProviderBuilder => { var openTelemetryConfig = new DiagnosticsConfiguration(); configuration.GetSection("OpenTelemetry" ).Bind(openTelemetryConfig); var envName = environment.EnvironmentName; var serviceName = $"{envName} -{openTelemetryConfig.ServiceName} " ; tracerProviderBuilder.ConfigureServices(serviceCollection => { services.AddOptions<DiagnosticsConfiguration>().Bind(configuration.GetSection("OpenTelemetry" )).ValidateDataAnnotations(); }); tracerProviderBuilder .AddSource(serviceName) .ConfigureResource(resource => resource .AddService(serviceName, openTelemetryConfig.ServiceNamespace) .AddAttributes(new KeyValuePair<string , object >[] { new ("deployment.environment" , envName) })); if (environment.IsDevelopment()) { tracerProviderBuilder.AddConsoleExporter(); } else { tracerProviderBuilder.AddOtlpExporter(options => { options.Endpoint = new Uri(openTelemetryConfig.OtlpUrl); options.Protocol = OtlpExportProtocol.HttpProtobuf; }); } } ); }