Skip to content
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

Add support for MP Metrics 2.3 #2245

Merged
merged 54 commits into from
Aug 12, 2020
Merged

Add support for MP Metrics 2.3 #2245

merged 54 commits into from
Aug 12, 2020

Conversation

tjquinno
Copy link
Member

Resolves #2140

REST.request overview

Quite a few of the changes below support the REST.request optional feature, in which each JAX-RS endpoint is automatically measured by a distinct SimpleTimer metric. Here's the overview of how that's implemented:

  1. The CDI extension adds a "synthetic" annotation (used only internally) to each JAX-RS endpoint.
  2. The extension also registers the correct SimpleTimer metric for each endpoint.
  3. At invocation-time the interceptor looks up the appropriate SimpleTimer instance and uses it to measure the work done in the intercepted method.

Summary of changes by module

metrics/metrics
Add HelidonSimpleTimer impl of new SimpleTimer metric
Update Registry with SimpleTimer-related methods
New tests for SimpleTimer

microprofile/metrics
Add infrastructure for @SimplyTimed in various classes

Add internal @SyntheticSimplyTimed; marker interface so CDI will trigger interception.
Add interceptor for above that looks up or creates the matching SimpleTimer to update.

Update CDI extension:

  • Tell CDI about the synthetic annotation and its interceptor. (This allows the normal CDI mechanisms to take care of setting up the interceptor where needed.)
  • Dynamically add synthetic @SyntheticSimplyTimed to each JAX-RS endpoint method so CDI will automatically invoke the corresponding interceptor.
  • Record (during @ProcessAnnotatedType) and then register (during @AfterDeploymentValidation) the SimpleTimer metrics for each method with @SyntheticSimplyTimed

Add tests

tck/tck-metrics
Add dependency to include optional tests
Because MP metrics 2.3.2 uses non-standard constructs, add an ArrayParamConverter and its provider to CDI
Add CDI extension to register the converter provider
Add UrlResourceProvider as in several other TCK projects; TCK fetches deployment URI

examples/archetypes
Add config setting enabling REST.request behavior in MP quickstart example and archetype.

Add explicit config setting to disable REST.request in other examples as a reminder that the feature is there without turning it on.

docs
MP metrics guide
Update example output because REST.request metrics now appear
Add brief section describing config control of the feature
Add brief discussion of SimpleTimer and @SimplyTimed

SE metrics guide
Add brief discussion of SimpleTimer

…mer to data structures

Signed-off-by: tim.quinn@oracle.com <tim.quinn@oracle.com>
…g to MP metrics 2.3

Signed-off-by: tim.quinn@oracle.com <tim.quinn@oracle.com>
…mer to data structures

Signed-off-by: tim.quinn@oracle.com <tim.quinn@oracle.com>
…ints to trigger REST.request SimpleTimer updates
Signed-off-by: tim.quinn@oracle.com <tim.quinn@oracle.com>
…ng metrics

Signed-off-by: tim.quinn@oracle.com <tim.quinn@oracle.com>
…cs to microprofile/tests/tck/tck-metrics so it cannot even accidentally be used by developers
ljnelson
ljnelson previously approved these changes Aug 11, 2020
@@ -166,6 +184,19 @@ curl -H "Accept: application/json" http://localhost:8080/metrics/vendor/grpc.re

NOTE: You cannot get the individual fields of a metric. For example, you cannot target http://localhost:8080/metrics/vendor/grpc.requests.meter.count.

==== Controlling `REST.request` metrics
Helidon implements the optional family of metrics, all with the name `REST.request`, as described in the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a link here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sigh. I had started to include one and got distracted and forgot to. Adding it.


@Override
public void jsonData(JsonObjectBuilder builder, MetricID metricID) {
JsonObjectBuilder myBuilder = JSON.createObjectBuilder()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dim recollection here that this is quite expensive to invoke with every call; I seem to recall some other class that can be cached statically to give you a new builder.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of our metric implementations use the same pattern. The JSON field (somewhat misnamed) is declared this way:

static final JsonBuilderFactory JSON = 
    Json.createBuilderFactory(Collections.emptyMap());

IIRC the real performance drain was in the createBuilderFactory call but it probably would be good to review all uses of this pattern to see if we can speed things up.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the way to do it. We need to cache the builder factory. JsonObjectBuilder itself is mutable and cannot be used from more than one thread (as it builds a single JSON Object).

= Arrays.asList(Counted.class, Metered.class, Timed.class, Gauge.class, ConcurrentGauge.class,
SimplyTimed.class);

private static final List<Class<? extends Annotation>> JAX_RS_ANNOTATIONS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably good enough. Note that strictly speaking a JAX-RS annotation is one that is, in turn, annotated with HttpMethod. I'd probably leave this line alone anyway.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to make sure I understand.

I think you're suggesting that instead of iterating through the individual annotation classes {GET.class, etc.) to see if one is present on a given method we could look for HttpMethod.class`. Is that it?

Related, the @Observes @WithAnnotations clause currently lists the individual JAX-RS-related annotations (GET.class, etc.) in the method declaration. Could we also use HttpMethod.class there?

ljnelson
ljnelson previously approved these changes Aug 11, 2020
@tjquinno tjquinno requested a review from ljnelson August 12, 2020 20:16
@tjquinno tjquinno merged commit a554d67 into helidon-io:master Aug 12, 2020
@tjquinno tjquinno deleted the metrics-2.3 branch August 12, 2020 20:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Update Helidon for MP Metrics 2.3.2
3 participants