-
Notifications
You must be signed in to change notification settings - Fork 863
[hosting] Support .NET 8 IMetricsBuilder API #4958
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 37 commits
9331203
b70f529
e411e22
dc4f60e
6db3bcb
680c506
496002f
3a03fa3
558df37
32a0388
25e7ef9
5ea6211
5d645eb
82b384d
f4c254a
995d2c4
9c87e60
3fd9045
c507377
fe10eb6
24322e8
3fe5702
bfec275
c728717
934e75b
467008e
f22cdf8
f5b2e6f
ec19a81
01114b3
4012f83
cd393f7
1500698
c2cb6be
0b623e9
9831c9f
6905583
cc195ba
d993289
0862f7f
f73d309
da5554b
f748914
7685521
8c4c9d2
54da2d9
97f3bf5
abbcbb1
7744d5e
9ab7c58
f2fce4a
152220c
1c264e8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| // <copyright file="OpenTelemetryMetricListener.cs" company="OpenTelemetry Authors"> | ||
| // Copyright The OpenTelemetry Authors | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
| // </copyright> | ||
|
|
||
| using System.Diagnostics; | ||
| using System.Diagnostics.Metrics; | ||
| using Microsoft.Extensions.Diagnostics.Metrics; | ||
|
|
||
| namespace OpenTelemetry.Metrics; | ||
|
|
||
| internal sealed class OpenTelemetryMetricListener : IMetricsListener, IDisposable | ||
CodeBlanch marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| private readonly MeterProviderSdk meterProviderSdk; | ||
| private IObservableInstrumentsSource? observableInstrumentsSource; | ||
|
|
||
| public OpenTelemetryMetricListener(MeterProvider meterProvider) | ||
| { | ||
| var meterProviderSdk = meterProvider as MeterProviderSdk; | ||
|
|
||
| Debug.Assert(meterProviderSdk != null, "meterProvider was not MeterProviderSdk"); | ||
|
|
||
| this.meterProviderSdk = meterProviderSdk!; | ||
|
|
||
| this.meterProviderSdk.OnCollectObservableInstruments += this.OnCollectObservableInstruments; | ||
| } | ||
|
|
||
| public string Name => "OpenTelemetry"; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What are the consequences of an app registering another listener by this same name? Is there any reason we should obscure a name a bit to reduce the chance of collision?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This name is important. It tells the engine how to bind settings for our listener. Similar to how in logging you can have different log levels for each For example you can do things like this: "Metrics": {
"EnabledMetrics": {
"Default": false
},
"SomeMetricsSDK": {
"EnabledMetrics": {
"System.Net": true
}
},
"OpenTelemetry": {
"EnabledMetrics": {
"Default": true
}
}
}The name we use here is what users will need to put in their configuration.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok got it. The name is fine by me. Though what is the consequence of registering one by the same name? Does the last one win? Is there any chance that the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The actual registration we do is done via To say that another way, the subscription manager operates on the IEnumerable<IMetricsListener>s registered in the container. It doesn't make like a dictionary using the name(s). The name is only used to look up the config/rules that apply to the listener. |
||
|
|
||
| public void Dispose() | ||
| { | ||
| this.meterProviderSdk.OnCollectObservableInstruments -= this.OnCollectObservableInstruments; | ||
| } | ||
|
|
||
| public MeasurementHandlers GetMeasurementHandlers() | ||
| { | ||
| return new MeasurementHandlers() | ||
| { | ||
| ByteHandler = (instrument, value, tags, state) | ||
| => this.MeasurementRecordedLong(instrument, value, tags, state), | ||
| ShortHandler = (instrument, value, tags, state) | ||
| => this.MeasurementRecordedLong(instrument, value, tags, state), | ||
| IntHandler = (instrument, value, tags, state) | ||
| => this.MeasurementRecordedLong(instrument, value, tags, state), | ||
| LongHandler = this.MeasurementRecordedLong, | ||
| FloatHandler = (instrument, value, tags, state) | ||
| => this.MeasurementRecordedDouble(instrument, value, tags, state), | ||
| DoubleHandler = this.MeasurementRecordedDouble, | ||
| }; | ||
| } | ||
|
|
||
| public bool InstrumentPublished(Instrument instrument, out object? userState) | ||
| { | ||
| userState = this.meterProviderSdk.InstrumentPublished(instrument, listeningIsManagedExternally: true); | ||
| return userState != null; | ||
| } | ||
|
|
||
| public void MeasurementsCompleted(Instrument instrument, object? userState) | ||
| { | ||
| var meterProvider = this.meterProviderSdk; | ||
|
|
||
| if (meterProvider.ViewCount > 0) | ||
| { | ||
| meterProvider.MeasurementsCompleted(instrument, userState); | ||
| } | ||
| else | ||
| { | ||
| meterProvider.MeasurementsCompletedSingleStream(instrument, userState); | ||
| } | ||
| } | ||
|
|
||
| public void Initialize(IObservableInstrumentsSource source) | ||
| { | ||
| this.observableInstrumentsSource = source; | ||
| } | ||
|
|
||
| private void OnCollectObservableInstruments() | ||
| { | ||
| this.observableInstrumentsSource?.RecordObservableInstruments(); | ||
| } | ||
|
|
||
| private void MeasurementRecordedDouble(Instrument instrument, double value, ReadOnlySpan<KeyValuePair<string, object?>> tagsRos, object? userState) | ||
| { | ||
| var meterProvider = this.meterProviderSdk; | ||
|
|
||
| if (meterProvider.ViewCount > 0) | ||
| { | ||
| meterProvider.MeasurementRecordedDouble(instrument, value, tagsRos, userState); | ||
| } | ||
| else | ||
| { | ||
| meterProvider.MeasurementRecordedDoubleSingleStream(instrument, value, tagsRos, userState); | ||
| } | ||
| } | ||
|
|
||
| private void MeasurementRecordedLong(Instrument instrument, long value, ReadOnlySpan<KeyValuePair<string, object?>> tagsRos, object? userState) | ||
| { | ||
| var meterProvider = this.meterProviderSdk; | ||
|
|
||
| if (meterProvider.ViewCount > 0) | ||
| { | ||
| meterProvider.MeasurementRecordedLong(instrument, value, tagsRos, userState); | ||
| } | ||
| else | ||
| { | ||
| meterProvider.MeasurementRecordedLongSingleStream(instrument, value, tagsRos, userState); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| // <copyright file="OpenTelemetryMetricsBuilderExtensions.cs" company="OpenTelemetry Authors"> | ||
| // Copyright The OpenTelemetry Authors | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
| // </copyright> | ||
|
|
||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.DependencyInjection.Extensions; | ||
| using OpenTelemetry.Internal; | ||
| using OpenTelemetry.Metrics; | ||
|
|
||
| namespace Microsoft.Extensions.Diagnostics.Metrics; | ||
|
|
||
| /// <summary> | ||
| /// Contains extension methods for registering OpenTelemetry metrics with an | ||
| /// <see cref="IMetricsBuilder"/> instance. | ||
| /// </summary> | ||
| internal static class OpenTelemetryMetricsBuilderExtensions | ||
| { | ||
| /// <summary> | ||
| /// Adds an OpenTelemetry <see cref="IMetricsListener"/> named 'OpenTelemetry' to the <see cref="IMetricsBuilder"/>. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// Note: This is safe to be called multiple times and by library authors. | ||
utpilla marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /// Only a single <see cref="MeterProvider"/> will be created for a given | ||
| /// <see cref="IServiceCollection"/>. | ||
| /// </remarks> | ||
| /// <param name="metricsBuilder"><see cref="IMetricsBuilder"/>.</param> | ||
| /// <returns>The supplied <see cref="IMetricsBuilder"/> for chaining | ||
| /// calls.</returns> | ||
| public static IMetricsBuilder UseOpenTelemetry( | ||
| this IMetricsBuilder metricsBuilder) | ||
| => UseOpenTelemetry(metricsBuilder, b => { }); | ||
|
|
||
| /// <summary> | ||
| /// Adds an OpenTelemetry <see cref="IMetricsListener"/> named 'OpenTelemetry' to the <see cref="IMetricsBuilder"/>. | ||
| /// </summary> | ||
| /// <remarks><inheritdoc cref="UseOpenTelemetry(IMetricsBuilder)" path="/remarks"/></remarks> | ||
| /// <param name="metricsBuilder"><see cref="IMetricsBuilder"/>.</param> | ||
| /// <param name="configure"><see cref="MeterProviderBuilder"/> | ||
| /// configuration callback.</param> | ||
| /// <returns>The supplied <see cref="IMetricsBuilder"/> for chaining | ||
| /// calls.</returns> | ||
| public static IMetricsBuilder UseOpenTelemetry( | ||
| this IMetricsBuilder metricsBuilder, | ||
| Action<MeterProviderBuilder> configure) | ||
| { | ||
| Guard.ThrowIfNull(metricsBuilder); | ||
| Guard.ThrowIfNull(configure); | ||
|
|
||
| var builder = new MeterProviderBuilderBase(metricsBuilder.Services); | ||
|
|
||
| metricsBuilder.Services.TryAddEnumerable( | ||
| ServiceDescriptor.Singleton<IMetricsListener, OpenTelemetryMetricListener>()); | ||
|
|
||
| configure(builder); | ||
|
|
||
| return metricsBuilder; | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.