From 24d2703dbf27d945f2317bd113b0cc81d45733f0 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 29 Apr 2021 12:48:22 -0700 Subject: [PATCH 01/25] Metrics Design --- .../2021/System.Diagnostics/Metrics-Design.md | 502 ++++++++++++++++++ 1 file changed, 502 insertions(+) create mode 100644 accepted/2021/System.Diagnostics/Metrics-Design.md diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md new file mode 100644 index 000000000..7846b471d --- /dev/null +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -0,0 +1,502 @@ +# Metrics APIs Design + +## Overview + +This document is discussing the .NET Metrics APIs design which implements the [OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/new_api.md). + +The OpenTelemetry Metrics APIs support reporting measurements about the execution of a computer program at run time. The Metrics APIs are designed explicitly for processing raw measurements, generally with the intent to produce continuous summaries of those measurements, efficiently and simultaneously. + +The OpenTelemetry architecture is splitting the measurement reporting part to a component called `APIs` and that is the part we are discussing here and proposing APIs for it. The other part is called `SDK` which will monitor, aggregate the Metrics measurements, and export the aggregated measurement to some backend. The SDK part will be implemented in the OpenTelemetry [dotnet repo](https://github.com/open-telemetry/opentelemetry-dotnet) and will not part of the .NET. The `SDK` will depend on the APIs we are going to expose in .NET. + +The proposed APIs will be used by the application or Library authoress to record metrics measurements. The APIs also include a listener which will allow listening to the recorded measurements events which can be used by the OpenTelemetry SDK to aggregate the measurements and export them. + +The proposed APIs are intended to be supported on Full Framework 4.6 and up, .NET Core all versions, and .NET 5.0 and up. + +```MD040 +Naming in this proposal is picked up from the OpenTelemetry specification to avoid having .NET APIs +deviating from the standard even if the standard names are not the best to use. +``` + +## Metric Terminologies + +### Instrument + +The Instrument is the type that will be used by the app and library authors to report measurements (e.g. Counter, Gauge...etc.). The instrument will have a name that should be validated as described in the OpenTelemetry specs. The Instrument can optionally have a description and unit of measurements. Instruments will be created with a numerical type parameter (e.g. `Counter`). The Instrument is going to support all CLS-compliant numerical types which are supported on the Full Framework (Byte, Int16, Int32, Int64, Single, Double, and Decimal). + +There are two types of instruments: + +- The first type we'll call it just `Instrument` for simplicity. These instruments are called inside a request, meaning they have an associated distributed Context (with Span, Baggage, etc.). OpenTelemetry specs call this type of instrument a synchronous Instrument but we are trying to avoid confusion with the async feature of the .NET. The proposal here proposes three instrument classes of that type: `Counter`, `UpDownCounter`, and `Histogram`. +- The second type is called `ObservableInstrument` which reports measurements by a callback, once per collection interval, and lacks Context. OpenTelemetry specs call this type of instrument an asynchronous Instrument but we are trying to avoid confusion with the async feature of the .NET. The proposal here is proposing three instrument classes of that type: `ObservableCounter`, `ObservableGauge`, and `ObservableUpDownCounter`. + +### Meter + +Meter is the factory type responsible for creating Instruments. Meter will have a name and optional version strings. + +### Listener + +The listener is the type that allows listening to the recorded measurements occurred by both the non-observable instrument and the observable instrument. The listener is an important class that will be used by OpenTelemetry to implement the Metrics SDK. + +### Tags + +Tag is the term used to refer to a key-value attribute associated with a metric event. Each tag categorizes the metric event, allowing events to be filtered and grouped for analysis. +Current OpenTelemetry specs call it Labels but this is going to change to Attributes. We have used the tags name in the tracing APIs and we'll stick with this name for the sake of consistency with tracing. + +## APIs Proposal + +### Meter Class + +```csharp +namespace System.Diagnostics.Metrics +{ + public class Meter : IDisposable + { + + /// + /// The constructor allows creating the Meter class with the name and optionally the version. + /// The name should be validated as described by the OpenTelemetry specs. + /// + public Meter(string name) { throw null; } + public Meter(string name, string? version) { throw null; } + + /// + /// Getter properties to retrieve the Meter name and version + /// + public string Name { get; } + public string? Version { get; } + + /// + /// Factory Methods to create Counter, UpDownCounter, and Histogram instruments. + /// + public Counter CreateCounter( + string name, + string? description = null, + string? unit = null) where T : unmanaged { throw null; } + + public UpDownCounter CreateUpDownCounter( + string name, + string? description = null, + string? unit = null) where T : unmanaged { throw null; } + + public Histogram CreateHistogram( + string name, + string? description = null, + string? unit = null) where T : unmanaged { throw null; } + + /// + /// Factory Methods to create an observable Counter instrument. + /// + + public ObservableCounter CreateObservableCounter( + string name, + Func observeValue, + string? description = null, + string? unit = null) where T : unmanaged { throw null; } + + public ObservableCounter CreateObservableCounter( + string name, + Func> observeValue, + string? description = null, + string? unit = null) where T : unmanaged { throw null; } + + public ObservableCounter CreateObservableCounter( + string name, + Func>> observeValues, + string? description = null, + string? unit = null) where T : unmanaged { throw null; } + + /// + /// Factory Methods to create observable gauge instrument. + /// + public ObservableGauge CreateObservableGauge( + string name, + Func observeValue, + string? description = null, + string? unit = null) where T : unmanaged { throw null; } + + public ObservableGauge CreateObservableGauge( + string name, + Func> observeValues, + string? description = null, + string? unit = null) where T : unmanaged { throw null; } + + public ObservableGauge CreateObservableGauge( + string name, + Func>> observeValues, + string? description = null, + string? unit = null) where T : unmanaged { throw null; } + + /// + /// Factory Methods to create observable UpDownCounter instrument. + /// + public ObservableUpDownCounter CreateObservableUpDownCounter( + string name, + Func observeValue, + string? description = null, + string? unit = null) where T : unmanaged { throw null; } + + public ObservableUpDownCounter CreateObservableUpDownCounter( + string name, + Func> observeValues, + string? description = null, + string? unit = null) where T : unmanaged { throw null; } + + public ObservableUpDownCounter CreateObservableUpDownCounter( + string name, + Func>> observeValues, + string? description = null, + string? unit = null) where T : unmanaged { throw null; } + + public void Dispose() { throw null; } + } +} +``` + +### Instrument Base Class + +```csharp +namespace System.Diagnostics.Metrics +{ + /// + /// Is the base class which contains all common properties between different types of instruments. + /// It contains the protected constructor and the Publish method allows activating the instrument + /// to start recording measurements. + /// + + public abstract class Instrument + { + /// + /// Protected constructor to initialize the common instrument properties. + /// + protected Instrument(Meter meter, string name, string? description, string? unit) { throw null; } + + /// + /// Publish is to allow activating the instrument to start recording measurements and to allow + /// listeners to start listening to such measurements. + /// + protected void Publish() { throw null; } + + /// + /// Getters to retrieve the properties that the instrument is created with. + /// + public Meter Meter { get; } + public string Name { get; } + public string? Description { get; } + public string? Unit { get; } + + /// + /// A property tells if a listener is listening to this instrument measurement recording. + /// + public bool Enabled => throw null; + + /// + /// A property tells if the instrument is a regular instrument or an observable instrument. + /// + public virtual bool IsObservable => throw null; + } +} +``` + +### Non-observable Instrument Base Class + +```csharp +namespace System.Diagnostics.Metrics +{ + /// + /// Instrument is the base class from which all non-observable instruments will inherit from. + /// Mainly It'll support the CLS compliant numerical types + /// + public abstract class Instrument : Instrument where T : unmanaged + { + /// + /// Protected constructor to create the instrument with the common properties. + /// + protected Instrument(Meter meter, string name, string? description, string? unit) : + base(meter, name, description, unit) { throw null; } + + /// + /// Record measurement overloads allowing passing different numbers of tags. + /// + + protected void RecordMeasurement(T val) { throw null; } + + protected void RecordMeasurement( + T val, + KeyValuePair tag1) { throw null; } + + protected void RecordMeasurement( + T val, + KeyValuePair tag1, + KeyValuePair tag2) { throw null; } + + protected void RecordMeasurement( + T val, + KeyValuePair tag1, + KeyValuePair tag2, + KeyValuePair tag3) { throw null; } + + protected void RecordMeasurement( + T val, + ReadOnlySpan> tags) { throw null; } + } +} +``` + +### Observable Instrument Base class + +```csharp +namespace System.Diagnostics.Metrics +{ + /// + /// ObservableInstrument is the base class from which all observable instruments will inherit from. + /// Mainly It'll support the CLS compliant numerical types + /// + public abstract class ObservableInstrument : Instrument where T : unmanaged + { + /// + /// Protected constructor to create the instrument with the common properties. + /// + protected ObservableInstrument( + Meter meter, + string name, + string? description, + string? unit) : base(meter, name, description, unit) { throw null; } + + /// + /// Observe will report the non-additive values of the measurements. + /// + protected abstract IEnumerable> Observe(); + } +} +``` + +### Measurement class + +```csharp + +namespace System.Diagnostics.Metrics +{ + /// + /// A helper class used by the Observable instruments Observe method to repro the measurement values + /// with the associated tags. + /// + public struct Measurement where T : unmanaged + { + /// + /// Construct the Measurement using the value and the list of tags. + /// We'll always copy the input list as this is not perf hot path. + /// + public Measurement(T value, IEnumerable> tags) { throw null; } + public Measurement(T value, params KeyValuePair[] tags) { throw null; } + + public ReadOnlySpan> Tags { get { throw null; } } + public T Value { get; } + } +} +``` + +### Non-observable Instruments + +```csharp +namespace System.Diagnostics.Metrics +{ + /// + /// The counter is a non-observable Instrument that supports non-negative increments. + /// e.g. Number of completed requests. + /// + public class Counter : Instrument where T : unmanaged + { + public void Add(T measurement) { throw null; } + public void Add(T measurement, + KeyValuePair tag1) { throw null; } + public void Add(T measurement, + KeyValuePair tag1, + KeyValuePair tag2) { throw null; } + public void Add(T measurement, + KeyValuePair tag1, + KeyValuePair tag2, + KeyValuePair tag3) { throw null; } + public void Add(T measurement, + params KeyValuePair[] tags) { throw null; } + } + + /// + /// UpDownCounter is a non-observable Instrument that supports increments and decrements. + /// e.g. Number of items in a queue. + /// + public class UpDownCounter : Instrument where T : unmanaged + { + public void Add(T measurement) { throw null; } + public void Add(T measurement, + KeyValuePair tag1) { throw null; } + public void Add(T measurement, + KeyValuePair tag1, + KeyValuePair tag2) { throw null; } + public void Add(T measurement, + KeyValuePair tag1, + KeyValuePair tag2, + KeyValuePair tag3) { throw null; } + public void Add(T measurement, + params KeyValuePair[] tags) { throw null; } + } + + /// + /// The histogram is a non-observable Instrument that can be used to report arbitrary values + /// that are likely to be statistically meaningful. It is intended for statistics such + /// e.g. the request duration. + /// + public class Histogram : Instrument where T : unmanaged + { + public void Record(T measurement) { throw null; } + public void Record( + T measurement, + KeyValuePair tag1) { throw null; } + public void Record( + T measurement, + KeyValuePair tag1, + KeyValuePair tag2) { throw null; } + public void Record( + T measurement, + KeyValuePair tag1, + KeyValuePair tag2, + KeyValuePair tag3) { throw null; } + public void Record( + T measurement, + params KeyValuePair[] tags) { throw null; } + } +} + +``` + +### Observable Instruments + +```csharp +namespace System.Diagnostics.Metrics +{ + /// + /// ObservableCounter is an observable Instrument that reports monotonically increasing value(s) + /// when the instrument is being observed. + /// e.g. CPU time (for different processes, threads, user mode or kernel mode). + /// + public class ObservableCounter : ObservableInstrument where T : unmanaged + { + protected override IEnumerable> Observe() { throw null; } + } + + /// + /// ObservableUpDownCounter is an observable Instrument that reports additive value(s) + /// when the instrument is being observed. + /// e.g. the process heap size + /// + public class ObservableUpDownCounter : ObservableInstrument where T : unmanaged + { + protected override IEnumerable> Observe() { throw null; } + } + + /// + /// ObservableGauge is an observable Instrument that reports non-additive value(s) + /// when the instrument is being observed. + /// e.g. the current room temperature + /// + public class ObservableGauge : ObservableInstrument where T : unmanaged + { + protected override IEnumerable> Observe() { throw null; } + } +} +``` + +### MeterListener + +```csharp +namespace System.Diagnostics.Metrics +{ + /// + /// A delegate to represent the callbacks signatures used in the listener. + /// + public delegate void MeasurementCallback( + Instrument instrument, + T measurement, + ReadOnlySpan<(string TagName, object TagValue)> tags, + object? cookie); + + + /// + /// The listener class can be used to listen to observable and non-observable instrument + /// recorded measurements. + /// + public class MeterListener : IDisposable + { + /// + /// Simple constructor + /// + public MeterListener() { throw null; } + + /// + /// Callbacks to get notification when an instrument is published + /// + public Action? InstrumentPublished { get; set; } + + /// + /// Callbacks to get notification when stopping the measurement on some instrument + /// this can happen when the Meter or the Listener is disposed of. Or calling Stop() + /// on the listener. + /// + // This need some clarification + public Action? MeasurementsCompleted { get; set; } + + /// + /// Start listening to a specific instrument measurement recording. + /// + public void EnableMeasurementEvents(Instrument instrument, object? cookie = null) { throw null; } + + /// + /// Stop listening to a specific instrument measurement recording. + /// + public void DisableMeasurementEvents(Instrument instrument) { throw null; } + + /// + /// Set a callback for a specific numeric type to get the measurement recording notification + /// from all instruments which enabled listened to and was created with the same specified + /// numeric type. + /// + public void SetMeasurementEventCallback(MeasurementCallback? measurementCallback) { throw null; } + + public void Start() { throw null; } + public void Stop() { throw null; } + + /// + /// Call all Observable instruments to get the recorded measurements reported to the + /// callbacks enabled by SetMeasurementEventCallback + /// + public void RecordObservableInstruments() { throw null; } + + public void Dispose() { throw null; } + } +} +``` + +### Library Measurement Recording Example + +```csharp + Meter meter = new Meter("io.opentelemetry.contrib.mongodb", "v1.0"); + Counter counter = meter.CreateCounter("Requests"); + counter.Add(1); + counter.Add(1, KeyValuePair("request", "read")); +``` + +### Listening Example + +```csharp + InstrumentListener listener = new InstrumentListener(); + listener.InstrumentPublished = (instrument) => + { + if (instrument.Name == "Requests" && instrument.Meter.Name == "io.opentelemetry.contrib.mongodb") + { + listener.EnableMeasurementEvents(instrument, null); + } + }; + listener.SetMeasurementEventCallback((instrument, measurement, labels, cookie) => + { + Console.WriteLine($"Instrument: {instrument.Name} has recorded the measurement {measurement}"); + }); + listener.Start(); +``` \ No newline at end of file From d76ae0d20086f378c50320f60d8c48e321ae78da Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 29 Apr 2021 13:35:10 -0700 Subject: [PATCH 02/25] Apply suggestions from code review Co-authored-by: Cijo Thomas --- accepted/2021/System.Diagnostics/Metrics-Design.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 7846b471d..c040a17bf 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -8,7 +8,7 @@ The OpenTelemetry Metrics APIs support reporting measurements about the executio The OpenTelemetry architecture is splitting the measurement reporting part to a component called `APIs` and that is the part we are discussing here and proposing APIs for it. The other part is called `SDK` which will monitor, aggregate the Metrics measurements, and export the aggregated measurement to some backend. The SDK part will be implemented in the OpenTelemetry [dotnet repo](https://github.com/open-telemetry/opentelemetry-dotnet) and will not part of the .NET. The `SDK` will depend on the APIs we are going to expose in .NET. -The proposed APIs will be used by the application or Library authoress to record metrics measurements. The APIs also include a listener which will allow listening to the recorded measurements events which can be used by the OpenTelemetry SDK to aggregate the measurements and export them. +The proposed APIs will be used by the application or Library authors to record metrics measurements. The APIs also include a listener which will allow listening to the recorded measurements events which can be used by the OpenTelemetry SDK to aggregate the measurements and export them. The proposed APIs are intended to be supported on Full Framework 4.6 and up, .NET Core all versions, and .NET 5.0 and up. @@ -115,7 +115,7 @@ namespace System.Diagnostics.Metrics public ObservableGauge CreateObservableGauge( string name, - Func> observeValues, + Func> observeValue, string? description = null, string? unit = null) where T : unmanaged { throw null; } @@ -136,7 +136,7 @@ namespace System.Diagnostics.Metrics public ObservableUpDownCounter CreateObservableUpDownCounter( string name, - Func> observeValues, + Func> observeValue, string? description = null, string? unit = null) where T : unmanaged { throw null; } @@ -499,4 +499,4 @@ namespace System.Diagnostics.Metrics Console.WriteLine($"Instrument: {instrument.Name} has recorded the measurement {measurement}"); }); listener.Start(); -``` \ No newline at end of file +``` From 966ddf07c868d99974724de5c3a774bdc806c3ba Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 29 Apr 2021 13:37:54 -0700 Subject: [PATCH 03/25] Apply suggestions from code review Co-authored-by: Reiley Yang --- accepted/2021/System.Diagnostics/Metrics-Design.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index c040a17bf..8f018d537 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -6,9 +6,9 @@ This document is discussing the .NET Metrics APIs design which implements the [O The OpenTelemetry Metrics APIs support reporting measurements about the execution of a computer program at run time. The Metrics APIs are designed explicitly for processing raw measurements, generally with the intent to produce continuous summaries of those measurements, efficiently and simultaneously. -The OpenTelemetry architecture is splitting the measurement reporting part to a component called `APIs` and that is the part we are discussing here and proposing APIs for it. The other part is called `SDK` which will monitor, aggregate the Metrics measurements, and export the aggregated measurement to some backend. The SDK part will be implemented in the OpenTelemetry [dotnet repo](https://github.com/open-telemetry/opentelemetry-dotnet) and will not part of the .NET. The `SDK` will depend on the APIs we are going to expose in .NET. +The OpenTelemetry architecture is splitting the measurement reporting part to a component called `APIs` and that is the part we are discussing here and proposing APIs for it. The other part is called `SDK` which will monitor, aggregate the Metrics measurements, and export the aggregated measurement to some backend. The SDK part will be implemented in the [OpenTelemetry .NET repo](https://github.com/open-telemetry/opentelemetry-dotnet) and will not be part of the .NET. The `SDK` will depend on the APIs we are going to expose in .NET. -The proposed APIs will be used by the application or Library authors to record metrics measurements. The APIs also include a listener which will allow listening to the recorded measurements events which can be used by the OpenTelemetry SDK to aggregate the measurements and export them. +The proposed APIs will be used by the application or library authors to record metrics measurements. The APIs also include a listener which will allow listening to the recorded measurements events which can be used by the OpenTelemetry SDK (or other potential consumers) to aggregate the measurements and export them. The proposed APIs are intended to be supported on Full Framework 4.6 and up, .NET Core all versions, and .NET 5.0 and up. From bfe2c30b82bf6bbece4e836abd7c90605b87551b Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 29 Apr 2021 13:45:37 -0700 Subject: [PATCH 04/25] Update accepted/2021/System.Diagnostics/Metrics-Design.md Co-authored-by: Reiley Yang --- accepted/2021/System.Diagnostics/Metrics-Design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 8f018d537..fa42d74b7 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -14,7 +14,7 @@ The proposed APIs are intended to be supported on Full Framework 4.6 and up, .NE ```MD040 Naming in this proposal is picked up from the OpenTelemetry specification to avoid having .NET APIs -deviating from the standard even if the standard names are not the best to use. +deviating from the standard even if the standard names are not the best option for the .NET ecosystem. ``` ## Metric Terminologies From b9428e9c0ad5a8af0b1bcf4371bc583c9ef0ac7d Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 29 Apr 2021 13:55:34 -0700 Subject: [PATCH 05/25] Update accepted/2021/System.Diagnostics/Metrics-Design.md Co-authored-by: Cijo Thomas --- accepted/2021/System.Diagnostics/Metrics-Design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index fa42d74b7..8b44745d4 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -34,7 +34,7 @@ Meter is the factory type responsible for creating Instruments. Meter will have ### Listener -The listener is the type that allows listening to the recorded measurements occurred by both the non-observable instrument and the observable instrument. The listener is an important class that will be used by OpenTelemetry to implement the Metrics SDK. +The listener is the type that allows listening to the measurements recorded by instruments. The listener is an important class that will be used by OpenTelemetry to implement the Metrics SDK. ### Tags From d6b95b6ec356e63b1489988b19d318d5e35daa12 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 29 Apr 2021 15:11:39 -0700 Subject: [PATCH 06/25] Address some feedback --- .../2021/System.Diagnostics/Metrics-Design.md | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 8b44745d4..680e3ba04 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -10,7 +10,7 @@ The OpenTelemetry architecture is splitting the measurement reporting part to a The proposed APIs will be used by the application or library authors to record metrics measurements. The APIs also include a listener which will allow listening to the recorded measurements events which can be used by the OpenTelemetry SDK (or other potential consumers) to aggregate the measurements and export them. -The proposed APIs are intended to be supported on Full Framework 4.6 and up, .NET Core all versions, and .NET 5.0 and up. +The proposed APIs are intended to be supported on Full Framework 4.6 and up, .NET Core supported versions, and .NET 5.0 and up. The proposed APIs will be part of the System.Diagnostics.DiagnosticSource package. ```MD040 Naming in this proposal is picked up from the OpenTelemetry specification to avoid having .NET APIs @@ -34,7 +34,7 @@ Meter is the factory type responsible for creating Instruments. Meter will have ### Listener -The listener is the type that allows listening to the measurements recorded by instruments. The listener is an important class that will be used by OpenTelemetry to implement the Metrics SDK. +The listener is the type that allows listening to the measurements reported by instruments (e.g. Counter, ObservableCounter, etc.). The listener is an important class that will be used by OpenTelemetry to implement the Metrics SDK. ### Tags @@ -221,22 +221,22 @@ namespace System.Diagnostics.Metrics protected void RecordMeasurement( T val, - KeyValuePair tag1) { throw null; } + KeyValuePair tag1) { throw null; } protected void RecordMeasurement( T val, - KeyValuePair tag1, - KeyValuePair tag2) { throw null; } + KeyValuePair tag1, + KeyValuePair tag2) { throw null; } protected void RecordMeasurement( T val, - KeyValuePair tag1, - KeyValuePair tag2, - KeyValuePair tag3) { throw null; } + KeyValuePair tag1, + KeyValuePair tag2, + KeyValuePair tag3) { throw null; } protected void RecordMeasurement( T val, - ReadOnlySpan> tags) { throw null; } + ReadOnlySpan> tags) { throw null; } } } ``` @@ -265,6 +265,8 @@ namespace System.Diagnostics.Metrics /// Observe will report the non-additive values of the measurements. /// protected abstract IEnumerable> Observe(); + + public override bool IsObservable => throw null; } } ``` @@ -285,8 +287,9 @@ namespace System.Diagnostics.Metrics /// Construct the Measurement using the value and the list of tags. /// We'll always copy the input list as this is not perf hot path. /// - public Measurement(T value, IEnumerable> tags) { throw null; } + public Measurement(T value, IEnumerable> tags) { throw null; } public Measurement(T value, params KeyValuePair[] tags) { throw null; } + public Measurement(T value, ReadOnlySpan> tags) { throw null; } public ReadOnlySpan> Tags { get { throw null; } } public T Value { get; } @@ -307,16 +310,18 @@ namespace System.Diagnostics.Metrics { public void Add(T measurement) { throw null; } public void Add(T measurement, - KeyValuePair tag1) { throw null; } + KeyValuePair tag1) { throw null; } + public void Add(T measurement, + KeyValuePair tag1, + KeyValuePair tag2) { throw null; } public void Add(T measurement, - KeyValuePair tag1, - KeyValuePair tag2) { throw null; } + KeyValuePair tag1, + KeyValuePair tag2, + KeyValuePair tag3) { throw null; } public void Add(T measurement, - KeyValuePair tag1, - KeyValuePair tag2, - KeyValuePair tag3) { throw null; } + ReadOnlySpan<> tags) { throw null; } public void Add(T measurement, - params KeyValuePair[] tags) { throw null; } + params KeyValuePair[] tags) { throw null; } } /// @@ -327,16 +332,18 @@ namespace System.Diagnostics.Metrics { public void Add(T measurement) { throw null; } public void Add(T measurement, - KeyValuePair tag1) { throw null; } + KeyValuePair tag1) { throw null; } + public void Add(T measurement, + KeyValuePair tag1, + KeyValuePair tag2) { throw null; } public void Add(T measurement, - KeyValuePair tag1, - KeyValuePair tag2) { throw null; } + KeyValuePair tag1, + KeyValuePair tag2, + KeyValuePair tag3) { throw null; } public void Add(T measurement, - KeyValuePair tag1, - KeyValuePair tag2, - KeyValuePair tag3) { throw null; } + ReadOnlySpan<> tags) { throw null; } public void Add(T measurement, - params KeyValuePair[] tags) { throw null; } + params KeyValuePair[] tags) { throw null; } } /// @@ -349,19 +356,21 @@ namespace System.Diagnostics.Metrics public void Record(T measurement) { throw null; } public void Record( T measurement, - KeyValuePair tag1) { throw null; } + KeyValuePair tag1) { throw null; } public void Record( T measurement, - KeyValuePair tag1, - KeyValuePair tag2) { throw null; } + KeyValuePair tag1, + KeyValuePair tag2) { throw null; } public void Record( T measurement, - KeyValuePair tag1, - KeyValuePair tag2, - KeyValuePair tag3) { throw null; } + KeyValuePair tag1, + KeyValuePair tag2, + KeyValuePair tag3) { throw null; } + public void Record(T measurement, + ReadOnlySpan<> tags) { throw null; } public void Record( T measurement, - params KeyValuePair[] tags) { throw null; } + params KeyValuePair[] tags) { throw null; } } } @@ -415,7 +424,7 @@ namespace System.Diagnostics.Metrics public delegate void MeasurementCallback( Instrument instrument, T measurement, - ReadOnlySpan<(string TagName, object TagValue)> tags, + ReadOnlySpan> tags, object? cookie); From f142525357aba292e9e4fe539ea6d979666b74dc Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 29 Apr 2021 15:20:01 -0700 Subject: [PATCH 07/25] more feedback --- accepted/2021/System.Diagnostics/Metrics-Design.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 680e3ba04..0d3fa8cbd 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -39,7 +39,7 @@ The listener is the type that allows listening to the measurements reported by i ### Tags Tag is the term used to refer to a key-value attribute associated with a metric event. Each tag categorizes the metric event, allowing events to be filtered and grouped for analysis. -Current OpenTelemetry specs call it Labels but this is going to change to Attributes. We have used the tags name in the tracing APIs and we'll stick with this name for the sake of consistency with tracing. +Current OpenTelemetry specs call it Attributes. We have used the tags name in the tracing APIs and we'll stick with this name for the sake of consistency with tracing. ## APIs Proposal @@ -278,7 +278,7 @@ namespace System.Diagnostics.Metrics namespace System.Diagnostics.Metrics { /// - /// A helper class used by the Observable instruments Observe method to repro the measurement values + /// A helper class used by the Observable instruments Observe method to report the measurement values /// with the associated tags. /// public struct Measurement where T : unmanaged From 65a53af984568575220c9f9ff7ce20877eb36789 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 29 Apr 2021 15:29:04 -0700 Subject: [PATCH 08/25] label->tag --- accepted/2021/System.Diagnostics/Metrics-Design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 0d3fa8cbd..a235cf283 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -503,7 +503,7 @@ namespace System.Diagnostics.Metrics listener.EnableMeasurementEvents(instrument, null); } }; - listener.SetMeasurementEventCallback((instrument, measurement, labels, cookie) => + listener.SetMeasurementEventCallback((instrument, measurement, tags, cookie) => { Console.WriteLine($"Instrument: {instrument.Name} has recorded the measurement {measurement}"); }); From b4ecbc4c22742f6719d4fcbd474d474c5c8407f6 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 29 Apr 2021 16:00:07 -0700 Subject: [PATCH 09/25] Update accepted/2021/System.Diagnostics/Metrics-Design.md Co-authored-by: Noah Falk --- accepted/2021/System.Diagnostics/Metrics-Design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index a235cf283..13d2650f1 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -32,7 +32,7 @@ There are two types of instruments: Meter is the factory type responsible for creating Instruments. Meter will have a name and optional version strings. -### Listener +### MeterListener The listener is the type that allows listening to the measurements reported by instruments (e.g. Counter, ObservableCounter, etc.). The listener is an important class that will be used by OpenTelemetry to implement the Metrics SDK. From b2a08ddccdfc6b399759fd24a99f3901c1fd8c6a Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 29 Apr 2021 16:02:39 -0700 Subject: [PATCH 10/25] Apply suggestions from code review Co-authored-by: Noah Falk --- accepted/2021/System.Diagnostics/Metrics-Design.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 13d2650f1..8c41381c5 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -248,7 +248,7 @@ namespace System.Diagnostics.Metrics { /// /// ObservableInstrument is the base class from which all observable instruments will inherit from. - /// Mainly It'll support the CLS compliant numerical types + /// It will only support the CLS compliant numerical types /// public abstract class ObservableInstrument : Instrument where T : unmanaged { @@ -262,7 +262,7 @@ namespace System.Diagnostics.Metrics string? unit) : base(meter, name, description, unit) { throw null; } /// - /// Observe will report the non-additive values of the measurements. + /// Observe() fetches the current measurements being tracked by this instrument. /// protected abstract IEnumerable> Observe(); @@ -278,7 +278,7 @@ namespace System.Diagnostics.Metrics namespace System.Diagnostics.Metrics { /// - /// A helper class used by the Observable instruments Observe method to report the measurement values + /// A measurement stores one observed value and its associated tags. This type is used by Observable instruments' Observe() method when reporting current measurements. /// with the associated tags. /// public struct Measurement where T : unmanaged @@ -465,7 +465,7 @@ namespace System.Diagnostics.Metrics /// /// Set a callback for a specific numeric type to get the measurement recording notification /// from all instruments which enabled listened to and was created with the same specified - /// numeric type. + /// numeric type. If a measurement of type T is recorded and a callback of type T is registered, that callback is used. If there is no callback for type T but there is a callback for type object, the measured value is boxed and reported via the object typed callback. If there is neither type T callback nor object callback then the measurement will not be reported. /// public void SetMeasurementEventCallback(MeasurementCallback? measurementCallback) { throw null; } From 952f05bd6705ca099628c536a53936397f29b6a3 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 29 Apr 2021 16:10:31 -0700 Subject: [PATCH 11/25] Feedback --- .../2021/System.Diagnostics/Metrics-Design.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 8c41381c5..08c75e9fb 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -220,22 +220,22 @@ namespace System.Diagnostics.Metrics protected void RecordMeasurement(T val) { throw null; } protected void RecordMeasurement( - T val, + T measurement, KeyValuePair tag1) { throw null; } protected void RecordMeasurement( - T val, + T measurement, KeyValuePair tag1, KeyValuePair tag2) { throw null; } protected void RecordMeasurement( - T val, + T measurement, KeyValuePair tag1, KeyValuePair tag2, KeyValuePair tag3) { throw null; } protected void RecordMeasurement( - T val, + T measurement, ReadOnlySpan> tags) { throw null; } } } @@ -278,7 +278,7 @@ namespace System.Diagnostics.Metrics namespace System.Diagnostics.Metrics { /// - /// A measurement stores one observed value and its associated tags. This type is used by Observable instruments' Observe() method when reporting current measurements. + /// A measurement stores one observed value and its associated tags. This type is used by Observable instruments' Observe() method when reporting current measurements. /// with the associated tags. /// public struct Measurement where T : unmanaged @@ -306,7 +306,7 @@ namespace System.Diagnostics.Metrics /// The counter is a non-observable Instrument that supports non-negative increments. /// e.g. Number of completed requests. /// - public class Counter : Instrument where T : unmanaged + public sealed class Counter : Instrument where T : unmanaged { public void Add(T measurement) { throw null; } public void Add(T measurement, @@ -328,7 +328,7 @@ namespace System.Diagnostics.Metrics /// UpDownCounter is a non-observable Instrument that supports increments and decrements. /// e.g. Number of items in a queue. /// - public class UpDownCounter : Instrument where T : unmanaged + public sealed class UpDownCounter : Instrument where T : unmanaged { public void Add(T measurement) { throw null; } public void Add(T measurement, @@ -351,7 +351,7 @@ namespace System.Diagnostics.Metrics /// that are likely to be statistically meaningful. It is intended for statistics such /// e.g. the request duration. /// - public class Histogram : Instrument where T : unmanaged + public sealed class Histogram : Instrument where T : unmanaged { public void Record(T measurement) { throw null; } public void Record( @@ -386,7 +386,7 @@ namespace System.Diagnostics.Metrics /// when the instrument is being observed. /// e.g. CPU time (for different processes, threads, user mode or kernel mode). /// - public class ObservableCounter : ObservableInstrument where T : unmanaged + public sealed class ObservableCounter : ObservableInstrument where T : unmanaged { protected override IEnumerable> Observe() { throw null; } } @@ -396,7 +396,7 @@ namespace System.Diagnostics.Metrics /// when the instrument is being observed. /// e.g. the process heap size /// - public class ObservableUpDownCounter : ObservableInstrument where T : unmanaged + public sealed class ObservableUpDownCounter : ObservableInstrument where T : unmanaged { protected override IEnumerable> Observe() { throw null; } } @@ -406,7 +406,7 @@ namespace System.Diagnostics.Metrics /// when the instrument is being observed. /// e.g. the current room temperature /// - public class ObservableGauge : ObservableInstrument where T : unmanaged + public sealed class ObservableGauge : ObservableInstrument where T : unmanaged { protected override IEnumerable> Observe() { throw null; } } From 6ad96b82ca699a2aec00dd7285380c76a91a0f30 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 29 Apr 2021 17:04:00 -0700 Subject: [PATCH 12/25] Rename cookie to state --- accepted/2021/System.Diagnostics/Metrics-Design.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 08c75e9fb..5d5cedf63 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -425,7 +425,7 @@ namespace System.Diagnostics.Metrics Instrument instrument, T measurement, ReadOnlySpan> tags, - object? cookie); + object? state); /// @@ -455,7 +455,7 @@ namespace System.Diagnostics.Metrics /// /// Start listening to a specific instrument measurement recording. /// - public void EnableMeasurementEvents(Instrument instrument, object? cookie = null) { throw null; } + public void EnableMeasurementEvents(Instrument instrument, object? state = null) { throw null; } /// /// Stop listening to a specific instrument measurement recording. @@ -503,7 +503,7 @@ namespace System.Diagnostics.Metrics listener.EnableMeasurementEvents(instrument, null); } }; - listener.SetMeasurementEventCallback((instrument, measurement, tags, cookie) => + listener.SetMeasurementEventCallback((instrument, measurement, tags, state) => { Console.WriteLine($"Instrument: {instrument.Name} has recorded the measurement {measurement}"); }); From 97e3b332cf1ad69407a0aefd4eab68242a2ac1a9 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 29 Apr 2021 17:07:18 -0700 Subject: [PATCH 13/25] Remove UpDownCounter --- .../2021/System.Diagnostics/Metrics-Design.md | 31 ++----------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 5d5cedf63..c9b645f50 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -25,7 +25,7 @@ The Instrument is the type that will be used by the app and library authors to r There are two types of instruments: -- The first type we'll call it just `Instrument` for simplicity. These instruments are called inside a request, meaning they have an associated distributed Context (with Span, Baggage, etc.). OpenTelemetry specs call this type of instrument a synchronous Instrument but we are trying to avoid confusion with the async feature of the .NET. The proposal here proposes three instrument classes of that type: `Counter`, `UpDownCounter`, and `Histogram`. +- The first type we'll call it just `Instrument` for simplicity. These instruments are called inside a request, meaning they have an associated distributed Context (with Span, Baggage, etc.). OpenTelemetry specs call this type of instrument a synchronous Instrument but we are trying to avoid confusion with the async feature of the .NET. The proposal here proposes three instrument classes of that type: `Counter` and `Histogram`. - The second type is called `ObservableInstrument` which reports measurements by a callback, once per collection interval, and lacks Context. OpenTelemetry specs call this type of instrument an asynchronous Instrument but we are trying to avoid confusion with the async feature of the .NET. The proposal here is proposing three instrument classes of that type: `ObservableCounter`, `ObservableGauge`, and `ObservableUpDownCounter`. ### Meter @@ -65,18 +65,13 @@ namespace System.Diagnostics.Metrics public string? Version { get; } /// - /// Factory Methods to create Counter, UpDownCounter, and Histogram instruments. + /// Factory Methods to create Counter and Histogram instruments. /// public Counter CreateCounter( string name, string? description = null, string? unit = null) where T : unmanaged { throw null; } - public UpDownCounter CreateUpDownCounter( - string name, - string? description = null, - string? unit = null) where T : unmanaged { throw null; } - public Histogram CreateHistogram( string name, string? description = null, @@ -324,28 +319,6 @@ namespace System.Diagnostics.Metrics params KeyValuePair[] tags) { throw null; } } - /// - /// UpDownCounter is a non-observable Instrument that supports increments and decrements. - /// e.g. Number of items in a queue. - /// - public sealed class UpDownCounter : Instrument where T : unmanaged - { - public void Add(T measurement) { throw null; } - public void Add(T measurement, - KeyValuePair tag1) { throw null; } - public void Add(T measurement, - KeyValuePair tag1, - KeyValuePair tag2) { throw null; } - public void Add(T measurement, - KeyValuePair tag1, - KeyValuePair tag2, - KeyValuePair tag3) { throw null; } - public void Add(T measurement, - ReadOnlySpan<> tags) { throw null; } - public void Add(T measurement, - params KeyValuePair[] tags) { throw null; } - } - /// /// The histogram is a non-observable Instrument that can be used to report arbitrary values /// that are likely to be statistically meaningful. It is intended for statistics such From 90fdd2395f6f36ef0931145d7231adf0587fd3f4 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 29 Apr 2021 17:27:22 -0700 Subject: [PATCH 14/25] Add MeterListener parameter to the InstrumentPublished callback --- accepted/2021/System.Diagnostics/Metrics-Design.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index c9b645f50..a66782a87 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -415,7 +415,7 @@ namespace System.Diagnostics.Metrics /// /// Callbacks to get notification when an instrument is published /// - public Action? InstrumentPublished { get; set; } + public Action? InstrumentPublished { get; set; } /// /// Callbacks to get notification when stopping the measurement on some instrument @@ -469,11 +469,11 @@ namespace System.Diagnostics.Metrics ```csharp InstrumentListener listener = new InstrumentListener(); - listener.InstrumentPublished = (instrument) => + listener.InstrumentPublished = (instrument, meterListener) => { if (instrument.Name == "Requests" && instrument.Meter.Name == "io.opentelemetry.contrib.mongodb") { - listener.EnableMeasurementEvents(instrument, null); + meterListener.EnableMeasurementEvents(instrument, null); } }; listener.SetMeasurementEventCallback((instrument, measurement, tags, state) => From 7c90d18ac32caf14ba2ece035f1b9a6b49bb8a52 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Fri, 30 Apr 2021 11:10:31 -0700 Subject: [PATCH 15/25] more Feedback --- accepted/2021/System.Diagnostics/Metrics-Design.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index a66782a87..ad7d1010a 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -212,7 +212,7 @@ namespace System.Diagnostics.Metrics /// Record measurement overloads allowing passing different numbers of tags. /// - protected void RecordMeasurement(T val) { throw null; } + protected void RecordMeasurement(T measurement) { throw null; } protected void RecordMeasurement( T measurement, @@ -314,7 +314,7 @@ namespace System.Diagnostics.Metrics KeyValuePair tag2, KeyValuePair tag3) { throw null; } public void Add(T measurement, - ReadOnlySpan<> tags) { throw null; } + ReadOnlySpan> tags) { throw null; } public void Add(T measurement, params KeyValuePair[] tags) { throw null; } } @@ -340,7 +340,7 @@ namespace System.Diagnostics.Metrics KeyValuePair tag2, KeyValuePair tag3) { throw null; } public void Record(T measurement, - ReadOnlySpan<> tags) { throw null; } + ReadOnlySpan> tags) { throw null; } public void Record( T measurement, params KeyValuePair[] tags) { throw null; } @@ -405,7 +405,7 @@ namespace System.Diagnostics.Metrics /// The listener class can be used to listen to observable and non-observable instrument /// recorded measurements. /// - public class MeterListener : IDisposable + public sealed class MeterListener : IDisposable { /// /// Simple constructor @@ -432,8 +432,9 @@ namespace System.Diagnostics.Metrics /// /// Stop listening to a specific instrument measurement recording. + /// returns the associated state. /// - public void DisableMeasurementEvents(Instrument instrument) { throw null; } + public object? DisableMeasurementEvents(Instrument instrument) { throw null; } /// /// Set a callback for a specific numeric type to get the measurement recording notification From ef1c421c9551d771442fd2cafdfa97fdd69e6dd2 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Fri, 30 Apr 2021 16:54:45 -0700 Subject: [PATCH 16/25] find KeyValuePait creation --- accepted/2021/System.Diagnostics/Metrics-Design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index ad7d1010a..126b8a47a 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -463,7 +463,7 @@ namespace System.Diagnostics.Metrics Meter meter = new Meter("io.opentelemetry.contrib.mongodb", "v1.0"); Counter counter = meter.CreateCounter("Requests"); counter.Add(1); - counter.Add(1, KeyValuePair("request", "read")); + counter.Add(1, KeyValuePair.Create("request", "read")); ``` ### Listening Example From f6fd8d9100a1d8f8b81a2c0e634ae705dd15f6ac Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Tue, 4 May 2021 15:14:10 -0700 Subject: [PATCH 17/25] fix param name --- accepted/2021/System.Diagnostics/Metrics-Design.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 126b8a47a..1dbbf054c 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -216,7 +216,7 @@ namespace System.Diagnostics.Metrics protected void RecordMeasurement( T measurement, - KeyValuePair tag1) { throw null; } + KeyValuePair tag) { throw null; } protected void RecordMeasurement( T measurement, @@ -305,7 +305,7 @@ namespace System.Diagnostics.Metrics { public void Add(T measurement) { throw null; } public void Add(T measurement, - KeyValuePair tag1) { throw null; } + KeyValuePair tag) { throw null; } public void Add(T measurement, KeyValuePair tag1, KeyValuePair tag2) { throw null; } @@ -329,7 +329,7 @@ namespace System.Diagnostics.Metrics public void Record(T measurement) { throw null; } public void Record( T measurement, - KeyValuePair tag1) { throw null; } + KeyValuePair tag) { throw null; } public void Record( T measurement, KeyValuePair tag1, From ca43c1e3f8a455255e543a26c3ba4048cbd7271a Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Tue, 4 May 2021 16:19:36 -0700 Subject: [PATCH 18/25] Make Observe method public --- accepted/2021/System.Diagnostics/Metrics-Design.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 1dbbf054c..bc5f77959 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -259,7 +259,7 @@ namespace System.Diagnostics.Metrics /// /// Observe() fetches the current measurements being tracked by this instrument. /// - protected abstract IEnumerable> Observe(); + public abstract IEnumerable> Observe(); public override bool IsObservable => throw null; } @@ -361,7 +361,7 @@ namespace System.Diagnostics.Metrics /// public sealed class ObservableCounter : ObservableInstrument where T : unmanaged { - protected override IEnumerable> Observe() { throw null; } + public override IEnumerable> Observe() { throw null; } } /// @@ -371,7 +371,7 @@ namespace System.Diagnostics.Metrics /// public sealed class ObservableUpDownCounter : ObservableInstrument where T : unmanaged { - protected override IEnumerable> Observe() { throw null; } + public override IEnumerable> Observe() { throw null; } } /// @@ -381,7 +381,7 @@ namespace System.Diagnostics.Metrics /// public sealed class ObservableGauge : ObservableInstrument where T : unmanaged { - protected override IEnumerable> Observe() { throw null; } + public override IEnumerable> Observe() { throw null; } } } ``` From fcda96df350c8cba21652d884353070a342e8187 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Tue, 4 May 2021 19:28:15 -0700 Subject: [PATCH 19/25] Make Observe as protected again --- accepted/2021/System.Diagnostics/Metrics-Design.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index bc5f77959..1dbbf054c 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -259,7 +259,7 @@ namespace System.Diagnostics.Metrics /// /// Observe() fetches the current measurements being tracked by this instrument. /// - public abstract IEnumerable> Observe(); + protected abstract IEnumerable> Observe(); public override bool IsObservable => throw null; } @@ -361,7 +361,7 @@ namespace System.Diagnostics.Metrics /// public sealed class ObservableCounter : ObservableInstrument where T : unmanaged { - public override IEnumerable> Observe() { throw null; } + protected override IEnumerable> Observe() { throw null; } } /// @@ -371,7 +371,7 @@ namespace System.Diagnostics.Metrics /// public sealed class ObservableUpDownCounter : ObservableInstrument where T : unmanaged { - public override IEnumerable> Observe() { throw null; } + protected override IEnumerable> Observe() { throw null; } } /// @@ -381,7 +381,7 @@ namespace System.Diagnostics.Metrics /// public sealed class ObservableGauge : ObservableInstrument where T : unmanaged { - public override IEnumerable> Observe() { throw null; } + protected override IEnumerable> Observe() { throw null; } } } ``` From c7f212daa7cc0f62611c2039d8bf15e2015f5ecd Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 6 May 2021 09:28:57 -0700 Subject: [PATCH 20/25] Remove un-needed comment --- accepted/2021/System.Diagnostics/Metrics-Design.md | 1 - 1 file changed, 1 deletion(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 1dbbf054c..3014d455d 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -422,7 +422,6 @@ namespace System.Diagnostics.Metrics /// this can happen when the Meter or the Listener is disposed of. Or calling Stop() /// on the listener. /// - // This need some clarification public Action? MeasurementsCompleted { get; set; } /// From 080fd74db05244e70dbcfe3257da9655781d5a2a Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 6 May 2021 16:42:44 -0700 Subject: [PATCH 21/25] Remove MeterListener.Stop() --- accepted/2021/System.Diagnostics/Metrics-Design.md | 1 - 1 file changed, 1 deletion(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 3014d455d..7560e9c08 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -443,7 +443,6 @@ namespace System.Diagnostics.Metrics public void SetMeasurementEventCallback(MeasurementCallback? measurementCallback) { throw null; } public void Start() { throw null; } - public void Stop() { throw null; } /// /// Call all Observable instruments to get the recorded measurements reported to the From 1643f1c2f9cd50b177eb08b68a560e8d827820fb Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 6 May 2021 17:07:30 -0700 Subject: [PATCH 22/25] fix some typo --- accepted/2021/System.Diagnostics/Metrics-Design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 7560e9c08..6722f50b7 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -25,7 +25,7 @@ The Instrument is the type that will be used by the app and library authors to r There are two types of instruments: -- The first type we'll call it just `Instrument` for simplicity. These instruments are called inside a request, meaning they have an associated distributed Context (with Span, Baggage, etc.). OpenTelemetry specs call this type of instrument a synchronous Instrument but we are trying to avoid confusion with the async feature of the .NET. The proposal here proposes three instrument classes of that type: `Counter` and `Histogram`. +- The first type we'll call it just `Instrument` for simplicity. These instruments are called inside a request, meaning they have an associated distributed Context (with Span, Baggage, etc.). OpenTelemetry specs call this type of instrument a synchronous Instrument but we are trying to avoid confusion with the async feature of the .NET. The proposal here proposes two instrument classes of that type: `Counter` and `Histogram`. - The second type is called `ObservableInstrument` which reports measurements by a callback, once per collection interval, and lacks Context. OpenTelemetry specs call this type of instrument an asynchronous Instrument but we are trying to avoid confusion with the async feature of the .NET. The proposal here is proposing three instrument classes of that type: `ObservableCounter`, `ObservableGauge`, and `ObservableUpDownCounter`. ### Meter From 9633070f6a5583216aed07c23657b4df92b97246 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Fri, 7 May 2021 08:33:23 -0700 Subject: [PATCH 23/25] Apply suggestions from code review Co-authored-by: Reiley Yang --- .../2021/System.Diagnostics/Metrics-Design.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 6722f50b7..5cf975ce4 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -2,7 +2,7 @@ ## Overview -This document is discussing the .NET Metrics APIs design which implements the [OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/new_api.md). +This document is discussing the .NET Metrics APIs design which implements the [OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md). The OpenTelemetry Metrics APIs support reporting measurements about the execution of a computer program at run time. The Metrics APIs are designed explicitly for processing raw measurements, generally with the intent to produce continuous summaries of those measurements, efficiently and simultaneously. @@ -21,12 +21,12 @@ deviating from the standard even if the standard names are not the best option f ### Instrument -The Instrument is the type that will be used by the app and library authors to report measurements (e.g. Counter, Gauge...etc.). The instrument will have a name that should be validated as described in the OpenTelemetry specs. The Instrument can optionally have a description and unit of measurements. Instruments will be created with a numerical type parameter (e.g. `Counter`). The Instrument is going to support all CLS-compliant numerical types which are supported on the Full Framework (Byte, Int16, Int32, Int64, Single, Double, and Decimal). +The Instrument is the type that will be used by the app and library authors to report measurements (e.g. Counter, ObservableGauge...etc.). The instrument will have a name that should be validated as described in the OpenTelemetry specs. The Instrument can optionally have a description and unit of measurements. Instruments will be created with a numerical type parameter (e.g. `Counter`). The Instrument is going to support all CLS-compliant numerical types which are supported on the Full Framework (Byte, Int16, Int32, Int64, Single, Double, and Decimal). There are two types of instruments: - The first type we'll call it just `Instrument` for simplicity. These instruments are called inside a request, meaning they have an associated distributed Context (with Span, Baggage, etc.). OpenTelemetry specs call this type of instrument a synchronous Instrument but we are trying to avoid confusion with the async feature of the .NET. The proposal here proposes two instrument classes of that type: `Counter` and `Histogram`. -- The second type is called `ObservableInstrument` which reports measurements by a callback, once per collection interval, and lacks Context. OpenTelemetry specs call this type of instrument an asynchronous Instrument but we are trying to avoid confusion with the async feature of the .NET. The proposal here is proposing three instrument classes of that type: `ObservableCounter`, `ObservableGauge`, and `ObservableUpDownCounter`. +- The second type is called `ObservableInstrument` which reports measurements by a callback, and lacks Context. OpenTelemetry specs call this type of instrument an asynchronous Instrument but we are trying to avoid confusion with the async feature of the .NET. The proposal here is proposing three instrument classes of that type: `ObservableCounter`, `ObservableGauge`, and `ObservableUpDownCounter`. ### Meter @@ -65,7 +65,7 @@ namespace System.Diagnostics.Metrics public string? Version { get; } /// - /// Factory Methods to create Counter and Histogram instruments. + /// Factory methods to create Counter and Histogram instruments. /// public Counter CreateCounter( string name, @@ -78,7 +78,7 @@ namespace System.Diagnostics.Metrics string? unit = null) where T : unmanaged { throw null; } /// - /// Factory Methods to create an observable Counter instrument. + /// Factory methods to create an ObservableCounter instrument. /// public ObservableCounter CreateObservableCounter( @@ -100,7 +100,7 @@ namespace System.Diagnostics.Metrics string? unit = null) where T : unmanaged { throw null; } /// - /// Factory Methods to create observable gauge instrument. + /// Factory methods to create ObservableGauge instrument. /// public ObservableGauge CreateObservableGauge( string name, @@ -121,7 +121,7 @@ namespace System.Diagnostics.Metrics string? unit = null) where T : unmanaged { throw null; } /// - /// Factory Methods to create observable UpDownCounter instrument. + /// Factory methods to create ObservableUpDownCounter instrument. /// public ObservableUpDownCounter CreateObservableUpDownCounter( string name, @@ -198,7 +198,7 @@ namespace System.Diagnostics.Metrics { /// /// Instrument is the base class from which all non-observable instruments will inherit from. - /// Mainly It'll support the CLS compliant numerical types + /// Mainly it will support the CLS compliant numerical types. /// public abstract class Instrument : Instrument where T : unmanaged { @@ -273,7 +273,7 @@ namespace System.Diagnostics.Metrics namespace System.Diagnostics.Metrics { /// - /// A measurement stores one observed value and its associated tags. This type is used by Observable instruments' Observe() method when reporting current measurements. + /// A measurement stores one observed value and its associated tags. This type is used by Observable instruments' Observe() method when reporting current measurements with associated tags. /// with the associated tags. /// public struct Measurement where T : unmanaged @@ -321,7 +321,7 @@ namespace System.Diagnostics.Metrics /// /// The histogram is a non-observable Instrument that can be used to report arbitrary values - /// that are likely to be statistically meaningful. It is intended for statistics such + /// that are likely to be statistically meaningful. It is intended for statistics such as the request duration. /// e.g. the request duration. /// public sealed class Histogram : Instrument where T : unmanaged From 6990f8c7ba10735227fc22558d91cda8a9b50b2d Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Fri, 7 May 2021 08:46:01 -0700 Subject: [PATCH 24/25] Minor fixes --- .../2021/System.Diagnostics/Metrics-Design.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 5cf975ce4..8e6e21177 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -191,13 +191,13 @@ namespace System.Diagnostics.Metrics } ``` -### Non-observable Instrument Base Class +### Instrument Base Class ```csharp namespace System.Diagnostics.Metrics { /// - /// Instrument is the base class from which all non-observable instruments will inherit from. + /// Instrument is the base class from which all instruments that report measurements in the context of the request will inherit from. /// Mainly it will support the CLS compliant numerical types. /// public abstract class Instrument : Instrument where T : unmanaged @@ -243,7 +243,7 @@ namespace System.Diagnostics.Metrics { /// /// ObservableInstrument is the base class from which all observable instruments will inherit from. - /// It will only support the CLS compliant numerical types + /// It will only support the CLS compliant numerical types. /// public abstract class ObservableInstrument : Instrument where T : unmanaged { @@ -261,7 +261,7 @@ namespace System.Diagnostics.Metrics /// protected abstract IEnumerable> Observe(); - public override bool IsObservable => throw null; + public override bool IsObservable => true; } } ``` @@ -292,13 +292,13 @@ namespace System.Diagnostics.Metrics } ``` -### Non-observable Instruments +### Instruments Concrete Classes ```csharp namespace System.Diagnostics.Metrics { /// - /// The counter is a non-observable Instrument that supports non-negative increments. + /// The counter is an Instrument that supports non-negative increments. /// e.g. Number of completed requests. /// public sealed class Counter : Instrument where T : unmanaged @@ -320,7 +320,7 @@ namespace System.Diagnostics.Metrics } /// - /// The histogram is a non-observable Instrument that can be used to report arbitrary values + /// The histogram is an Instrument that can be used to report arbitrary values /// that are likely to be statistically meaningful. It is intended for statistics such as the request duration. /// e.g. the request duration. /// @@ -402,7 +402,7 @@ namespace System.Diagnostics.Metrics /// - /// The listener class can be used to listen to observable and non-observable instrument + /// The listener class can be used to listen to kinds of instruments. /// recorded measurements. /// public sealed class MeterListener : IDisposable From dcdd911d5994c1d4211f4b18b4e52421867188b5 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Fri, 7 May 2021 17:14:01 -0700 Subject: [PATCH 25/25] Address the design review feedback --- .../2021/System.Diagnostics/Metrics-Design.md | 117 +++++++++--------- 1 file changed, 59 insertions(+), 58 deletions(-) diff --git a/accepted/2021/System.Diagnostics/Metrics-Design.md b/accepted/2021/System.Diagnostics/Metrics-Design.md index 8e6e21177..2f760102b 100644 --- a/accepted/2021/System.Diagnostics/Metrics-Design.md +++ b/accepted/2021/System.Diagnostics/Metrics-Design.md @@ -69,13 +69,13 @@ namespace System.Diagnostics.Metrics /// public Counter CreateCounter( string name, - string? description = null, - string? unit = null) where T : unmanaged { throw null; } + string? unit = null, + string? description = null) where T : struct { throw null; } public Histogram CreateHistogram( string name, - string? description = null, - string? unit = null) where T : unmanaged { throw null; } + string? unit = null, + string? description = null) where T : struct { throw null; } /// /// Factory methods to create an ObservableCounter instrument. @@ -84,20 +84,20 @@ namespace System.Diagnostics.Metrics public ObservableCounter CreateObservableCounter( string name, Func observeValue, - string? description = null, - string? unit = null) where T : unmanaged { throw null; } + string? unit = null, + string? description = null) where T : struct { throw null; } public ObservableCounter CreateObservableCounter( string name, Func> observeValue, - string? description = null, - string? unit = null) where T : unmanaged { throw null; } + string? unit = null, + string? description = null,) where T : struct { throw null; } public ObservableCounter CreateObservableCounter( string name, Func>> observeValues, - string? description = null, - string? unit = null) where T : unmanaged { throw null; } + string? unit = null, + string? description = null) where T : struct { throw null; } /// /// Factory methods to create ObservableGauge instrument. @@ -105,20 +105,20 @@ namespace System.Diagnostics.Metrics public ObservableGauge CreateObservableGauge( string name, Func observeValue, - string? description = null, - string? unit = null) where T : unmanaged { throw null; } + string? unit = null, + string? description = null,) where T : struct { throw null; } public ObservableGauge CreateObservableGauge( string name, Func> observeValue, - string? description = null, - string? unit = null) where T : unmanaged { throw null; } + string? unit = null, + string? description = null) where T : struct { throw null; } public ObservableGauge CreateObservableGauge( string name, Func>> observeValues, - string? description = null, - string? unit = null) where T : unmanaged { throw null; } + string? unit = null, + string? description = null) where T : struct { throw null; } /// /// Factory methods to create ObservableUpDownCounter instrument. @@ -126,20 +126,20 @@ namespace System.Diagnostics.Metrics public ObservableUpDownCounter CreateObservableUpDownCounter( string name, Func observeValue, - string? description = null, - string? unit = null) where T : unmanaged { throw null; } + string? unit = null, + string? description = null,) where T : struct { throw null; } public ObservableUpDownCounter CreateObservableUpDownCounter( string name, Func> observeValue, - string? description = null, - string? unit = null) where T : unmanaged { throw null; } + string? unit = null, + string? description = null,) where T : struct { throw null; } public ObservableUpDownCounter CreateObservableUpDownCounter( string name, Func>> observeValues, - string? description = null, - string? unit = null) where T : unmanaged { throw null; } + string? unit = null, + string? description = null) where T : struct { throw null; } public void Dispose() { throw null; } } @@ -162,7 +162,7 @@ namespace System.Diagnostics.Metrics /// /// Protected constructor to initialize the common instrument properties. /// - protected Instrument(Meter meter, string name, string? description, string? unit) { throw null; } + protected Instrument(Meter meter, string name, string? unit, string? description) { throw null; } /// /// Publish is to allow activating the instrument to start recording measurements and to allow @@ -175,8 +175,8 @@ namespace System.Diagnostics.Metrics /// public Meter Meter { get; } public string Name { get; } - public string? Description { get; } public string? Unit { get; } + public string? Description { get; } /// /// A property tells if a listener is listening to this instrument measurement recording. @@ -200,13 +200,13 @@ namespace System.Diagnostics.Metrics /// Instrument is the base class from which all instruments that report measurements in the context of the request will inherit from. /// Mainly it will support the CLS compliant numerical types. /// - public abstract class Instrument : Instrument where T : unmanaged + public abstract class Instrument : Instrument where T : struct { /// /// Protected constructor to create the instrument with the common properties. /// - protected Instrument(Meter meter, string name, string? description, string? unit) : - base(meter, name, description, unit) { throw null; } + protected Instrument(Meter meter, string name, string? unit, string? description) : + base(meter, name, unit, description) { throw null; } /// /// Record measurement overloads allowing passing different numbers of tags. @@ -245,7 +245,7 @@ namespace System.Diagnostics.Metrics /// ObservableInstrument is the base class from which all observable instruments will inherit from. /// It will only support the CLS compliant numerical types. /// - public abstract class ObservableInstrument : Instrument where T : unmanaged + public abstract class ObservableInstrument : Instrument where T : struct { /// /// Protected constructor to create the instrument with the common properties. @@ -253,8 +253,8 @@ namespace System.Diagnostics.Metrics protected ObservableInstrument( Meter meter, string name, - string? description, - string? unit) : base(meter, name, description, unit) { throw null; } + string? unit, + string? description) : base(meter, name, unit, description) { throw null; } /// /// Observe() fetches the current measurements being tracked by this instrument. @@ -276,12 +276,13 @@ namespace System.Diagnostics.Metrics /// A measurement stores one observed value and its associated tags. This type is used by Observable instruments' Observe() method when reporting current measurements with associated tags. /// with the associated tags. /// - public struct Measurement where T : unmanaged + public readonly struct Measurement where T : struct { /// /// Construct the Measurement using the value and the list of tags. /// We'll always copy the input list as this is not perf hot path. /// + public Measurement(T value) { throw null; } public Measurement(T value, IEnumerable> tags) { throw null; } public Measurement(T value, params KeyValuePair[] tags) { throw null; } public Measurement(T value, ReadOnlySpan> tags) { throw null; } @@ -301,22 +302,22 @@ namespace System.Diagnostics.Metrics /// The counter is an Instrument that supports non-negative increments. /// e.g. Number of completed requests. /// - public sealed class Counter : Instrument where T : unmanaged + public sealed class Counter : Instrument where T : struct { - public void Add(T measurement) { throw null; } - public void Add(T measurement, - KeyValuePair tag) { throw null; } - public void Add(T measurement, - KeyValuePair tag1, - KeyValuePair tag2) { throw null; } - public void Add(T measurement, - KeyValuePair tag1, - KeyValuePair tag2, - KeyValuePair tag3) { throw null; } - public void Add(T measurement, - ReadOnlySpan> tags) { throw null; } - public void Add(T measurement, - params KeyValuePair[] tags) { throw null; } + public void Add(T delta) { throw null; } + public void Add(T delta, + KeyValuePair tag) { throw null; } + public void Add(T delta, + KeyValuePair tag1, + KeyValuePair tag2) { throw null; } + public void Add(T delta, + KeyValuePair tag1, + KeyValuePair tag2, + KeyValuePair tag3) { throw null; } + public void Add(T delta, + ReadOnlySpan> tags) { throw null; } + public void Add(T delta, + params KeyValuePair[] tags) { throw null; } } /// @@ -324,25 +325,25 @@ namespace System.Diagnostics.Metrics /// that are likely to be statistically meaningful. It is intended for statistics such as the request duration. /// e.g. the request duration. /// - public sealed class Histogram : Instrument where T : unmanaged + public sealed class Histogram : Instrument where T : struct { - public void Record(T measurement) { throw null; } + public void Record(T value) { throw null; } public void Record( - T measurement, + T value, KeyValuePair tag) { throw null; } public void Record( - T measurement, + T value, KeyValuePair tag1, KeyValuePair tag2) { throw null; } public void Record( - T measurement, + T value, KeyValuePair tag1, KeyValuePair tag2, KeyValuePair tag3) { throw null; } - public void Record(T measurement, + public void Record(T value, ReadOnlySpan> tags) { throw null; } public void Record( - T measurement, + T value, params KeyValuePair[] tags) { throw null; } } } @@ -359,7 +360,7 @@ namespace System.Diagnostics.Metrics /// when the instrument is being observed. /// e.g. CPU time (for different processes, threads, user mode or kernel mode). /// - public sealed class ObservableCounter : ObservableInstrument where T : unmanaged + public sealed class ObservableCounter : ObservableInstrument where T : struct { protected override IEnumerable> Observe() { throw null; } } @@ -369,7 +370,7 @@ namespace System.Diagnostics.Metrics /// when the instrument is being observed. /// e.g. the process heap size /// - public sealed class ObservableUpDownCounter : ObservableInstrument where T : unmanaged + public sealed class ObservableUpDownCounter : ObservableInstrument where T : struct { protected override IEnumerable> Observe() { throw null; } } @@ -379,7 +380,7 @@ namespace System.Diagnostics.Metrics /// when the instrument is being observed. /// e.g. the current room temperature /// - public sealed class ObservableGauge : ObservableInstrument where T : unmanaged + public sealed class ObservableGauge : ObservableInstrument where T : struct { protected override IEnumerable> Observe() { throw null; } } @@ -398,7 +399,7 @@ namespace System.Diagnostics.Metrics Instrument instrument, T measurement, ReadOnlySpan> tags, - object? state); + object? state) where T : struct; /// @@ -440,7 +441,7 @@ namespace System.Diagnostics.Metrics /// from all instruments which enabled listened to and was created with the same specified /// numeric type. If a measurement of type T is recorded and a callback of type T is registered, that callback is used. If there is no callback for type T but there is a callback for type object, the measured value is boxed and reported via the object typed callback. If there is neither type T callback nor object callback then the measurement will not be reported. /// - public void SetMeasurementEventCallback(MeasurementCallback? measurementCallback) { throw null; } + public void SetMeasurementEventCallback(MeasurementCallback? measurementCallback) where T : struct { throw null; } public void Start() { throw null; }