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

Allow metrics-capable components to work in absence of full-featured metrics #3441

Merged
merged 47 commits into from
Oct 19, 2021
Merged

Allow metrics-capable components to work in absence of full-featured metrics #3441

merged 47 commits into from
Oct 19, 2021

Conversation

tjquinno
Copy link
Member

@tjquinno tjquinno commented Sep 28, 2021

Resolves #2180

This PR creates two new components:

  • helidon-metrics-api abstracts the behavior of registry factories, metrics registries, and metrics implementations. It includes "no-op" implementations of metrics which Helidon uses:
    • for all of metrics if:
      • helidon-metrics is not on the runtime path, or
      • overall metrics is disabled via MetricsSettings.Builder or config
    • for a particular component's use of metrics if the component is set up (via its programmatic settings or config) to disable metrics usage
  • helidon-metrics-service-api abstracts the behavior of the MetricsSupport webserver-based metrics service and contains a minimal implementation which response with 404 to the metrics endpoints.

The existing helidon-metrics component remains and contains the full-featured implementations of metrics and MetricsSupport. For backward compatibility, the its former RegistryFactory class is now an API-compatible interface which delegates to the RegistryFactory in helidon-metrics-api.

See the README.md in the helidon-metrics-api for more details how metrics-capable components can be revised in small ways to take advantage of this new feature.

As a general change, there are several places which used to use only Config to locate settings (such as the web-context or routing. Examples: helidon-service-common-rest, HelidonRestServiceSupport, and helidon-microprofile-server RoutingBuilders. For those places, this PR introduces settings POJOs and their builders which can be initialized from config as well as programmatically. A number of config-based methods are deprecated in favor of new, settings-based, alternatives.

Here is a summary of the changes by component:

New component helidon-metrics-api

  • New MetricsSettings POJO which captures all the existing configurable behavior of metrics (enabled, base metric behavior, and KPI metrics settings) with implementations and factory methods.
  • New ComponentMetricsSettings which collects metrics behavior particular to a component, with implementations and factory methods. Currently just whether metrics should be enabled for the component
  • New RegistryFactory interface and related service loading interface RegistryFactoryProvider interface and loader class.
  • New BaseMetric interface defining common behavior of full-featured and no-op metrics.
  • New AbstractRegistry implements most of MetricRegistry with abstract methods for creating metrics instances; mostly a type-generalized copy of the previous helidon-metrics Registry class.
  • New no-op implementations of the metrics classes themselves and impls of MetricRegistry and RegistryFactory which dispense the no-op metrics.
  • Internally-focused README.md describing the revised approach and how to write or revise components to be _metrics-capableinstead ofmetrics-dependent`.

New component helidon-metrics-service-api

  • New MetricsSupport interface abstracting the behavior of the metrics web-based service.
  • A minimal implementation of above which returns 404 on accesses to the /metrics endpoints.

helidon-metrics

  • Existing interfaces and classes shrink now that they implement and extend new elements in helidon-metrics-api.
  • Use MetricsSettings instead of the corresponding Config (but still support assigning those settings via Config and the builder)
  • Previous RegistryFactory static factory methods for obtaining registry factory instances now delegate to helidon-metrics-api for backward compatibility and to enable migration over time of existing metrics-capable components.

helidon-service-common-rest

(This component contains common behavior for any SE service which adds an endpoint.)

  • Add RestServiceSettings and its Builder interfaces and implementations for them. These support as a POJO the following attributes for endpoints which a REST service provides, previously only via configuration:
    • web-context
    • routing
    • CORS settings
  • Change HelidonRestServerSupport (common base for XXXSupport classes) to use the new RestServiceSettings class instead of recording those values separately itself.

helidon-microprofile-server

  • Generalize creation of RoutingBuilders (which contain the default routing and the service endpoint routing information for a service) to accept the routing name, instead of only a config key to retrieve the routing name or a Config object to extract the routing key from. Those config-based methods remain but delegate to the new one.

helidon-microprofile-metrics

  • Use the RegistryFactory from the new helidon-metrics-api module instead of the one from helidon-metrics in:

    • MetricsCdiExtension
    • RegistryProducer

    The above one-line changes plus minor changes in pom.xml and module-info.java are all that's needed so MP metrics becomes metrics-capable.

  • Enhanced tests

helidon-examples-metrics

  • Fix a latent error in the metrics/kpi example test. While I was in there, I also converted to use hamcrest.

Documentation

Metrics can now be controlled in new ways:

  • absent from the runtime path
  • present but disabled overall
  • present and enabled overall with individual components' use of metrics disabled

Doc changes/additions:

  • The metrics guides (SE and MP) now discuss these briefly.

  • A new, separate SE guide (currently omitted from the left-hand nav list, but the revised SE metrics guide links to it) describing how to create a metrics-capable component or app. I suppressed this from the nav list because that list is already plenty long and this new information most likely interests only a small subset of our readers. I'm not sure that's the best approach, because we want to encourage users to write metrics-capable apps instead of metrics-dependent ones.

  • I did a bit of refactoring of common vs. unique-to-SE content.

  • In the new helidon-metrics-api module is an informal README.md geared to people converting existing Helidon services and components to be metrics-capable.

Other modules affected

Some other components have been written to isolate their metrics dependency to a separate module (e.g., helidon-webclient and helidon-webclient-metrics), leaving it to the user to include (or not) a dependency on the component's metrics component to control whether the component registers and updates its metrics. Over time, we can remove that complexity (while making sure we maintain backward compatibility for the existing usage pattern).

Until then, any component or app that uses the normal techniques of obtaining a MetricRegistry (in SE, using RegistryFactory static methods; in MP, using RegistryFactory static methods or CDI look-up of a MetricRegistry) essentially becomes metrics-capable without any change, meaning that the metrics.enabled setting works and even in the absence of helidon-metrics at runtime the component runs correctly (just without updating metrics). This is true as long as the code does not depend on metrics' values changing at runtime; if they do, they should declare a runtime dependency on helidon-metrics.

Because these components currently depend on helidon-metrics the full-featured metrics implementation will be on the runtime path of any app which depends on these components unless the person packaging or deploying an app takes steps to exclude helidon-metrics.

Examples

The new helidon-metrics-service-api component includes a trivial test service MyMetricsServiceSupport which follows the guidelines in the new doc content for creating or converting an SE service component.

You can also see this feature at work by changing the pom.xml in the MP quickstart app. Add this to the helidon-microprofile bundle dependency (that artifact depends on both helidon-metrics and, now, helidon-metrics-api and `helidon-metrics-service-api):

            <exclusions>
                <exclusion>
                    <groupId>io.helidon.metrics</groupId>
                    <artifactId>helidon-metrics</artifactId>
                </exclusion>
            </exclusions>

Then

mvn clean package -DskipTests
java -jar target/quickstart-mp.jar

In another window, access the app curl http://localhost:8080/greet and then try to access metrics using curl -v http://localhost:8080/metrics and you see this output:

< HTTP/1.1 404 Not Found
< Content-Type: text/plain
< Date: Sun, 10 Oct 2021 19:45:39 -0500
< transfer-encoding: chunked
< connection: keep-alive
< 
* Connection #0 to host localhost left intact
Metrics is disabled

All the MP metrics code runs (unknown to it) with the no-op implementations of RegistryFactory, MetricRegistry, and metrics without incident.

Signed-off-by: tim.quinn@oracle.com tim.quinn@oracle.com

@tjquinno tjquinno self-assigned this Sep 28, 2021
@tjquinno tjquinno changed the title Allow metrics-capable components to work in absence of full-featured metrics WIP - Allow metrics-capable components to work in absence of full-featured metrics Sep 28, 2021
@tjquinno tjquinno changed the title WIP - Allow metrics-capable components to work in absence of full-featured metrics Allow metrics-capable components to work in absence of full-featured metrics Sep 28, 2021
metrics/api/README.md Outdated Show resolved Hide resolved
metrics/api/README.md Outdated Show resolved Hide resolved
@tjquinno tjquinno changed the title Allow metrics-capable components to work in absence of full-featured metrics WIP - Allow metrics-capable components to work in absence of full-featured metrics Sep 29, 2021
@tjquinno tjquinno changed the title WIP - Allow metrics-capable components to work in absence of full-featured metrics Allow metrics-capable components to work in absence of full-featured metrics Sep 29, 2021
ljnelson
ljnelson previously approved these changes Sep 29, 2021
Copy link
Member

@ljnelson ljnelson left a comment

Choose a reason for hiding this comment

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

A couple of comments.

@tjquinno tjquinno changed the title Allow metrics-capable components to work in absence of full-featured metrics WIP - Allow metrics-capable components to work in absence of full-featured metrics Sep 29, 2021
@barchetta barchetta added this to the 2.4.0 milestone Oct 4, 2021
…aring whether full-featured metrics are on the runtime path and enabled

Signed-off-by: tim.quinn@oracle.com <tim.quinn@oracle.com>
…erve a (possibly incorrect) tolerance of mismatched metadata and metric type
… creating a MetricID; associated private method changes regarding metric type checking and casting
@tjquinno tjquinno requested a review from tomas-langer October 19, 2021 09:50
…rovider and metrics support provider choices at start-up; reduce visibility of a class used only in-package
Copy link
Member

@tomas-langer tomas-langer left a comment

Choose a reason for hiding this comment

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

LGTM

@tjquinno tjquinno merged commit 959c341 into helidon-io:master Oct 19, 2021
@tjquinno tjquinno deleted the metrics-noop branch October 19, 2021 12:23
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.

Metrics support in other modules
4 participants