Code Monkey home page Code Monkey logo

dotnet-core-7-open-telemetry-lab's Introduction

DotNet Core 7 OpenTelemetry Lab

此專案用以了解如何在 .Net Core 7 中透過 OpenTelemetry 建立日誌、指標與追蹤,並暴露到 Prometheus 中。

請注意,OpenTelemetry 雖然目前在開源社群非常活躍,但對於 .Net Core 來說,它的相關 SDK 有很多都還是搶鮮版,因此若要應用到生產環境中,請審慎評估。

前置準備

  • NuGet 套件
    • OpenTelemetry
    • OpenTelemetry.Exporter.Console

      將日誌輸出到終端機

    • OpenTelemetry.Exporter.Prometheus.AspNetCore (搶鮮版)

      將指標輸出到指定的路徑,並使用 Prometheus 格式輸出

    • OpenTelemetry.Exporter.OpenTelemetryProtocol
    • OpenTelemetry.Extensions.Hosting
    • OpenTelemetry.Instruumentation.AspNetCore
    • OpenTelemetry.Instrumentation.Http
    • OpenTelemetry.Instrumentation.Process

      輸出 CPU、記憶體等指標資料

    • OpenTelemetry.Instrumentation.Runtime

      輸出 GC 等資料

並在 Extensions 資料夾中新增 OpenTelemetryExtension.cs 檔案,寫入如下的內容

public static class OpenTelemetryExtension
{
    public static Meter openTelemetryMeter = new Meter("dotnet7.core.telemetry", "1.0.0");
    public static IServiceCollection ConfigureOpenTelemetry(
        ILoggingBuilder loggingBuilder,
        IServiceCollection serviceCollection,
        IConfiguration config)
    {
        string? applicationName = config.GetValue<string>("Application:Name");
        if (applicationName == null)
        {
            applicationName = "OpenTelemetry.Lab";
        }

        string? otlpTargetUri = config.GetValue(
            "OpenTelemetry:OtlpUri",
            "http://localhost:4318");
        if (otlpTargetUri == null)
        {
            otlpTargetUri = "http://localhost:4318";
        }

        var resource = ResourceBuilder.CreateDefault().AddService(applicationName);
        // 設定僅輸出警告日誌
        // loggingBuilder.AddFilter<OpenTelemetryLoggerProvider>("*", LogLevel.Warning);
        loggingBuilder.AddOpenTelemetry(options =>
        {
            options.SetResourceBuilder(resource);
            options.AddConsoleExporter();
        });

        serviceCollection.AddOpenTelemetry()
            .ConfigureResource(resource => resource
                .AddService(serviceName: applicationName))
            .WithMetrics(metrics => metrics
                .AddMeter(openTelemetryMeter.Name)
                .AddAspNetCoreInstrumentation()
                .AddRuntimeInstrumentation()
                .AddProcessInstrumentation()
                .AddPrometheusExporter()
                .AddConsoleExporter()
                .AddPrometheusExporter())
            .WithTracing(tracing => tracing
                .AddAspNetCoreInstrumentation()
                .AddConsoleExporter())
            .UseOtlpExporter(
                OtlpExportProtocol.HttpProtobuf,
                new Uri(otlpTargetUri));

        return serviceCollection;
    }
}

最後到 Program.cs 中調整程式碼:

...
var builder = WebApplication.CreateBuilder(args);
...
SwaggerDefinitionExtension.ConfigureSwagger(builder.Services);
ServiceMapperExtension.GetServiceProvider(builder.Services);
DatabaseExtension.AddDatabaseContext(builder.Services, builder.Configuration);
AuthorizationExtension.ConfigureAuthorization(builder.Services, builder.Configuration);
HttpClientExtension.ConfigureHttpClients(builder.Services);
// 增加 OpenTelemetryExtension
OpenTelemetryExtension.ConfigureOpenTelemetry(builder.Logging, builder.Services, builder.Configuration);
...
app.UseHttpsRedirection();

app.UseAuthorization();

app.UseRouting();

// 設定 OpenTelemetry 輸出 Prometheus 指標的路徑
app.UseOpenTelemetryPrometheusScrapingEndpoint(context =>
    context.Request.Path == "/metrics");

日誌撰寫

請注意,所有的日誌輸出都應使用結構化日誌進行輸出,這類格式的日誌對於後續系統自動化分析才有意義。

  1. 在 Extensions 資料夾新增 ILoggerExtension.cs,並加入以下程式碼:

    這個主要在做結構化日誌的設定,不一定要透過這種方式輸出日誌

    internal static partial class LoggerExtensions
    {
        /// <summary>
        /// 啟動應用程式的日誌
        /// </summary>
        /// <param name="logger"></param>
        [LoggerMessage(LogLevel.Information, "Starting the app...")]
        public static partial void StartingApp(this ILogger logger);
    
        /// <summary>
        /// 取得天氣預報的日誌,其中包含請求的使用者名稱
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="userName">使用者名稱</param>
        [LoggerMessage(LogLevel.Information, "Requesting all weather forcast results, user name is `{userName}`.")]
        public static partial void RetrievingWeatherForecast(this ILogger logger, string userName);
    }
  2. 在專案任意地方注入 ILogger 介面後,透過 ILogger 去呼叫第一步中定義的方法輸入日誌。

  3. 若需要調整日誌輸出的嚴重性設定,可以到 OpenTelemetryExtension 中設定只輸出哪些嚴重性的日誌。

  4. 若需要針對日誌做後處理或前處理,可以自行新增一 LogProcessor,如下範例是一個日誌後處理,可以在結束時輸出 Hello - OnEnd 日誌:

    1. 新增 LogProcessor

      public class LogProcessor : BaseProcessor<LogRecord>
      {
          public override void OnEnd(LogRecord data)
          {
              Console.WriteLine("Hello - OnEnd");
              base.OnEnd(data);
          }
      }
    2. 調整 OpenTelemetryExtension.cs 中日誌的設定,加入以下邏輯:

      loggingBuilder.AddOpenTelemetry(options =>
      {
          options.SetResourceBuilder(resource);
          options.AddConsoleExporter();
          options.AddProcessor(new LogProcessor());
          options.IncludeFormattedMessage = true;
          options.ParseStateValues = true;
      });
    3. 重新啟動應用程式,並試著打看看 API,就會看到終端機輸出 Hello - OnEnd 字樣的日誌了。

指標撰寫

  1. 預期指標都會透過 Middleware 進行記錄,因此需建立 OpenTelemetryMiddleware,並在檔案中鍵入以下程式碼:

    Meter 不建議建立太多,這會影響應用程式的效能,因此最好的方式就是在 OpenTelemetryExtension 中建立後,這邊直接引用該 Meter 即可

    using System.Diagnostics.Metrics;
    
    namespace DotNet7.Template.Api.Middlewares
    {
        public class OpenTelemetryMiddleware
        {
            private readonly RequestDelegate _next;
            private Counter<int> _greetingCounter;
    
            public OpenTelemetryMiddleware(RequestDelegate next)
            {
                _next = next;
                // 引用 OpenTelemetryExtension 中的 Meter 建立自訂指標
                _greetingCounter = OpenTelemetryExtension.openTelemetryMeter.CreateCounter<int>(
                    "greetings.count",
                    description: "Counts the number of greetings.");
            }
    
            public async Task Invoke(HttpContext context)
            {
                await _next(context);
                _greetingCounter.Add(1);
            }
        }
    }
  2. MiddlewareExtension.cs 中調整為程式碼:

    public static class MiddlewareExtension
    {
        public static IApplicationBuilder ConfigureMiddlewares(this IApplicationBuilder builder)
        {
            // 套用 OpenTelemetryMiddleware
            builder.UseMiddleware<OpenTelemetryMiddleware>();
    
            return builder;
        }
    }
  3. 在到 Program.cs 中確認下面的程式碼有沒有被啟用

    ...
    var app = builder.Build();
    
    // 套用 Middlewares
    app.ConfigureMiddlewares();
    ...
  4. 啟動應用程式,存取 /metrics 就可以看到 Prometheus 格式的指標被輸出在頁面上

    若沒看到自訂的指標,請先試著打幾次 API,當流量經過 Middleware 後,這些指標就會被暴露出來了

撰寫追蹤

OpenTelemetry 在 .Net Core 中的追蹤實作是依賴於 .Net Core 內建的 System.Diagnostics API,因此若希望使用 OpenTelemetry API 實作追蹤,請參閱 OpenTelemetry API Shim 文件

參考資料

dotnet-core-7-open-telemetry-lab's People

Contributors

samuikaze avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.