|
| 1 | +--- |
| 2 | +title: Source-generated metrics |
| 3 | +description: Learn how to use a source generator to create metrics in .NET |
| 4 | +ms.date: 04/11/2025 |
| 5 | +--- |
| 6 | + |
| 7 | +# Source generated metering |
| 8 | + |
| 9 | +.NET's metering infrastructure is designed to deliver a highly-usable and high-performance metering solution |
| 10 | +for modern .NET applications. |
| 11 | + |
| 12 | +To use source generated metering, you first create a class that defines the names and dimensions of the metrics your code can produce. |
| 13 | +Then you need to create the class with partial methods signatures. |
| 14 | + |
| 15 | +Then, the .NET's code generator automatically generates the code, which exposes strongly-typed metering types and |
| 16 | +methods that you can invoke to record metric values. The generated methods are implemented in a highly efficient |
| 17 | +form, which reduces computation overhead as compared to traditional metering solutions. |
| 18 | + |
| 19 | +## Install the package |
| 20 | + |
| 21 | +To get started, install the [📦 Microsoft.Extensions.Telemetry.Abstractions](https://www.nuget.org/packages/Microsoft.Extensions.Telemetry.Abstractions) NuGet package: |
| 22 | + |
| 23 | +### [.NET CLI](#tab/dotnet-cli) |
| 24 | + |
| 25 | +```dotnetcli |
| 26 | +dotnet add package Microsoft.Extensions.Telemetry.Abstractions |
| 27 | +``` |
| 28 | + |
| 29 | +### [PackageReference](#tab/package-reference) |
| 30 | + |
| 31 | +```xml |
| 32 | +<ItemGroup> |
| 33 | + <PackageReference Include="Microsoft.Extensions.Telemetry.Abstractions" |
| 34 | + Version="*" /> |
| 35 | +</ItemGroup> |
| 36 | +``` |
| 37 | + |
| 38 | +--- |
| 39 | + |
| 40 | +## Generic attributes |
| 41 | + |
| 42 | +Generic attributes are only supported in C# 11 or later, so if you are using generic attributes then please enable C# 11 or later. |
| 43 | +Please use non generic attributes if you are using C# 10 or earlier. |
| 44 | + |
| 45 | +## Usage |
| 46 | + |
| 47 | +The following example shows a class that declares two metrics. The methods are marked with an attribute and are declared as `static` and `partial`. |
| 48 | +The code generator runs at build time and provides an implementation of these methods, along with accompanying |
| 49 | +types. |
| 50 | + |
| 51 | +```csharp |
| 52 | +using System.Diagnostics.Metrics; |
| 53 | +using Microsoft.Extensions.Diagnostics.Metrics; |
| 54 | + |
| 55 | +internal class MetricConstants |
| 56 | +{ |
| 57 | + public const string EnvironmentName = "env"; |
| 58 | + public const string Region = "region"; |
| 59 | + public const string RequestName = "requestName"; |
| 60 | + public const string RequestStatus = "requestStatus"; |
| 61 | +} |
| 62 | + |
| 63 | +internal static partial class Metric |
| 64 | +{ |
| 65 | + // an explicit metric name is given |
| 66 | + [Histogram<long>("requestName", "duration", Name = "MyCustomMetricName")] |
| 67 | + public static partial Latency CreateLatency(Meter meter); |
| 68 | + |
| 69 | + // no explicit metric name given, it is auto-generated from the method name |
| 70 | + [Counter<int>(MetricConstants.EnvironmentName, MetricConstants.Region, MetricConstants.RequestName, MetricConstants.RequestStatus)] |
| 71 | + public static partial TotalCount CreateTotalCount(Meter meter); |
| 72 | + |
| 73 | + [Counter<int>] |
| 74 | + public static partial TotalFailures CreateTotalFailures(Meter meter); |
| 75 | +} |
| 76 | +``` |
| 77 | + |
| 78 | +The previous declaration automatically returns the following: |
| 79 | + |
| 80 | +- `Latency` class with a `Record` method |
| 81 | +- `TotalCount` class with an `Add` method |
| 82 | +- `TotalFailures` class with a `Add` method. |
| 83 | + |
| 84 | +The attributes indicate the set of dimensions that each metric uses. The signature for the generated types looks like this: |
| 85 | + |
| 86 | +```csharp |
| 87 | +internal class TotalCount |
| 88 | +{ |
| 89 | + public void Add(int value, object? env, object? region, object? requestName, object? requestStatus) |
| 90 | +} |
| 91 | + |
| 92 | +internal TotalFailures |
| 93 | +{ |
| 94 | + public void Add(int value) |
| 95 | +} |
| 96 | + |
| 97 | +internal class Latency |
| 98 | +{ |
| 99 | + public void Record(long value, object? requestName, object? duration); |
| 100 | +} |
| 101 | +``` |
| 102 | + |
| 103 | +The dimensions specified in the attributes have been turned into arguments to the `Add` and `Record` methods. |
| 104 | +You then use the generated methods to create instances of these types. With the instances created, |
| 105 | +you can call `Add` and `Record` to register metric values, like this: |
| 106 | + |
| 107 | +```csharp |
| 108 | +internal class MyClass |
| 109 | +{ |
| 110 | + private readonly Latency _latencyMetric; |
| 111 | + private readonly TotalCount _totalCountMetric; |
| 112 | + private readonly TotalFailures _totalFailuresMetric; |
| 113 | + |
| 114 | + public MyClass(Meter meter) |
| 115 | + { |
| 116 | + // Create metric instances using the source-generated factory methods |
| 117 | + _latencyMetric = Metric.CreateLatency(meter); |
| 118 | + _totalCountMetric = Metric.CreateTotalCount(meter); |
| 119 | + _totalFailuresMetric = Metric.CreateTotalFailures(meter); |
| 120 | + } |
| 121 | + |
| 122 | + public void ReportSampleRequestCount() |
| 123 | + { |
| 124 | + // method logic ... |
| 125 | +
|
| 126 | + // Invoke Add on the counter and pass the dimension values. |
| 127 | + _totalCountMetric.Add(1, envName, regionName, requestName, status); |
| 128 | + } |
| 129 | + |
| 130 | + public void ReportSampleLatency() |
| 131 | + { |
| 132 | + // method logic ... |
| 133 | +
|
| 134 | + // Invoke Record on the histogram and pass the dimension values. |
| 135 | + _latencyMetric.Record(1, requestName, duration); |
| 136 | + } |
| 137 | + |
| 138 | + public void ReportSampleFailuresCount() |
| 139 | + { |
| 140 | + // method logic ... |
| 141 | +
|
| 142 | + // Invoke Add on the counter and pass the dimension values. |
| 143 | + _totalFailuresMetric.Add(1); |
| 144 | + } |
| 145 | +} |
| 146 | +``` |
| 147 | + |
| 148 | +## Metric methods requirements |
| 149 | + |
| 150 | +Metric methods have some constraints that you must follow: |
| 151 | + |
| 152 | +- They must be static, partial, and public. |
| 153 | +- The return type must be unique. |
| 154 | +- Their names must not start with an underscore. |
| 155 | +- Their parameter names must not start with an underscore. |
| 156 | +- Their first parameter must be `Meter`. |
| 157 | +- They can't be generic or accept any generic parameters. |
| 158 | + |
| 159 | +## Supported metrics |
| 160 | + |
| 161 | +Please refer to the .NET [`Types of instruments`](https://learn.microsoft.com/dotnet/core/diagnostics/metrics-instrumentation#types-of-instruments) to learn about all the supported instruments and description on how to choose which instrument to use in different situations. |
0 commit comments