diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs index b44e5e98c9c7c..10763fefd1af4 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs @@ -393,8 +393,10 @@ public abstract class Instrument { public string? Description { get {throw null;} } public bool Enabled { get {throw null; } } - protected Instrument(Meter meter, string name, string? unit, string? description) {throw null;} - protected Instrument(Meter meter, string name, string? unit, string? description, System.Collections.Generic.IEnumerable>? tags) {throw null;} + protected Instrument(Meter meter, string name) : this(meter, name, unit: null, description: null, tags: null) { throw null; } + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + protected Instrument(Meter meter, string name, string? unit, string? description) : this(meter, name, unit, description, tags: null) { throw null; } + protected Instrument(Meter meter, string name, string? unit = default, string? description = default, System.Collections.Generic.IEnumerable>? tags = default) { throw null; } public virtual bool IsObservable { get {throw null; } } public Meter Meter { get {throw null;} } public string Name { get {throw null;} } @@ -404,8 +406,19 @@ public abstract class Instrument } public abstract class Instrument : Instrument where T : struct { - protected Instrument(Meter meter, string name, string? unit, string? description) : base(meter, name, unit, description) { throw null; } - protected Instrument(Meter meter, string name, string? unit, string? description, System.Collections.Generic.IEnumerable>? tags) : base(meter, name, unit, description, tags) {throw null;} + public InstrumentAdvice? Advice { get { throw null; } } + protected Instrument(Meter meter, string name) : this(meter, name, unit: null, description: null, tags: null, advice: null) { throw null; } + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + protected Instrument(Meter meter, string name, string? unit, string? description) : this(meter, name, unit, description, tags: null, advice: null) { throw null; } + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + protected Instrument(Meter meter, string name, string? unit, string? description, System.Collections.Generic.IEnumerable>? tags) : this(meter, name, unit, description, tags, advice: null) { throw null; } + protected Instrument( + Meter meter, + string name, + string? unit = default, + string? description = default, + System.Collections.Generic.IEnumerable>? tags = default, + InstrumentAdvice? advice = default) : base(meter, name, unit, description, tags) { throw null; } protected void RecordMeasurement(T measurement) { throw null; } protected void RecordMeasurement(T measurement, System.Collections.Generic.KeyValuePair tag) { throw null; } protected void RecordMeasurement(T measurement, System.Collections.Generic.KeyValuePair tag1, System.Collections.Generic.KeyValuePair tag2) { throw null; } @@ -413,6 +426,11 @@ public abstract class Instrument : Instrument where T : struct protected void RecordMeasurement(T measurement, in TagList tagList) { throw null; } protected void RecordMeasurement(T measurement, ReadOnlySpan> tags) { throw null; } } + public sealed class InstrumentAdvice where T : struct + { + public InstrumentAdvice() { throw null; } + public System.Collections.Generic.IReadOnlyList? HistogramBucketBoundaries { get { throw null; } init { throw null; } } + } public readonly struct Measurement where T : struct { public Measurement(T value) { throw null; } @@ -431,8 +449,12 @@ public class Meter : IDisposable public Gauge CreateGauge(string name, string? unit = null, string? description = null, System.Collections.Generic.IEnumerable>? tags = null) where T : struct { throw null; } public UpDownCounter CreateUpDownCounter(string name, string? unit = null, string? description = null) where T : struct { throw null; } public UpDownCounter CreateUpDownCounter(string name, string? unit, string? description, System.Collections.Generic.IEnumerable> tags) where T : struct { throw null; } - public Histogram CreateHistogram(string name, string? unit = null, string? description = null) where T : struct { throw null; } - public Histogram CreateHistogram(string name, string? unit, string? description, System.Collections.Generic.IEnumerable> tags) where T : struct { throw null; } + public Histogram CreateHistogram(string name) where T : struct { throw null; } + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public Histogram CreateHistogram(string name, string? unit, string? description) where T : struct { throw null; } + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public Histogram CreateHistogram(string name, string? unit, string? description, System.Collections.Generic.IEnumerable>? tags) where T : struct { throw null; } + public Histogram CreateHistogram(string name, string? unit = default, string? description = default, System.Collections.Generic.IEnumerable>? tags = default, InstrumentAdvice? advice = default) where T : struct { throw null; } public ObservableCounter CreateObservableCounter( string name, Func observeValue, diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/Resources/Strings.resx b/src/libraries/System.Diagnostics.DiagnosticSource/src/Resources/Strings.resx index 6ad3bfd0b2a11..b228dca0765cc 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/Resources/Strings.resx +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/Resources/Strings.resx @@ -1,17 +1,17 @@  - @@ -174,4 +174,7 @@ The instrument is of different generic type. + + Histogram explicit bucket boundaries must be specified in ascending order and cannot contain duplicate values. + \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj index 88f8f0b2cd90f..79efda4894eae 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -55,6 +55,7 @@ System.Diagnostics.DiagnosticSource + @@ -93,10 +94,8 @@ System.Diagnostics.DiagnosticSource - - + + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Histogram.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Histogram.cs index 3863efe704c7c..88c99481670c0 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Histogram.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Histogram.cs @@ -15,11 +15,13 @@ namespace System.Diagnostics.Metrics /// public sealed class Histogram : Instrument where T : struct { - internal Histogram(Meter meter, string name, string? unit, string? description) : this(meter, name, unit, description, tags: null) + internal Histogram(Meter meter, string name, string? unit, string? description) + : this(meter, name, unit, description, tags: null, advice: null) { } - internal Histogram(Meter meter, string name, string? unit, string? description, IEnumerable>? tags) : base(meter, name, unit, description, tags) + internal Histogram(Meter meter, string name, string? unit, string? description, IEnumerable>? tags, InstrumentAdvice? advice) + : base(meter, name, unit, description, tags, advice) { Publish(); } diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Instrument.common.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Instrument.common.cs index bc813c0d4cfe4..ca1c7dd63d236 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Instrument.common.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Instrument.common.cs @@ -2,11 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.ComponentModel; namespace System.Diagnostics.Metrics { /// - /// Instrument{T} is the base class for all non-observable instruments. + /// is the base class for all non-observable instruments. /// /// /// This class supports only the following generic parameter types: , , , , , , and @@ -15,28 +16,67 @@ namespace System.Diagnostics.Metrics public abstract partial class Instrument : Instrument where T : struct { /// - /// Create the metrics instrument using the properties meter, name, description, and unit. - /// All classes extending Instrument{T} need to call this constructor when constructing object of the extended class. + /// Gets the associated with the instrument. /// - /// The meter that created the instrument. - /// The instrument name. cannot be null. + public InstrumentAdvice? Advice { get; } + + /// + /// Constructs a new instance of . + /// + /// The meter that created the instrument. Cannot be null. + /// The instrument name. Cannot be null. + protected Instrument(Meter meter, string name) + : this(meter, name, unit: null, description: null, tags: null, advice: null) + { + } + + /// + /// Constructs a new instance of . + /// + /// The meter that created the instrument. Cannot be null. + /// The instrument name. Cannot be null. /// Optional instrument unit of measurements. /// Optional instrument description. - protected Instrument(Meter meter, string name, string? unit, string? description) : this(meter, name, unit, description, tags: null) + [EditorBrowsable(EditorBrowsableState.Never)] + protected Instrument(Meter meter, string name, string? unit, string? description) + : this(meter, name, unit, description, tags: null, advice: null) { } /// - /// Create the metrics instrument using the properties meter, name, description, and unit. - /// All classes extending Instrument{T} need to call this constructor when constructing object of the extended class. + /// Constructs a new instance of . /// - /// The meter that created the instrument. - /// The instrument name. cannot be null. + /// The meter that created the instrument. Cannot be null. + /// The instrument name. Cannot be null. /// Optional instrument unit of measurements. /// Optional instrument description. /// Optional instrument tags. - protected Instrument(Meter meter, string name, string? unit, string? description, IEnumerable>? tags) : base(meter, name, unit, description, tags) + [EditorBrowsable(EditorBrowsableState.Never)] + protected Instrument(Meter meter, string name, string? unit, string? description, IEnumerable>? tags) + : this(meter, name, unit, description, tags, advice: null) { + } + + /// + /// Constructs a new instance of . + /// + /// The meter that created the instrument. Cannot be null. + /// The instrument name. Cannot be null. + /// Optional instrument unit of measurements. + /// Optional instrument description. + /// Optional instrument tags. + /// Optional . + protected Instrument( + Meter meter, + string name, + string? unit = default, + string? description = default, + IEnumerable>? tags = default, + InstrumentAdvice? advice = default) + : base(meter, name, unit, description, tags) + { + Advice = advice; + ValidateTypeParameter(); } diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Instrument.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Instrument.cs index 17941aa0d8b83..0a3362e015d1a 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Instrument.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Instrument.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.ComponentModel; namespace System.Diagnostics.Metrics { @@ -27,25 +28,42 @@ public abstract class Instrument internal readonly DiagLinkedList _subscriptions = new DiagLinkedList(); /// - /// Protected constructor to initialize the common instrument properties like the meter, name, description, and unit. - /// All classes extending Instrument need to call this constructor when constructing object of the extended class. + /// Constructs a new instance of . /// - /// The meter that created the instrument. - /// The instrument name. cannot be null. + /// The meter that created the instrument. Cannot be null. + /// The instrument name. Cannot be null. + protected Instrument(Meter meter, string name) + : this(meter, name, unit: null, description: null, tags: null) + { + } + + /// + /// Constructs a new instance of . + /// + /// The meter that created the instrument. Cannot be null. + /// The instrument name. Cannot be null. /// Optional instrument unit of measurements. /// Optional instrument description. - protected Instrument(Meter meter, string name, string? unit, string? description) : this(meter, name, unit, description, null) { } + [EditorBrowsable(EditorBrowsableState.Never)] + protected Instrument(Meter meter, string name, string? unit, string? description) + : this(meter, name, unit, description, tags: null) + { + } /// - /// Protected constructor to initialize the common instrument properties like the meter, name, description, and unit. - /// All classes extending Instrument need to call this constructor when constructing object of the extended class. + /// Constructs a new instance of . /// - /// The meter that created the instrument. - /// The instrument name. cannot be null. + /// The meter that created the instrument. Cannot be null. + /// The instrument name. Cannot be null. /// Optional instrument unit of measurements. /// Optional instrument description. /// Optional instrument tags. - protected Instrument(Meter meter, string name, string? unit, string? description, IEnumerable>? tags) + protected Instrument( + Meter meter, + string name, + string? unit = default, + string? description = default, + IEnumerable>? tags = default) { Meter = meter ?? throw new ArgumentNullException(nameof(meter)); Name = name ?? throw new ArgumentNullException(nameof(name)); diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/InstrumentAdvice.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/InstrumentAdvice.cs new file mode 100644 index 0000000000000..b06a5e4012a5b --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/InstrumentAdvice.cs @@ -0,0 +1,72 @@ +// 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.Collections.ObjectModel; + +namespace System.Diagnostics.Metrics +{ + /// + /// Contains configuration settings advised to be used by metrics consumers when recording measurements for a given . + /// + /// Instrument value type. + public sealed class InstrumentAdvice where T : struct + { + private readonly ReadOnlyCollection? _HistogramBucketBoundaries; + + /// + /// Initializes a new instance of the class. + /// + public InstrumentAdvice() + { + Instrument.ValidateTypeParameter(); + } + + /// + /// Gets the explicit bucket boundaries advised to be used with histogram instruments. + /// + /// + /// Notes: + /// + /// A value means no bucket boundaries have been configured and default values should be used for bucket configuration. + /// An empty set of bucket boundaries hints that the histogram by default should NOT contain buckets and should only track count and sum values. + /// A set of distinct increasing values for bucket boundaries hints that the histogram should use those for its default bucket configuration. + /// + /// + public IReadOnlyList? HistogramBucketBoundaries + { + get => _HistogramBucketBoundaries; + init + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + List bucketBoundariesCopy = new List(value); + + if (!IsSortedAndDistinct(bucketBoundariesCopy)) + { + throw new ArgumentException(SR.InvalidHistogramExplicitBucketBoundaries, nameof(value)); + } + + _HistogramBucketBoundaries = new ReadOnlyCollection(bucketBoundariesCopy); + } + } + + private static bool IsSortedAndDistinct(List values) + { + Comparer comparer = Comparer.Default; + + for (int i = 1; i < values.Count; i++) + { + if (comparer.Compare(values[i - 1], values[i]) >= 0) + { + return false; + } + } + + return true; + } + } +} diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs index b9a6e0e8885ad..f61f4a7ad9295 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.Threading; @@ -120,7 +121,7 @@ private void Initialize(string name, string? version, IEnumerable /// Create a metrics Counter object. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. /// Optional instrument unit of measurements. /// Optional instrument description. /// @@ -132,10 +133,10 @@ private void Initialize(string name, string? version, IEnumerable /// Create a metrics Counter object. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. /// Optional instrument unit of measurements. /// Optional instrument description. - /// tags to attach to the counter. + /// Optional tags to attach to the counter. /// /// Counter is an Instrument which supports non-negative increments. /// Example uses for Counter: count the number of bytes received, count the number of requests completed, count the number of accounts created, count the number of checkpoints run, and count the number of HTTP 5xx errors. @@ -170,26 +171,53 @@ public Gauge CreateGauge(string name, string? unit = null, string? descrip /// /// Histogram is an Instrument which can be used to report arbitrary values that are likely to be statistically meaningful. It is intended for statistics such as histograms, summaries, and percentile. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. + /// + /// Example uses for Histogram: the request duration and the size of the response payload. + /// + public Histogram CreateHistogram(string name) where T : struct + => CreateHistogram(name, unit: null, description: null, tags: null, advice: null); + + /// + /// Histogram is an Instrument which can be used to report arbitrary values that are likely to be statistically meaningful. It is intended for statistics such as histograms, summaries, and percentile. + /// + /// The instrument name. Cannot be null. /// Optional instrument unit of measurements. /// Optional instrument description. /// /// Example uses for Histogram: the request duration and the size of the response payload. /// - public Histogram CreateHistogram(string name, string? unit = null, string? description = null) where T : struct => CreateHistogram(name, unit, description, tags: null); + [EditorBrowsable(EditorBrowsableState.Never)] + public Histogram CreateHistogram(string name, string? unit, string? description) where T : struct + => CreateHistogram(name, unit, description, tags: null, advice: null); /// /// Histogram is an Instrument which can be used to report arbitrary values that are likely to be statistically meaningful. It is intended for statistics such as histograms, summaries, and percentile. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. /// Optional instrument unit of measurements. /// Optional instrument description. - /// tags to attach to the counter. + /// Optional tags to attach to the histogram. /// /// Example uses for Histogram: the request duration and the size of the response payload. /// + [EditorBrowsable(EditorBrowsableState.Never)] public Histogram CreateHistogram(string name, string? unit, string? description, IEnumerable>? tags) where T : struct - => (Histogram)GetOrCreateInstrument(typeof(Histogram), name, unit, description, tags, () => new Histogram(this, name, unit, description, tags)); + => CreateHistogram(name, unit, description, tags, advice: null); + + /// + /// Histogram is an Instrument which can be used to report arbitrary values that are likely to be statistically meaningful. It is intended for statistics such as histograms, summaries, and percentile. + /// + /// The instrument name. Cannot be null. + /// Optional instrument unit of measurements. + /// Optional instrument description. + /// Optional tags to attach to the histogram. + /// Optional to attach to the histogram. + /// + /// Example uses for Histogram: the request duration and the size of the response payload. + /// + public Histogram CreateHistogram(string name, string? unit = default, string? description = default, IEnumerable>? tags = default, InstrumentAdvice? advice = default) where T : struct + => (Histogram)GetOrCreateInstrument(typeof(Histogram), name, unit, description, tags, () => new Histogram(this, name, unit, description, tags, advice)); /// /// Create a metrics UpDownCounter object. @@ -210,7 +238,7 @@ public UpDownCounter CreateUpDownCounter(string name, string? unit = null, /// The instrument name. Cannot be null. /// Optional instrument unit of measurements. /// Optional instrument description. - /// tags to attach to the counter. + /// Optional tags to attach to the counter. /// /// UpDownCounter is an Instrument which supports reporting positive or negative metric values. /// Example uses for UpDownCounter: reporting the change in active requests or queue size. @@ -238,7 +266,7 @@ public ObservableUpDownCounter CreateObservableUpDownCounter(string name, /// The callback to call to get the measurements when the is called by . /// Optional instrument unit of measurements. /// Optional instrument description. - /// tags to attach to the counter. + /// Optional tags to attach to the counter. /// /// Example uses for ObservableUpDownCounter: the process heap size or the approximate number of items in a lock-free circular buffer. /// @@ -266,7 +294,7 @@ public ObservableUpDownCounter CreateObservableUpDownCounter(string name, /// The callback to call to get the measurements when the is called by /// Optional instrument unit of measurements. /// Optional instrument description. - /// tags to attach to the counter. + /// Optional tags to attach to the counter. /// /// Example uses for ObservableUpDownCounter: the process heap size or the approximate number of items in a lock-free circular buffer. /// @@ -293,7 +321,7 @@ public ObservableUpDownCounter CreateObservableUpDownCounter(string name, /// The callback to call to get the measurements when the is called by . /// Optional instrument unit of measurements. /// Optional instrument description. - /// tags to attach to the counter. + /// Optional tags to attach to the counter. /// /// Example uses for ObservableUpDownCounter: the process heap size or the approximate number of items in a lock-free circular buffer. /// @@ -303,7 +331,7 @@ public ObservableUpDownCounter CreateObservableUpDownCounter(string name, /// /// ObservableCounter is an Instrument which reports monotonically increasing value(s) when the instrument is being observed. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. /// The callback to call to get the measurements when the is called by . /// Optional instrument unit of measurements. /// Optional instrument description. @@ -316,11 +344,11 @@ public ObservableCounter CreateObservableCounter(string name, Func obse /// /// ObservableCounter is an Instrument which reports monotonically increasing value(s) when the instrument is being observed. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. /// The callback to call to get the measurements when the is called by . /// Optional instrument unit of measurements. /// Optional instrument description. - /// tags to attach to the counter. + /// Optional tags to attach to the counter. /// /// Example uses for ObservableCounter: The number of page faults for each process. /// @@ -330,7 +358,7 @@ public ObservableCounter CreateObservableCounter(string name, Func obse /// /// ObservableCounter is an Instrument which reports monotonically increasing value(s) when the instrument is being observed. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. /// The callback to call to get the measurements when the is called by /// Optional instrument unit of measurements. /// Optional instrument description. @@ -343,11 +371,11 @@ public ObservableCounter CreateObservableCounter(string name, Func /// ObservableCounter is an Instrument which reports monotonically increasing value(s) when the instrument is being observed. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. /// The callback to call to get the measurements when the is called by /// Optional instrument unit of measurements. /// Optional instrument description. - /// tags to attach to the counter. + /// Optional tags to attach to the counter. /// /// Example uses for ObservableCounter: The number of page faults for each process. /// @@ -358,7 +386,7 @@ public ObservableCounter CreateObservableCounter(string name, Func /// ObservableCounter is an Instrument which reports monotonically increasing value(s) when the instrument is being observed. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. /// The callback to call to get the measurements when the is called by . /// Optional instrument unit of measurements. /// Optional instrument description. @@ -371,11 +399,11 @@ public ObservableCounter CreateObservableCounter(string name, Func /// ObservableCounter is an Instrument which reports monotonically increasing value(s) when the instrument is being observed. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. /// The callback to call to get the measurements when the is called by . /// Optional instrument unit of measurements. /// Optional instrument description. - /// tags to attach to the counter. + /// Optional tags to attach to the counter. /// /// Example uses for ObservableCounter: The number of page faults for each process. /// @@ -385,7 +413,7 @@ public ObservableCounter CreateObservableCounter(string name, Func /// ObservableGauge is an asynchronous Instrument which reports non-additive value(s) (e.g. the room temperature - it makes no sense to report the temperature value from multiple rooms and sum them up) when the instrument is being observed. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. /// The callback to call to get the measurements when the is called by . /// Optional instrument unit of measurements. /// Optional instrument description. @@ -395,18 +423,18 @@ public ObservableGauge CreateObservableGauge(string name, Func observeV /// /// ObservableGauge is an asynchronous Instrument which reports non-additive value(s) (e.g. the room temperature - it makes no sense to report the temperature value from multiple rooms and sum them up) when the instrument is being observed. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. /// The callback to call to get the measurements when the is called by . /// Optional instrument unit of measurements. /// Optional instrument description. - /// tags to attach to the counter. + /// Optional tags to attach to the gauge. public ObservableGauge CreateObservableGauge(string name, Func observeValue, string? unit, string? description, IEnumerable>? tags) where T : struct => new ObservableGauge(this, name, observeValue, unit, description, tags); /// /// ObservableGauge is an asynchronous Instrument which reports non-additive value(s) (e.g. the room temperature - it makes no sense to report the temperature value from multiple rooms and sum them up) when the instrument is being observed. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. /// The callback to call to get the measurements when the is called by . /// Optional instrument unit of measurements. /// Optional instrument description. @@ -416,18 +444,18 @@ public ObservableGauge CreateObservableGauge(string name, Func /// ObservableGauge is an asynchronous Instrument which reports non-additive value(s) (e.g. the room temperature - it makes no sense to report the temperature value from multiple rooms and sum them up) when the instrument is being observed. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. /// The callback to call to get the measurements when the is called by . /// Optional instrument unit of measurements. /// Optional instrument description. - /// tags to attach to the counter. + /// Optional tags to attach to the gauge. public ObservableGauge CreateObservableGauge(string name, Func> observeValue, string? unit, string? description, IEnumerable>? tags) where T : struct => new ObservableGauge(this, name, observeValue, unit, description, tags); /// /// ObservableGauge is an asynchronous Instrument which reports non-additive value(s) (e.g. the room temperature - it makes no sense to report the temperature value from multiple rooms and sum them up) when the instrument is being observed. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. /// The callback to call to get the measurements when the is called by . /// Optional instrument unit of measurements. /// Optional instrument description. @@ -437,11 +465,11 @@ public ObservableGauge CreateObservableGauge(string name, Func /// ObservableGauge is an asynchronous Instrument which reports non-additive value(s) (e.g. the room temperature - it makes no sense to report the temperature value from multiple rooms and sum them up) when the instrument is being observed. /// - /// The instrument name. cannot be null. + /// The instrument name. Cannot be null. /// The callback to call to get the measurements when the is called by . /// Optional instrument unit of measurements. /// Optional instrument description. - /// tags to attach to the counter. + /// Optional tags to attach to the gauge. public ObservableGauge CreateObservableGauge(string name, Func>> observeValues, string? unit, string? description, IEnumerable>? tags) where T : struct => new ObservableGauge(this, name, observeValues, unit, description, tags); diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsAdviceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsAdviceTests.cs new file mode 100644 index 0000000000000..e825fed29f8d4 --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsAdviceTests.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; + +namespace System.Diagnostics.Metrics.Tests +{ + public class MetricsAdviceTests + { + [Fact] + public void HistogramAdviceConstructionTest() + { + Assert.Throws(() => new InstrumentAdvice { HistogramBucketBoundaries = null }); + + InstrumentAdvice emptyExplicitBucketBoundariesAdvice = new InstrumentAdvice { HistogramBucketBoundaries = Array.Empty() }; + + Assert.NotNull(emptyExplicitBucketBoundariesAdvice.HistogramBucketBoundaries); + Assert.Empty(emptyExplicitBucketBoundariesAdvice.HistogramBucketBoundaries); + + int[] singleExplicitBucketBoundary = new int[] { 0 }; + + InstrumentAdvice singleExplicitBucketBoundaryAdvice = new InstrumentAdvice { HistogramBucketBoundaries = singleExplicitBucketBoundary }; + + Assert.Equal(singleExplicitBucketBoundary, singleExplicitBucketBoundaryAdvice.HistogramBucketBoundaries); + + // Verify data cannot be mutated after construction + singleExplicitBucketBoundary[0] = int.MaxValue; + Assert.NotEqual(singleExplicitBucketBoundary, singleExplicitBucketBoundaryAdvice.HistogramBucketBoundaries); + + int[] invalidBucketBoundariesNondistinctValues = new int[] { 0, 1, 2, 3, 4, 4 }; + + Assert.Throws(() => new InstrumentAdvice { HistogramBucketBoundaries = invalidBucketBoundariesNondistinctValues }); + + int[] invalidBucketBoundariesOrdering = new int[] { 0, 1, 2, 3, 5, 4 }; + + Assert.Throws(() => new InstrumentAdvice { HistogramBucketBoundaries = invalidBucketBoundariesOrdering }); + } + } +} diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs index cc512d20d4baa..667c3eaf87245 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs @@ -3,7 +3,6 @@ using Microsoft.DotNet.RemoteExecutor; using System.Collections.Generic; -using System.Diagnostics.Metrics; using System.Diagnostics.Tests; using System.Linq; using System.Threading; @@ -1688,6 +1687,26 @@ public void TestInstrumentCreationWithTags() }).Dispose(); } + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + public void TestHistogramCreationWithAdvice() + { + RemoteExecutor.Invoke(() => + { + using Meter meter = new Meter(nameof(TestHistogramCreationWithAdvice)); + + Histogram histogramWithoutAdvice = meter.CreateHistogram(name: nameof(histogramWithoutAdvice)); + + Assert.Null(histogramWithoutAdvice.Advice); + + int[] explicitBucketBoundaries = new int[] { 0, 100, 1000, 10000 }; + + Histogram histogramWithAdvice = meter.CreateHistogram(name: nameof(histogramWithAdvice), advice: new InstrumentAdvice { HistogramBucketBoundaries = explicitBucketBoundaries }); + + Assert.NotNull(histogramWithAdvice.Advice?.HistogramBucketBoundaries); + Assert.Equal(explicitBucketBoundaries, histogramWithAdvice.Advice.HistogramBucketBoundaries); + }).Dispose(); + } + private void PublishCounterMeasurement(Counter counter, T value, KeyValuePair[] tags) where T : struct { switch (tags.Length) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj index 29a8e55dc2fc0..446c67800c4a0 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj @@ -32,6 +32,7 @@ +