From e1edded9750c7656b9c35b16ee53125a1d6c8469 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Tue, 29 Aug 2023 11:55:19 +0800 Subject: [PATCH] Add IMeterFactory best practice to ASP.NET Core metrics (#30073) Co-authored-by: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com> --- aspnetcore/log-mon/metrics/metrics.md | 49 +++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/aspnetcore/log-mon/metrics/metrics.md b/aspnetcore/log-mon/metrics/metrics.md index 6a8c7e4bd0..9cc7dde291 100644 --- a/aspnetcore/log-mon/metrics/metrics.md +++ b/aspnetcore/log-mon/metrics/metrics.md @@ -91,7 +91,52 @@ For more information, see [dotnet-counters](/dotnet/core/diagnostics/dotnet-coun ## Create custom metrics -See [Create custom metrics](/dotnet/core/diagnostics/metrics#create-custom-metrics) for information on creating custom metrics. +Metrics are created using APIs in the namespace. See [Create custom metrics](/dotnet/core/diagnostics/metrics-instrumentation#create-a-custom-metric) for information on creating custom metrics. + +### Creating metrics in ASP.NET Core apps with `IMeterFactory` + +We recommended creating `Meter` instances in ASP.NET Core apps with . + +ASP.NET Core registers in dependency injection (DI) by default. The meter factory integrates metrics with DI, making isolating and collecting metrics easy. `IMeterFactory` is especially useful for testing. It allows for multiple tests to run side-by-side and only collecting metrics values that are recorded in a test. + +To use `IMeterFactory` in an app, create a type that uses `IMeterFactory` to create the app's custom metrics: + +```cs +public class ContosoMetrics +{ + private readonly Counter _productSoldCounter; + + public ContosoMetrics(IMeterFactory meterFactory) + { + var meter = meterFactory.CreateMeter("Contoso.Web"); + _productSoldCounter = meter.CreateCounter("contoso.product.sold"); + } + + public void ProductSold(string productName, int quantity) + { + _productSoldCounter.Add(quantity, + new KeyValuePair("contoso.product.name", productName)); + } +} +``` + +Register the metrics type with DI in `Program.cs`: + +```cs +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddSingleton(); +``` + +Inject the metrics type and record values where needed. Because the metrics type is registered in DI it can be use with MVC controllers, minimal APIs, or any other type that is created by DI: + +```cs +app.MapPost("/complete-sale", ([FromBody] SaleModel model, ContosoMetrics metrics) => +{ + // ... business logic such as saving the sale to a database ... + + metrics.ProductSold(model.QuantitySold, model.ProductName); +}); +``` ## View metrics in Grafana with OpenTelemetry and Prometheus @@ -208,7 +253,7 @@ The proceeding test: * Bootstraps a web app in memory with . `Program` in the factory's generic argument specifies the web app. * Collects metrics values with . * Requires a package reference to `Microsoft.Extensions.Telemetry.Testing`. - * The `MetricCollector` is created using the web app's `IMeterFactory`. This allows the collector to only report metrics values recorded by test. + * The `MetricCollector` is created using the web app's . This allows the collector to only report metrics values recorded by test. * Includes the meter name, `Microsoft.AspNetCore.Hosting`, and counter name, `http.server.request.duration` to collect. * Makes an HTTP request to the web app. * Asserts the test using results from the metrics collector.