You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
description: Learn how to use a source generator to create metrics in .NET
4
+
ms.date: 04/11/2025
5
+
---
6
+
7
+
# Compile-time metric source generation
8
+
9
+
.NET's metering infrastructure is designed to deliver a highly usable and high-performance metering solution for modern .NET applications.
10
+
11
+
To use source-generated metering, create a class that defines the names and dimensions of the metrics your code can produce. Then, create the class with `partial` method signatures.
12
+
13
+
The source generator automatically generates the code, which exposes strongly typed metering types and methods that you can invoke to record metric values. The generated methods are implemented in a highly efficient form, which reduces computation overhead as compared to traditional metering solutions.
14
+
15
+
## Get started
16
+
17
+
To get started, install the [📦 Microsoft.Extensions.Telemetry.Abstractions](https://www.nuget.org/packages/Microsoft.Extensions.Telemetry.Abstractions) NuGet package:
For more information, see [dotnet add package](../tools/dotnet-package-add.md) or [Manage package dependencies in .NET applications](../tools/dependencies.md).
37
+
38
+
## Generic attributes
39
+
40
+
Generic attributes require C# 11 or later. For C# 10 or earlier, use nongeneric attributes instead.
41
+
42
+
The following example shows a class that declares three metrics. The methods are marked with an attribute and are declared as `static` and `partial`.
43
+
The code generator runs at build time and provides an implementation of these methods, along with accompanying
The dimensions specified in the attributes have been turned into arguments to the `Add` and `Record` methods. You then use the generated methods to create instances of these types. With the instancescreated, youcancall `Add` and `Record` toregistermetricvalues, asshowninthefollowingexample:
Formoreinformationonthesupportedmetrics, see [Typesofinstruments](metrics-instrumentation.md#types-of-instruments) tolearnhowtochoosewhichinstrumenttouseindifferentsituations.
@@ -11,95 +11,56 @@ Modern .NET applications can capture metrics using the <xref:System.Diagnostics.
11
11
> [!NOTE]
12
12
> In the context of metrics, a tag is sometimes also called a "dimension." This article uses "tag" for clarity and consistency with .NET metrics terminology.
13
13
14
-
## Tag name defaults and customization
15
-
16
-
By default, the source generator derives metric tag names from the field and property names of your tag class. In other words, each public field or property in the strongly-typed tag object becomes a tag name by default. You can override this by using the <xref:Microsoft.Extensions.Diagnostics.Metrics.TagNameAttribute> on a field or property to specify a custom tag name. In the examples below, you’ll see both approaches in action.
14
+
## Get started
17
15
18
-
## Example 1: Basic metric with a single tag
16
+
To get started, install the [📦 Microsoft.Extensions.Telemetry.Abstractions](https://www.nuget.org/packages/Microsoft.Extensions.Telemetry.Abstractions) NuGet package:
19
17
20
-
The following example demonstrates a simple counter metric with one tag. In this scenario, we want to count the number of processed requests and categorize them by a `Region` tag:
In the code above, `RequestTags` is a strongly-typed tag struct with a single property `Region`. The `CreateRequestCount` method is marked with <xref:Microsoft.Extensions.Diagnostics.Metrics.CounterAttribute`1> where `T` is an `int`, indicating it generates a **Counter** instrument that tracks `int` values. The attribute references `typeof(RequestTags)`, meaning the counter will use the tags defined in `RequestTags` when recording metrics. The source generator will produce a strongly-typed instrument class (named `RequestCount`) with an `Add` method that accepts integer value and `RequestTags` object.
24
+
### [PackageReference](#tab/package-reference)
36
25
37
-
To use the generated metric, create a <xref:System.Diagnostics.Metrics.Meter> and record measurements as shown below:
// Create a tag object with the relevant tag value
44
-
vartags=newRequestTags { Region="NorthAmerica" };
35
+
For more information, see [dotnet add package](../tools/dotnet-package-add.md) or [Manage package dependencies in .NET applications](../tools/dependencies.md).
45
36
46
-
// Record a metric value with the associated tag
47
-
requestCountMetric.Add(1, tags);
48
-
```
49
-
50
-
In this usage example, calling `MyMetrics.CreateRequestCount(meter)` creates a counter instrument (via the `Meter`) and returns a `RequestCount` metric object. When you call `requestCountMetric.Add(1, tags)`, the metric system records a count of 1 associated with the tag `Region="NorthAmerica"`. You can reuse the `RequestTags` object or create new ones to record counts for different regions, and the tag name `Region` will consistently be applied to every measurement.
37
+
## Tag name defaults and customization
51
38
52
-
## Example 2: Metric with nested tag objects
39
+
By default, the source generator derives metric tag names from the field and property names of your tag class. In other words, each public field or property in the strongly-typed tag object becomes a tag name by default. You can override this by using the <xref:Microsoft.Extensions.Diagnostics.Metrics.TagNameAttribute> on a field or property to specify a custom tag name. In the examples below, you’ll see both approaches in action.
53
40
54
-
For more complex scenarios, you can define tag classes that include multiple tags, nested objects, or even inherited properties. This allows a group of related metrics to share a common set of tags easily. In the next example, we define a set of tag classes and use them for three different metrics:
41
+
## Example 1: Basic metric with a single tag
55
42
56
-
```csharp
57
-
publicclassMetricTags : MetricParentTags
58
-
{
59
-
[TagName("Dim1DimensionName")]
60
-
publicstring? Dim1; // custom tag name via attribute
43
+
The following example demonstrates a simple counter metric with one tag. In this scenario, we want to count the number of processed requests and categorize them by a `Region` tag:
61
44
62
-
publicOperationsOperation { get; set; } // tag name defaults to "Operation"
In the preceding code, `RequestTags` is a strongly-typed tag struct with a single property `Region`. The `CreateRequestCount` method is marked with <xref:Microsoft.Extensions.Diagnostics.Metrics.CounterAttribute`1> where `T` is an `int`, indicating it generates a `Counter` instrument that tracks `int` values. The attribute references `typeof(RequestTags)`, meaning the counter uses the tags defined in `RequestTags` when recording metrics. The source generator produces a strongly-typed instrument class (named `RequestCount`) with an `Add` method that accepts integer value and `RequestTags` object.
66
48
67
-
publicenumOperations
68
-
{
69
-
Unknown=0,
70
-
Operation1=1,
71
-
}
49
+
To use the generated metric, create a <xref:System.Diagnostics.Metrics.Meter> and record measurements as shown below:
72
50
73
-
publicclassMetricParentTags
74
-
{
75
-
[TagName("DimensionNameOfParentOperation")]
76
-
publicstring? ParentOperationName { get; set; } // custom tag name via attribute
51
+
:::code language="csharp" source="snippets/MetricsGen/MyClass.cs" id ="tag":::
In this usage example, calling `MyMetrics.CreateRequestCount(meter)` creates a counter instrument (via the `Meter`) and returns a `RequestCount` metric object. When you call `requestCountMetric.Add(1, tags)`, the metric system records a count of 1 associated with the tag `Region="NorthAmerica"`. You can reuse the `RequestTags` object or create new ones to record counts for different regions, and the tag name `Region` will consistently be applied to every measurement.
80
54
81
-
publicclassMetricChildTags
82
-
{
83
-
publicstring? Dim2 { get; set; } // tag name defaults to "Dim2"
84
-
}
55
+
## Example 2: Metric with nested tag objects
85
56
86
-
publicstructMetricTagsStruct
87
-
{
88
-
publicstringDim3 { get; set; } // tag name defaults to "Dim3"
89
-
}
57
+
For more complex scenarios, you can define tag classes that include multiple tags, nested objects, or even inherited properties. This allows a group of related metrics to effectively share a common set of tags. In the next example, you define a set of tag classes and use them for three different metrics:
The preceding code defines the metric inheritance and object shapes. The following code demonstrates how to use these shapes with the generator, as shown in the `Metric` class:
In this example, `MetricTags` is a tag class that inherits from `MetricParentTags` and also contains a nested tag object (`MetricChildTags`) and a nested struct (`MetricTagsStruct`). The tag properties demonstrate both default and customized tag names:
105
66
@@ -113,55 +74,7 @@ All three metric definitions `CreateLatency`, `CreateTotalCount`, and `CreateTot
113
74
114
75
The following code shows how to create and use these metrics in a class:
115
76
116
-
```csharp
117
-
internalclassMyClass
118
-
{
119
-
privatereadonlyLatency_latencyMetric;
120
-
privatereadonlyTotalCount_totalCountMetric;
121
-
privatereadonlyTotalFailures_totalFailuresMetric;
122
-
123
-
publicMyClass(Metermeter)
124
-
{
125
-
// Create metric instances using the source-generated factory methods
:::code language="csharp" source="snippets/MetricsGen/MyClass.cs" id ="creationwithtags":::
165
78
166
79
In the preceding `MyClass.DoWork` method, a `MetricTags` object is populated with values for each tag. This single `tags` object is then passed to all three instruments when recording data. The `Latency` metric (a histogram) records the elapsed time, and both counters (`TotalCount` and `TotalFailures`) record occurrence counts. Because all metrics share the same tag object type, the tags (`Dim1DimensionName`, `Operation`, `Dim2`, `Dim3`, `DimensionNameOfParentOperation`) are present on every measurement.
167
80
@@ -184,6 +97,7 @@ Adhering to these requirements ensures that the source generator can successfull
184
97
185
98
## See also
186
99
100
+
-[Source generated metrics in .NET](metrics-generator.md)
187
101
-[Creating metrics in .NET (Instrumentation tutorial)](metrics-instrumentation.md)
188
102
-[Collecting metrics in .NET (Using MeterListener and exporters)](metrics-collection.md)
189
103
-[Logging source generation in .NET](../extensions/logger-message-generator.md) (for a similar source-generation approach applied to logging)
0 commit comments