Extensions.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. using Microsoft.AspNetCore.Builder;
  2. using Microsoft.AspNetCore.Diagnostics.HealthChecks;
  3. using Microsoft.Extensions.DependencyInjection;
  4. using Microsoft.Extensions.Diagnostics.HealthChecks;
  5. using Microsoft.Extensions.Logging;
  6. using Microsoft.Extensions.ServiceDiscovery;
  7. using OpenTelemetry;
  8. using OpenTelemetry.Metrics;
  9. using OpenTelemetry.Trace;
  10. namespace Microsoft.Extensions.Hosting;
  11. // Adds common Aspire services: service discovery, resilience, health checks, and OpenTelemetry.
  12. // This project should be referenced by each service project in your solution.
  13. // To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults
  14. public static class Extensions
  15. {
  16. private const string HealthEndpointPath = "/health";
  17. private const string AlivenessEndpointPath = "/alive";
  18. public static TBuilder AddServiceDefaults<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
  19. {
  20. builder.ConfigureOpenTelemetry();
  21. builder.AddDefaultHealthChecks();
  22. builder.Services.AddServiceDiscovery();
  23. builder.Services.ConfigureHttpClientDefaults(http =>
  24. {
  25. // Turn on resilience by default
  26. http.AddStandardResilienceHandler();
  27. // Turn on service discovery by default
  28. http.AddServiceDiscovery();
  29. });
  30. // Uncomment the following to restrict the allowed schemes for service discovery.
  31. // builder.Services.Configure<ServiceDiscoveryOptions>(options =>
  32. // {
  33. // options.AllowedSchemes = ["https"];
  34. // });
  35. return builder;
  36. }
  37. public static TBuilder ConfigureOpenTelemetry<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
  38. {
  39. builder.Logging.AddOpenTelemetry(logging =>
  40. {
  41. logging.IncludeFormattedMessage = true;
  42. logging.IncludeScopes = true;
  43. });
  44. builder.Services.AddOpenTelemetry()
  45. .WithMetrics(metrics =>
  46. {
  47. metrics.AddAspNetCoreInstrumentation()
  48. .AddHttpClientInstrumentation()
  49. .AddRuntimeInstrumentation();
  50. })
  51. .WithTracing(tracing =>
  52. {
  53. tracing.AddSource(builder.Environment.ApplicationName)
  54. .AddAspNetCoreInstrumentation(tracing =>
  55. // Exclude health check requests from tracing
  56. tracing.Filter = context =>
  57. !context.Request.Path.StartsWithSegments(HealthEndpointPath)
  58. && !context.Request.Path.StartsWithSegments(AlivenessEndpointPath)
  59. )
  60. // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package)
  61. //.AddGrpcClientInstrumentation()
  62. .AddHttpClientInstrumentation();
  63. });
  64. builder.AddOpenTelemetryExporters();
  65. return builder;
  66. }
  67. private static TBuilder AddOpenTelemetryExporters<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
  68. {
  69. var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
  70. if (useOtlpExporter)
  71. {
  72. builder.Services.AddOpenTelemetry().UseOtlpExporter();
  73. }
  74. // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package)
  75. //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]))
  76. //{
  77. // builder.Services.AddOpenTelemetry()
  78. // .UseAzureMonitor();
  79. //}
  80. return builder;
  81. }
  82. public static TBuilder AddDefaultHealthChecks<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
  83. {
  84. builder.Services.AddHealthChecks()
  85. // Add a default liveness check to ensure app is responsive
  86. .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
  87. return builder;
  88. }
  89. public static WebApplication MapDefaultEndpoints(this WebApplication app)
  90. {
  91. // Adding health checks endpoints to applications in non-development environments has security implications.
  92. // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments.
  93. if (app.Environment.IsDevelopment())
  94. {
  95. // All health checks must pass for app to be considered ready to accept traffic after starting
  96. app.MapHealthChecks(HealthEndpointPath);
  97. // Only health checks tagged with the "live" tag must pass for app to be considered alive
  98. app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions
  99. {
  100. Predicate = r => r.Tags.Contains("live")
  101. });
  102. }
  103. return app;
  104. }
  105. }