-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Remove/reduce usage of MetricBuildItem #10626
Conversation
...ntime/src/main/java/io/quarkus/hibernate/orm/runtime/metrics/HibernateMpMetricsProvider.java
Outdated
Show resolved
Hide resolved
This PR moves metric registration from STATIC_INIT to a runtime |
I am sure we could go back a step and make this happen sooner. In this case, I followed what Ken did to get the micrometer hibernate binder working w/ the extension. In all things, there is eventually an order (these x things must be present to connect the dots). The key in this case is knowing the persistence units defined by the application. What was done previously was done at static init, but it also only looked for the default persistence unit.
It does break that approach, and it is something I think we should explore because the MetricBuildItem pattern bakes in hard dependencies between MP Metrics and deployment modules, and doesn't add a lot of benefit in trade. (From the quarkus micrometer extension, look @ the integration test that uses hibernate.. in theory, that doesn't use SmallRye metrics at all, so SmallRye/MP Metrics shouldn't show up on the classpath as anything other than an optional compile dep... BUT.. because the deployment module uses MetricBuildItem and defines/references some metrics classes in its BuildItems, the Hibernate ORM extension itself has a hard dependency on the MP Metrics API). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know there's been other discussions around registering metrics prior to startup, so my only comment is on the class description
...ntime/src/main/java/io/quarkus/hibernate/orm/runtime/metrics/HibernateMpMetricsProvider.java
Outdated
Show resolved
Hide resolved
I don't think this is ready until the Writing Extensions guide is updated with a concise new strategy how extensions should do this from now on, because this clearly goes against what we currently have documented. |
It is still in draft, and that's part of why. I have something else in flight now (see the "alternate build item" commit) that would be used to replace that part of the extension guide. |
Added revisions to the extension guide to use the new build item. It cleans up a lot. I think we need some additional guidance there (don’t count what can be timed, use overlapping names that take advantage of tags to support aggregation, etc) |
MetricsFactory for micrometer (to compare w/ SmallRye impl): https://github.com/ebullient/quarkus-micrometer-extension/blob/experimental/runtime/src/main/java/dev/ebullient/micrometer/runtime/MicrometerMetricsFactory.java |
core/runtime/src/main/java/io/quarkus/runtime/metrics/MetricsFactory.java
Outdated
Show resolved
Hide resolved
...etrics/runtime/src/main/java/io/quarkus/smallrye/metrics/runtime/SmallRyeMetricsFactory.java
Outdated
Show resolved
Hide resolved
* | ||
* @param countFunction Function supplying a monotonically increasing number value | ||
*/ | ||
void counter(Supplier<Number> countFunction); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if an extension needs to create a counter that will be updated via calls to inc()
rather than be a supplier or function? I guess we need a counter()
function here without parameters that just registers a plain counter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my intent was to use supplier or ToDoubleFunction always via the shared API. IMO, it is a best practice for reusable libraries anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, but it would force some libraries to make significant changes, because they work by calling inc()
and don't create any state objects for their counters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am going to go find out how common that is. So far, it isn't very. And yes, this is on me to achieve. The goal of this common facade is to make that transition easier... but the model here is what Hibernate, Agroal, and Vert.x use..
Creating any kind of additional Counter interface introduces a lot of wrapper items (which is essentially what the Counter type is.. it just isn't managed by the library.
MP Metrics, FWIW, uses long values with inc() for counters, while Micrometer uses double values with increment(). This is why a simple "counter" interface isn't as simple as it sounds. A MeterBinder pattern works best to cover this case (using metricsSystemSupported method to do something more advanced/native/specific).
In the case of http (for example), I'm doing something native to micrometer for tracking http/eventbus/... metrics within the micrometer extension. I imagine the MP Metrics extension will do the same, and I think (for that case) it is the wiser thing to do. For Micrometer, there are existing MeterBinders that can be reused/pulled in (still @ bytecode recording time), and I prefer to reuse those where we can (this is where metricsSystemSupported
can be used for deferred imports to ensure optional/compile-only dependencies.
core/runtime/src/main/java/io/quarkus/runtime/metrics/MetricsFactory.java
Show resolved
Hide resolved
core/runtime/src/main/java/io/quarkus/runtime/metrics/MetricsFactory.java
Outdated
Show resolved
Hide resolved
...trics/runtime/src/main/java/io/quarkus/smallrye/metrics/runtime/SmallRyeMetricsRecorder.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Thanks!
...eployment/src/main/java/io/quarkus/smallrye/metrics/deployment/SmallRyeMetricsProcessor.java
Show resolved
Hide resolved
Well, we already do this (except it's in the resteasy extension: https://github.com/quarkusio/quarkus/blob/1.6.1.Final/extensions/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerCommonProcessor.java#L444). But this approach only allows the metrics to be registered at runtime (when the REST resources are first called), what I'm talking about is moving the registration to build-time, for which I'd need to use the Then I got an idea that we could probably do this by producing (in the RestEasy extension) a I'm not sure if we solve the circular dependency by moving this logic from the resteasy extension to the smallrye-metrics extension - because it depends on configuration values of the resteasy extension - can an extension read the config of a different extension? EDIT: yes it should be possible (but I haven't checked it in practice). Any better ideas how to eagerly register the SimpleTimers described in the MP Metrics spec (https://download.eclipse.org/microprofile/microprofile-metrics-2.3/microprofile-metrics-spec-2.3.html#_optional_rest)? |
One option is to not worry about MP Metrics REST endpoints, and their eager instantiation, and focus on shifting the spec towards the direction it needs to go. With the proposed direction we're thinking of, I believe metrics would be eager and instrumented at the appropriate level without issue |
This does not have anything to do with improving the spec for the future (which we definitely will do, but that's a longer term goal), this is fixing an immediate problem that several users have reported lately and I've promised them a resolution. |
But if we can give them the functionality they're requesting by moving things forward away from MP Metrics, doesn't that solve the underlying concern without adding solutions that we don't necessarily like just because of "where things stand now"? |
Taking things one bit at a time: There is a way to declare/use timers in a simple way via the MetricsFactory. In the case of more extensive build or runtime instrumentation for timers, I think that has to move into the metrics extension. E.g. for micrometer, the vert.x binder is enabled or disabled and includes all REST traffic -- it wouldn't do anything with RESTEasy at all. I think enable/disable of metrics can (in the enable/disable case at least) move to the metrics extension. Detailed adaptation (jaeger, maybe hibernate/agroal) can be in the provider extension, and yes, it would then have a compile-time/optional dependence on the API package only (not the extension, just the API, and preferably only in the runtime module, and not in the deployment module). It could use the MetricsCapability build item to determine at build time which system to initialize. |
@gsmet any concerns from your side in merging this? |
Declared MetricBuildItems were processed at STATIC_INIT time previously. In the new case, there are a few choices, but all rely on a recorder to keep API dependencies in the runtime module. Usage could still be recorded (to eagerly register metrics) at either STATIC_INIT or RUNTIME_INIT. While the mechanism around declaring the metrics is different (to avoid deployment module entanglement), registration processing time (bytecode recording time) is the same (or can be earlier than currently) |
I don't have a strong opinion about it. @jmartisk is really the guardian of this part so I let him handle that one. As long as it gets merged before CR1 is packaged (planned for this Thursday), I'm good with it. |
I'm not sure we're on the same page here, my comment wasn't about bytecode recording phases, I was asking how to use the If such cases want to continue working (after this PR) without using hacks like what I sketched in #10626 (comment), they will have to stay with the original I'm not against merging this PR as I agree with its longer-term usefulness, I'm just pointing out the potential mess that we're creating at the same time. Given these circumstances, could we perhaps hold this off until 1.8? Or do we really want it in 1.7? I'm not that comfortable including such large changes at the last minute before release, especially if it does not directly benefit users of that release, but rather it changes things for extension developers. |
To head us on the path we want to be on, I believe we do need to merge this sooner rather than later. Once this is merged, we can look to include a Micrometer based extension. As this changes developing extensions a bit in the direction we want, it would be good to include this in 1.7. |
@kenfinnigan if you plan to ship the Micrometer extension with Quarkus Core itself (or even the platform), I would say it could wait for 1.8 because there's no chance we will be able to merge it before 1.7.0.Final. Or is there a secret plan I'm not aware of? |
micrometer would come in for 1.8, for sure. From 1.7 perspective, this is about shifting the doc and guidance for extensions using metrics. |
Right, the actual Micrometer extension wouldn't be included until post 1.7 |
If so, and if we don't expect it being a pain, I would rather merge this at the beginning of the 1.8 cycle. I see potential risks and no benefits for the user (until a Micrometer extension is introduced) but maybe I'm mistaken? Feel free to correct me if I have an incorrect image of this as I haven't followed this subject closely. |
Yesterday morning I agreed with you @gsmet, but then @ebullient pointed out there are changes to how to integrate with metrics for extension writers that is important to include for the next product release |
MetricsFactoryConsumerBuildItem, MetricsCapabilityBuildItem
I've updated the SmallRyeMetricsFactory to create SimpleTimer instead (as we discussed). An extension could cast the MetricsFactory in the recorder if they wanted, or they could use the API directly. Metrics can be a hot path, so while the MetricsFactory is designed to cover the 80% case, in the event that something more interesting is warranted, dropping to direct usage of the API will be better (MP Metrics histogram vs. Micrometer distribution summary, e.g.).
Introducing the new build item doesn't break existing usage of the deprecated build item. We can work with those community projects to help them transition to something that makes the most sense.
This is a non-breaking change, so that is expected. You have to start somewhere.
Again, I expect this will change over time. What we can do is remove the dependency between deployment modules for the extensions (while the API requirement would remain).
This is just the first (non-breaking) step. The changes I have included for hibernate, agroal, jaeger, and k8s aren't strictly required, but they do prove that the new build item can be used to satisfy a few different use cases.
We will have more options with this build item, at a minimum.
If the "large" bits (hibernate, agroal, jaeger, k8s) are an issue, I can move those commits into a different PR. While they move pieces around, they are not destructive (nor do I consider them risky). |
Lots of great discussion on here but it sounds like most of the remaining points are issues we can look into as part of subsequent work on 1.8. AFAICT everything pertaining to the abstraction has been dealt with. The risk items that @gsmet brings up are excellent concerns this close to 1.7, but it sounds like @ebullient and @kenfinnigan have a high degree of confidence based on testing, and the point @kenfinnigan states above about increased adoption of an API we all know will change very soon is also important. On the balance I find this argument convincing and agree we should merge. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very well, after some contemplation with my skeptical hat on, I finally give this my blessing.
Thanks @n1hility for your insight and @kenfinnigan and @ebullient for your patience with me ;)
Remove/reduce usage of MetricBuildItem to allow support for different metrics systems.
This will resolve #8272
@Sanne -- this is the next step of our conversation. This is similar / comparable to what the micrometer HibernateMeterBinder does, and is a basic re-frame of what the MetricBuildItem did, but is more direct.
@kenfinnigan / @jmartisk : FYI & review, too
For Hibernate-ORM metrics produced look like this w/ the changes in this PR: