diff --git a/src/Generators/Microsoft.Gen.Metrics/MetricFactoryEmitter.cs b/src/Generators/Microsoft.Gen.Metrics/MetricFactoryEmitter.cs index 531095d0c85..76c6db3ef9d 100644 --- a/src/Generators/Microsoft.Gen.Metrics/MetricFactoryEmitter.cs +++ b/src/Generators/Microsoft.Gen.Metrics/MetricFactoryEmitter.cs @@ -146,7 +146,15 @@ private void GenMetricFactoryMethods(MetricMethod metricMethod, string nspace) OutOpenBrace(); OutLn($"return {GetMetricDictionaryName(metricMethod)}.GetOrAdd({meterParam.Name}, static _meter =>"); OutLn(" {"); - OutLn($" var instrument = _meter.{createMethodName}(@\"{metricMethod.MetricName}\");"); + if (string.IsNullOrEmpty(metricMethod.MetricUnit)) + { + OutLn($" var instrument = _meter.{createMethodName}(@\"{metricMethod.MetricName}\");"); + } + else + { + OutLn($" var instrument = _meter.{createMethodName}(@\"{metricMethod.MetricName}\", @\"{metricMethod.MetricUnit}\");"); + } + OutLn($" return new {nsprefix}{metricMethod.MetricTypeName}(instrument);"); OutLn(" });"); OutCloseBrace(); diff --git a/src/Generators/Microsoft.Gen.Metrics/Model/MetricMethod.cs b/src/Generators/Microsoft.Gen.Metrics/Model/MetricMethod.cs index 8a2db1ed8ff..dc5f45b1bad 100644 --- a/src/Generators/Microsoft.Gen.Metrics/Model/MetricMethod.cs +++ b/src/Generators/Microsoft.Gen.Metrics/Model/MetricMethod.cs @@ -12,6 +12,7 @@ internal sealed class MetricMethod public Dictionary TagDescriptionDictionary = []; public string? Name; public string? MetricName; + public string? MetricUnit; public string? XmlDefinition; public bool IsExtensionMethod; public string Modifiers = string.Empty; diff --git a/src/Generators/Microsoft.Gen.Metrics/Parser.cs b/src/Generators/Microsoft.Gen.Metrics/Parser.cs index 680bf579f2c..25c2b33b3e9 100644 --- a/src/Generators/Microsoft.Gen.Metrics/Parser.cs +++ b/src/Generators/Microsoft.Gen.Metrics/Parser.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Text; using System.Text.RegularExpressions; @@ -273,13 +274,14 @@ private static bool TryGetTagNameFromAttribute(ISymbol symbol, SymbolHolder symb return false; } - private (string metricName, HashSet tagNames, Dictionary dimensionDescriptions) ExtractAttributeParameters( + private (string metricName, string metricUnit, HashSet tagNames, Dictionary dimensionDescriptions) ExtractAttributeParameters( AttributeData attribute, SemanticModel semanticModel) { var tagHashSet = new HashSet(); var tagDescriptionMap = new Dictionary(); string metricNameFromAttribute = string.Empty; + string metricUnitFromAttribute = string.Empty; if (!attribute.NamedArguments.IsDefaultOrEmpty) { foreach (var arg in attribute.NamedArguments) @@ -288,7 +290,11 @@ private static bool TryGetTagNameFromAttribute(ISymbol symbol, SymbolHolder symb arg.Key is "MetricName" or "Name") { metricNameFromAttribute = (arg.Value.Value ?? string.Empty).ToString().Replace("\\\\", "\\"); - break; + } + else if (arg.Value.Kind == TypedConstantKind.Primitive && + arg.Key is "Unit") + { + metricUnitFromAttribute = (arg.Value.Value ?? string.Empty).ToString(); } } } @@ -330,7 +336,7 @@ private static bool TryGetTagNameFromAttribute(ISymbol symbol, SymbolHolder symb } } - return (metricNameFromAttribute, tagHashSet, tagDescriptionMap); + return (metricNameFromAttribute, metricUnitFromAttribute, tagHashSet, tagDescriptionMap); } private string GetSymbolXmlCommentSummary(ISymbol symbol) @@ -422,20 +428,20 @@ private void GetTagDescription( if (!methodAttribute.ConstructorArguments.IsDefaultOrEmpty && methodAttribute.ConstructorArguments[0].Kind == TypedConstantKind.Type) { - KeyValuePair namedArg = default; + ImmutableArray> namedArgs = ImmutableArray>.Empty; var ctorArg = methodAttribute.ConstructorArguments[0]; if (!methodAttribute.NamedArguments.IsDefaultOrEmpty) { - namedArg = methodAttribute.NamedArguments[0]; + namedArgs = methodAttribute.NamedArguments; } - strongTypeAttrParams = ExtractStrongTypeAttributeParameters(ctorArg, namedArg, symbols); + strongTypeAttrParams = ExtractStrongTypeAttributeParameters(ctorArg, namedArgs, symbols); } else { var parameters = ExtractAttributeParameters(methodAttribute, semanticModel); - (strongTypeAttrParams.MetricNameFromAttribute, strongTypeAttrParams.TagHashSet, strongTypeAttrParams.TagDescriptionDictionary) = parameters; + (strongTypeAttrParams.MetricNameFromAttribute, strongTypeAttrParams.MetricUnitFromAttribute, strongTypeAttrParams.TagHashSet, strongTypeAttrParams.TagDescriptionDictionary) = parameters; } string metricNameFromMethod = methodSymbol.ReturnType.Name; @@ -444,6 +450,7 @@ private void GetTagDescription( { Name = methodSymbol.Name, MetricName = string.IsNullOrWhiteSpace(strongTypeAttrParams.MetricNameFromAttribute) ? metricNameFromMethod : strongTypeAttrParams.MetricNameFromAttribute, + MetricUnit = strongTypeAttrParams.MetricUnitFromAttribute, InstrumentKind = instrumentKind, GenericType = genericType.ToDisplayString(_genericTypeSymbolFormat), TagKeys = strongTypeAttrParams.TagHashSet, @@ -605,14 +612,22 @@ private void Diag(DiagnosticDescriptor desc, Location? location, params object?[ private StrongTypeAttributeParameters ExtractStrongTypeAttributeParameters( TypedConstant constructorArg, - KeyValuePair namedArgument, + ImmutableArray> namedArguments, SymbolHolder symbols) { var strongTypeAttributeParameters = new StrongTypeAttributeParameters(); - if (namedArgument is { Key: "Name", Value.Value: { } }) + // Extract "Name" and "Unit" values from the named arguments, if present, and assign them to the corresponding properties. + foreach (var namedArgument in namedArguments) { - strongTypeAttributeParameters.MetricNameFromAttribute = namedArgument.Value.Value.ToString(); + if (namedArgument.Key == "Name" && namedArgument.Value.Value is { } nameValue) + { + strongTypeAttributeParameters.MetricNameFromAttribute = nameValue.ToString(); + } + else if (namedArgument.Key == "Unit" && namedArgument.Value.Value is { } unitValue) + { + strongTypeAttributeParameters.MetricUnitFromAttribute = unitValue.ToString(); + } } if (constructorArg.IsNull || diff --git a/src/Generators/Microsoft.Gen.Metrics/StrongTypeAttributeParameters.cs b/src/Generators/Microsoft.Gen.Metrics/StrongTypeAttributeParameters.cs index 139973aa661..96abf55fe40 100644 --- a/src/Generators/Microsoft.Gen.Metrics/StrongTypeAttributeParameters.cs +++ b/src/Generators/Microsoft.Gen.Metrics/StrongTypeAttributeParameters.cs @@ -9,6 +9,7 @@ namespace Microsoft.Gen.Metrics; internal sealed class StrongTypeAttributeParameters { public string MetricNameFromAttribute = string.Empty; + public string MetricUnitFromAttribute = string.Empty; public HashSet TagHashSet = []; public Dictionary TagDescriptionDictionary = []; public List StrongTypeConfigs = []; diff --git a/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/CounterAttribute.cs b/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/CounterAttribute.cs index 00d333c0c12..43894559618 100644 --- a/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/CounterAttribute.cs +++ b/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/CounterAttribute.cs @@ -3,6 +3,8 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Shared.DiagnosticIds; namespace Microsoft.Extensions.Diagnostics.Metrics; @@ -73,7 +75,13 @@ public CounterAttribute(Type type) public string[]? TagNames { get; } /// - /// Gets the type that supplies metric tags values. + /// Gets the type that supplies metric tag values. /// public Type? Type { get; } + + /// + /// Gets or sets the unit of measurement for the metric. + /// + [Experimental(DiagnosticIds.Experiments.Telemetry)] + public string? Unit { get; set; } } diff --git a/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/CounterAttributeT.cs b/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/CounterAttributeT.cs index cc6548f2bf0..91426ac71b2 100644 --- a/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/CounterAttributeT.cs +++ b/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/CounterAttributeT.cs @@ -3,6 +3,8 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Shared.DiagnosticIds; namespace Microsoft.Extensions.Diagnostics.Metrics; @@ -82,4 +84,10 @@ public CounterAttribute(Type type) /// Gets the type that supplies metric tag values. /// public Type? Type { get; } + + /// + /// Gets or sets the unit of measurement for the metric. + /// + [Experimental(DiagnosticIds.Experiments.Telemetry)] + public string? Unit { get; set; } } diff --git a/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/GaugeAttribute.cs b/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/GaugeAttribute.cs index 5886c221480..e26375eda90 100644 --- a/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/GaugeAttribute.cs +++ b/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/GaugeAttribute.cs @@ -3,6 +3,8 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Shared.DiagnosticIds; namespace Microsoft.Extensions.Diagnostics.Metrics; @@ -75,4 +77,10 @@ public GaugeAttribute(Type type) /// Gets the type that supplies metric tag values. /// public Type? Type { get; } + + /// + /// Gets or sets the unit of measurement for the metric. + /// + [Experimental(DiagnosticIds.Experiments.Telemetry)] + public string? Unit { get; set; } } diff --git a/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/HistogramAttribute.cs b/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/HistogramAttribute.cs index 77780e4803c..43f7b914051 100644 --- a/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/HistogramAttribute.cs +++ b/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/HistogramAttribute.cs @@ -3,6 +3,8 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Shared.DiagnosticIds; namespace Microsoft.Extensions.Diagnostics.Metrics; @@ -75,4 +77,10 @@ public HistogramAttribute(Type type) /// Gets the type that supplies metric tag values. /// public Type? Type { get; } + + /// + /// Gets or sets the unit of measurement for the metric. + /// + [Experimental(DiagnosticIds.Experiments.Telemetry)] + public string? Unit { get; set; } } diff --git a/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/HistogramAttributeT.cs b/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/HistogramAttributeT.cs index b6207b4477c..afdd9a30828 100644 --- a/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/HistogramAttributeT.cs +++ b/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/Metrics/HistogramAttributeT.cs @@ -3,6 +3,8 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Shared.DiagnosticIds; namespace Microsoft.Extensions.Diagnostics.Metrics; @@ -82,4 +84,10 @@ public HistogramAttribute(Type type) /// Gets the type that supplies metric tag values. /// public Type? Type { get; } + + /// + /// Gets or sets the unit of measurement for the metric. + /// + [Experimental(DiagnosticIds.Experiments.Telemetry)] + public string? Unit { get; set; } } diff --git a/test/Generators/Microsoft.Gen.Metrics/Generated/MetricTests.Ext.Unit.cs b/test/Generators/Microsoft.Gen.Metrics/Generated/MetricTests.Ext.Unit.cs new file mode 100644 index 00000000000..7e794d8a2ae --- /dev/null +++ b/test/Generators/Microsoft.Gen.Metrics/Generated/MetricTests.Ext.Unit.cs @@ -0,0 +1,193 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Diagnostics.Metrics.Testing; +using TestClasses; +using Xunit; +namespace Microsoft.Gen.Metrics.Test; + +public partial class MetricTests +{ + [Fact] + public void CounterWithUnit_WorkCorrectly() + { + using var collector = new MetricCollector(_meter, "CounterWithUnit"); + + CounterWithUnit counter = MetricsWithUnit.CreateCounterWithUnit(_meter); + counter.Add(100L); + + var measurement = Assert.Single(collector.GetMeasurementSnapshot()); + Assert.Equal(100L, measurement.Value); + Assert.Empty(measurement.Tags); + Assert.NotNull(collector.Instrument); + Assert.Equal("seconds", collector.Instrument.Unit); + } + + [Fact] + public void HistogramWithUnit_WorkCorrectly() + { + using var collector = new MetricCollector(_meter, "HistogramWithUnit"); + + HistogramWithUnit histogram = MetricsWithUnit.CreateHistogramWithUnit(_meter); + histogram.Record(50L); + + var measurement = Assert.Single(collector.GetMeasurementSnapshot()); + Assert.Equal(50L, measurement.Value); + Assert.Empty(measurement.Tags); + + Assert.NotNull(collector.Instrument); + Assert.Equal("milliseconds", collector.Instrument.Unit); + } + + [Fact] + public void CounterWithUnitAndDimensions_WorkCorrectly() + { + const long Value = 12345L; + + using var collector = new MetricCollector(_meter, "CounterWithUnitAndDims"); + + CounterWithUnitAndDims counter = MetricsWithUnit.CreateCounterWithUnitAndDims(_meter); + counter.Add(Value, "dim1Value", "dim2Value"); + + var measurement = Assert.Single(collector.GetMeasurementSnapshot()); + Assert.Equal(Value, measurement.Value); + Assert.Equal(new (string, object?)[] { ("s1", "dim1Value"), ("s2", "dim2Value") }, + measurement.Tags.Select(x => (x.Key, x.Value))); + + // Verify the instrument has the correct unit + Assert.NotNull(collector.Instrument); + Assert.Equal("bytes", collector.Instrument.Unit); + } + + [Fact] + public void HistogramWithUnitAndDimensions_WorkCorrectly() + { + const long Value = 9876; + + using var collector = new MetricCollector(_meter, "HistogramWithUnitAndDims"); + + HistogramWithUnitAndDims histogram = MetricsWithUnit.CreateHistogramWithUnitAndDims(_meter); + histogram.Record(Value, "val1"); + + var measurement = Assert.Single(collector.GetMeasurementSnapshot()); + Assert.Equal(Value, measurement.Value); + var tag = Assert.Single(measurement.Tags); + Assert.Equal(new KeyValuePair("s1", "val1"), tag); + + // Verify the instrument has the correct unit + Assert.NotNull(collector.Instrument); + Assert.Equal("requests", collector.Instrument.Unit); + } + + [Fact] + public void HistogramStrongTypeAndUnit_WorkCorrectly() + { + var newDimensions = new Dimensions + { + Dim1 = "s1", + Dim2 = "s2" + }; + + // Verify that a histogram created with a unit works correctly + using var collector = new MetricCollector(_meter, nameof(HistogramStrongTypeWithUnit)); + + HistogramStrongTypeWithUnit histogram = MetricsWithUnit.CreateHistogramStrongTypeWithUnit(_meter); + histogram.Record(50L, newDimensions); + + var measurement = Assert.Single(collector.GetMeasurementSnapshot()); + Assert.Equal(50L, measurement.Value); + + Assert.NotNull(collector.Instrument); + Assert.Equal("s", collector.Instrument.Unit); + + Assert.Equal( + new (string, object?)[] + { + ("Dim1", newDimensions.Dim1), + ("Dim2", newDimensions.Dim2) + }, + measurement.Tags.Select(x => (x.Key, x.Value))); + } + + [Fact] + public void CounterStrongTypeAndUnit_WorkCorrectly() + { + var newDimensions = new Dimensions + { + Dim1 = "s1", + Dim2 = "s2" + }; + + // Verify that a histogram created with a unit works correctly + using var collector = new MetricCollector(_meter, nameof(CounterStrongTypeWithUnit)); + + CounterStrongTypeWithUnit counter = MetricsWithUnit.CreateCounterStrongTypeWithUnit(_meter); + counter.Add(50L, newDimensions); + + var measurement = Assert.Single(collector.GetMeasurementSnapshot()); + Assert.Equal(50L, measurement.Value); + + Assert.NotNull(collector.Instrument); + Assert.Equal("bytes", collector.Instrument.Unit); + + Assert.Equal( + new (string, object?)[] + { + ("Dim1", newDimensions.Dim1), + ("Dim2", newDimensions.Dim2) + }, + measurement.Tags.Select(x => (x.Key, x.Value))); + } + + [Fact] + public void GenericCounterWithUnit_WorkCorrectly() + { + using var collector = new MetricCollector(_meter, "GenericDoubleCounterWithUnit"); + + GenericDoubleCounterWithUnit counter = MetricsWithUnit.CreateGenericDoubleCounterWithUnit(_meter); + counter.Add(3.14); + + var measurement = Assert.Single(collector.GetMeasurementSnapshot()); + Assert.Equal(3.14, measurement.Value); + Assert.Empty(measurement.Tags); + + // Verify the instrument has the correct unit + Assert.NotNull(collector.Instrument); + Assert.Equal("meters", collector.Instrument.Unit); + } + + [Fact] + public void GenericHistogramWithUnit_WorkCorrectly() + { + using var collector = new MetricCollector(_meter, "GenericIntHistogramWithUnit"); + + GenericIntHistogramWithUnit counter = MetricsWithUnit.CreateGenericHistogramWithUnitAndDims(_meter); + counter.Record(3); + + var measurement = Assert.Single(collector.GetMeasurementSnapshot()); + Assert.Equal(3, measurement.Value); + Assert.Empty(measurement.Tags); + + // Verify the instrument has the correct unit + Assert.NotNull(collector.Instrument); + Assert.Equal("microseconds", collector.Instrument.Unit); + } + + [Fact] + public void CounterWithNoUnit_UnitInInstrumentIsNull() + { + // Test that counters with empty/null units work + using var collector = new MetricCollector(_meter, nameof(Counter0D)); + Counter0D counter0D = CounterTestExtensions.CreateCounter0D(_meter); + counter0D.Add(10L); + + var measurement = Assert.Single(collector.GetMeasurementSnapshot()); + Assert.Equal(10L, measurement.Value); + + // Verify the instrument has no unit (or default unit) + Assert.NotNull(collector.Instrument); + Assert.Null(collector.Instrument.Unit); + } +} diff --git a/test/Generators/Microsoft.Gen.Metrics/TestClasses/MetricsWithUnit.cs b/test/Generators/Microsoft.Gen.Metrics/TestClasses/MetricsWithUnit.cs new file mode 100644 index 00000000000..95432f4aa05 --- /dev/null +++ b/test/Generators/Microsoft.Gen.Metrics/TestClasses/MetricsWithUnit.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Metrics; +using Microsoft.Extensions.Diagnostics.Metrics; + +namespace TestClasses +{ +#pragma warning disable SA1402 // File may only contain a single type + [SuppressMessage("Usage", "CA1801:Review unused parameters", + Justification = "For testing emitter for classes without namespace")] + public static partial class MetricsWithUnit + { + [Counter(Unit = "seconds")] + public static partial CounterWithUnit CreateCounterWithUnit(Meter meter); + + [Counter("s1", "s2", Unit = "bytes", Name = "CounterWithUnitAndDims")] + public static partial CounterWithUnitAndDims CreateCounterWithUnitAndDims(Meter meter); + + [Counter(typeof(Dimensions), Unit = "bytes")] + public static partial CounterStrongTypeWithUnit CreateCounterStrongTypeWithUnit(Meter meter); + + [Counter(Unit = "meters", Name = "GenericDoubleCounterWithUnit")] + public static partial GenericDoubleCounterWithUnit CreateGenericDoubleCounterWithUnit(Meter meter); + + [Histogram(Unit = "milliseconds", Name = "HistogramWithUnit")] + public static partial HistogramWithUnit CreateHistogramWithUnit(Meter meter); + + [Histogram(typeof(Dimensions), Unit = "s")] + public static partial HistogramStrongTypeWithUnit CreateHistogramStrongTypeWithUnit(Meter meter); + + [Histogram("s1", Unit = "requests", Name = "HistogramWithUnitAndDims")] + public static partial HistogramWithUnitAndDims CreateHistogramWithUnitAndDims(Meter meter); + + [Histogram(Unit = "microseconds", Name = "GenericIntHistogramWithUnit")] + public static partial GenericIntHistogramWithUnit CreateGenericHistogramWithUnitAndDims(Meter meter); + } + + public class Dimensions + { + public string? Dim1 { get; set; } + public string? Dim2 { get; set; } + } +#pragma warning disable SA1402 +} diff --git a/test/Generators/Microsoft.Gen.Metrics/Unit/ParserTests.StrongTypes.cs b/test/Generators/Microsoft.Gen.Metrics/Unit/ParserTests.StrongTypes.cs index 6b345029492..892b6fa3e15 100644 --- a/test/Generators/Microsoft.Gen.Metrics/Unit/ParserTests.StrongTypes.cs +++ b/test/Generators/Microsoft.Gen.Metrics/Unit/ParserTests.StrongTypes.cs @@ -660,4 +660,23 @@ static partial class MetricClass }"); Assert.Empty(d); } + + [Fact] + public async Task StructTypeWithUnit() + { + var d = await RunGenerator(@" + public struct HistogramStruct + { + [Dimension(""Dim1_FromAttribute"")] + public string? Dim1 { get; set; } + } + + public static partial class MetricClass + { + [Histogram(typeof(HistogramStruct), Name=""TotalCountTest"", Unit = ""s"")] + public static partial TotalCount CreateTotalCountCounter(Meter meter); + }"); + + Assert.Empty(d); + } } diff --git a/test/Generators/Microsoft.Gen.Metrics/Unit/ParserTests.cs b/test/Generators/Microsoft.Gen.Metrics/Unit/ParserTests.cs index 54a19ea2e86..f9d98461b0d 100644 --- a/test/Generators/Microsoft.Gen.Metrics/Unit/ParserTests.cs +++ b/test/Generators/Microsoft.Gen.Metrics/Unit/ParserTests.cs @@ -792,4 +792,17 @@ private static async Task> RunGenerator( return d; } + + [Fact] + public async Task UnitParameterTest() + { + var d = await RunGenerator(@" + partial class C + { + [Counter(Unit = ""s"", Name = ""myMetricName"")] + static partial MetricName CreateMetric(Meter meter); + }"); + + Assert.Empty(d); + } } diff --git a/test/Libraries/Microsoft.Extensions.Telemetry.Abstractions.Tests/Metrics/MetricAttributeTests.cs b/test/Libraries/Microsoft.Extensions.Telemetry.Abstractions.Tests/Metrics/MetricAttributeTests.cs index 4d60eaa06a1..bae3dc9f014 100644 --- a/test/Libraries/Microsoft.Extensions.Telemetry.Abstractions.Tests/Metrics/MetricAttributeTests.cs +++ b/test/Libraries/Microsoft.Extensions.Telemetry.Abstractions.Tests/Metrics/MetricAttributeTests.cs @@ -16,10 +16,13 @@ public void TestCounterAttribute() Assert.NotNull(attribute); Assert.Null(attribute.Name); Assert.Null(attribute.Type); + Assert.Null(attribute.Unit); Assert.Equal(new[] { "d1", "d2", "d3" }, attribute.TagNames); attribute.Name = MyMetric; Assert.Equal(MyMetric, attribute.Name); + attribute.Unit = "items"; + Assert.Equal("items", attribute.Unit); } [Fact] @@ -29,10 +32,13 @@ public void TestHistogramAttribute() Assert.NotNull(attribute); Assert.Null(attribute.Name); Assert.Null(attribute.Type); + Assert.Null(attribute.Unit); Assert.Equal(new[] { "d1", "d2", "d3" }, attribute.TagNames); attribute.Name = MyMetric; Assert.Equal(MyMetric, attribute.Name); + attribute.Unit = "items"; + Assert.Equal("items", attribute.Unit); } [Fact] @@ -42,10 +48,13 @@ public void TestCounterAttributeT() Assert.NotNull(attribute); Assert.Null(attribute.Name); Assert.Null(attribute.Type); + Assert.Null(attribute.Unit); Assert.Equal(new[] { "d1", "d2", "d3" }, attribute.TagNames); attribute.Name = MyMetric; Assert.Equal(MyMetric, attribute.Name); + attribute.Unit = "items"; + Assert.Equal("items", attribute.Unit); } [Fact] @@ -55,10 +64,13 @@ public void TestHistogramAttributeT() Assert.NotNull(attribute); Assert.Null(attribute.Name); Assert.Null(attribute.Type); + Assert.Null(attribute.Unit); Assert.Equal(new[] { "d1", "d2", "d3" }, attribute.TagNames); attribute.Name = MyMetric; Assert.Equal(MyMetric, attribute.Name); + attribute.Unit = "items"; + Assert.Equal("items", attribute.Unit); } [Fact] @@ -68,10 +80,13 @@ public void TestGaugeAttribute() Assert.NotNull(attribute); Assert.Null(attribute.Name); Assert.Null(attribute.Type); + Assert.Null(attribute.Unit); Assert.Equal(new[] { "d1", "d2", "d3" }, attribute.TagNames); attribute.Name = MyMetric; Assert.Equal(MyMetric, attribute.Name); + attribute.Unit = "items"; + Assert.Equal("items", attribute.Unit); } [Fact] @@ -82,10 +97,13 @@ public void TestStrongTypeCounterAttribute() Assert.NotNull(attribute); Assert.Null(attribute.Name); Assert.Null(attribute.TagNames); + Assert.Null(attribute.Unit); Assert.Equal(typeof(TagNameTest), attribute.Type); attribute.Name = MyMetric; Assert.Equal(MyMetric, attribute.Name); + attribute.Unit = "items"; + Assert.Equal("items", attribute.Unit); } [Fact] @@ -96,10 +114,13 @@ public void TestStrongTypeHistogramAttribute() Assert.NotNull(attribute); Assert.Null(attribute.Name); Assert.Null(attribute.TagNames); + Assert.Null(attribute.Unit); Assert.Equal(typeof(TagNameTest), attribute.Type); attribute.Name = MyMetric; Assert.Equal(MyMetric, attribute.Name); + attribute.Unit = "items"; + Assert.Equal("items", attribute.Unit); } [Fact] @@ -110,10 +131,13 @@ public void TestStrongTypeCounterAttributeT() Assert.NotNull(attribute); Assert.Null(attribute.Name); Assert.Null(attribute.TagNames); + Assert.Null(attribute.Unit); Assert.Equal(typeof(TagNameTest), attribute.Type); attribute.Name = MyMetric; Assert.Equal(MyMetric, attribute.Name); + attribute.Unit = "items"; + Assert.Equal("items", attribute.Unit); } [Fact] @@ -124,10 +148,13 @@ public void TestStrongTypeHistogramAttributeT() Assert.NotNull(attribute); Assert.Null(attribute.Name); Assert.Null(attribute.TagNames); + Assert.Null(attribute.Unit); Assert.Equal(typeof(TagNameTest), attribute.Type); attribute.Name = MyMetric; Assert.Equal(MyMetric, attribute.Name); + attribute.Unit = "items"; + Assert.Equal("items", attribute.Unit); } [Fact] @@ -138,10 +165,13 @@ public void TestStrongTypeGaugeAttribute() Assert.NotNull(attribute); Assert.Null(attribute.Name); Assert.Null(attribute.TagNames); + Assert.Null(attribute.Unit); Assert.Equal(typeof(TagNameTest), attribute.Type); attribute.Name = MyMetric; Assert.Equal(MyMetric, attribute.Name); + attribute.Unit = "items"; + Assert.Equal("items", attribute.Unit); } [Fact]