Skip to content

Remove Meter<T> #4049

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

Closed
noahfalk opened this issue Jun 8, 2023 · 6 comments · Fixed by #4342
Closed

Remove Meter<T> #4049

noahfalk opened this issue Jun 8, 2023 · 6 comments · Fixed by #4342
Assignees
Milestone

Comments

@noahfalk
Copy link
Member

noahfalk commented Jun 8, 2023

dotnet/extensions defines a Meter<T> type that doesn't work with the newly introduced MeterFactory and doesn't align with guidance we plan to give users for writing metrics in a DI-aware scenario. We should remove this type.

@noahfalk noahfalk added this to the 8.0 Preview6 milestone Jun 8, 2023
@geeknoid
Copy link
Member

geeknoid commented Jun 8, 2023

@dpk83 Can you provide a quick rationale for keeping Meter? I believe it's mostly about usability, reducing the ceremony for customers.

@noahfalk Can you provide a quick explanation why it doesn't work with MeterFactory? I believe it's related to instrument reference?

@dpk83
Copy link

dpk83 commented Jun 8, 2023

@dpk83 Can you provide a quick rationale for keeping Meter? I believe it's mostly about usability, reducing the ceremony for customers.

  • Simpler way to inject Meter of T. One step process Meter instead of 2 step process inject IMeterFactory and then IMeterFactory.Create
  • Less prone to errors in naming meters. Meter will pick up T's name, if developer needs to inject IMeterFactory and then create meter on their own, some of them might end up creating meter with custom names instead IMeterFactory.Create("meterName"). So for organizations/services then wants to ensure that T is used for meter name, need to build something additional to ensure the naming consistency

@noahfalk
Copy link
Member Author

noahfalk commented Jun 9, 2023

Can you provide a quick explanation why it doesn't work with MeterFactory?

There is Meter<T> as it is currently implemented in dotnet/extensions, and then the less simple explanation that tries to anticipate possible alternate implementations of Meter<T> and what problems arise there.

As currently implemented Meter<T> does not populate the new scope parameter of the Meter constructor. This parameter is used to distinguish Meters in different DI containers. For example this pattern we planned to tell users to do would not work:

// assume we have some type created in DI with constructor: MyWidget(Meter<MyWidget> meter)
var factory = services.GetRequiredService<IMeterFactory>();
var recorder = new InstrumentRecorder(factory, "MyWidget", "MyCounter");
var widget = services.GetRequiredService<MyWidget>();

// act
widget.DoSomething();

// assert
Assert(1, recorder.GetMeasurements().Count); // this fails because the MyWidget meter isn't associated
                                             // with the factory

There has also been some vocal feedback from folks who do not like particular designs, including opposition to Meter<T> on principle. Regardless of anyone's specific position that Meter<T> is a good or bad design choice, discussion on that topic ended when we said we were no longer pursuing it on the public issue. If we reverse our earlier decision, its reasonable that folks who were opposed to it before would expect opportunity for debate would resume.

Another issue is that Meter<T> doesn't handle cases where users want to specify any other Meter constructor argument like version or tags. Switching between injecting the factory or the Meter<T> is of course doable, but complicates the guidance and isn't easily discoverable without resorting to docs.

And then a bunch of hypotheticals:

  • What if users passed null instead of factory to the recorder? In isolation the unit test would work, but run in parallel it would fail because the Meters aren't being associated with the unique DI container in each test.
  • What if we changed Meter<T> to look like public Meter<T>(IMeterFactory factory) : Meter(..., scope:factory)?
    The test passes, but we didn't ever call IMeterFactory.Create() to create these Meters which defies user's expectations of what it means to have a factory.
  • What if we do what ILogger<T> does and create a 2nd inner type that is constructed by the factory?
    Now unit tests that test by factory+name pass, but unit tests that identify the Meter<T> by reference fail because there is a difference in object identity between the Meter that was passed to constructor and the Meter that was used for recording measurements. It also has very counter-intuitive behavior where meter.CreateCounter().Meter != meter.

Maybe the right clever design can solve all the concerns or we could start suggesting broader changes that replace IMeterFactory with something else but the biggest issue is that we don't have time to play that process out. IMeterFactory, Meter<T> and IMeter<T> were already considered and resolved during a 4 month period of design and feedback. Its certainly unfortunate if the impact of the decisions being made there weren't clear and it feels like something went awry in the review or communication that we need to improve on. However I don't see any path that brings in Meter<T> without effectively resetting the discussion back to where we were in February and starting again.

@RussKie RussKie modified the milestones: 8.0 Preview6, 8.0 Preview7 Jun 21, 2023
@RussKie RussKie modified the milestones: 8.0 Preview7, 8.0 RC1 Jul 19, 2023
@joperezr
Copy link
Member

@noahfalk @geeknoid Is there something we still want to do for extensions here?

@xakep139
Copy link
Contributor

@klauco did we agree on removing Meter<T>?

@RussKie RussKie removed the untriaged label Aug 18, 2023
@joperezr joperezr assigned xakep139 and unassigned geeknoid Aug 29, 2023
xakep139 added a commit that referenced this issue Aug 31, 2023
@xakep139 xakep139 linked a pull request Aug 31, 2023 that will close this issue
@RussKie RussKie modified the milestones: 8.0 RC1, 8.0 RC2, 8.0-rtm Sep 14, 2023
geeknoid pushed a commit that referenced this issue Sep 27, 2023
* #4049 Remove generic Meter<T>

* first component test migration from Meter<T>

* fix source-gen test class

* fixes after initial feedback

* CR

* fix the link

* fix version details XML

* Update Microsoft.AspNetCore.HeaderParsing.csproj

* migrate resource monitoring

* fix duplicated file

* migrate HealthChecks package

* migrate Resilience packages

* fixes after merge

* Update src/Libraries/Microsoft.Extensions.Diagnostics.Testing/Metrics/MetricCollector.cs

* minor updates

* Apply suggestions from code review

* minor improvements

---------

Co-authored-by: Nikita Balabaev <[email protected]>
@ghost ghost removed the work in progress 🚧 label Sep 27, 2023
@xakep139
Copy link
Contributor

Done via #4342

@ghost ghost removed this from the 8.0-rtm milestone Sep 27, 2023
@xakep139 xakep139 added this to the 8.0-rtm milestone Sep 27, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Oct 27, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants