Contents
Overview
This document explains Helidon SE metrics-capable components and applications and describes how to create and control them.
Think of Helidon metrics in several related but different parts:
APIs
The Helidon metrics API
This API allows your code to register, look-up, remove, and update metrics using the
RegistryFactory,MetricRegistry, and individual metrics interfaces.The Helidon metrics REST service API
This API allows your code to set up and respond to the
/metricsendpoint so clients can retreive metrics information.
Implementations of the APIs
Implementations of the Helidon metrics API.
Helidon provides two—minimal and full-featured—and selects which one to use at runtime, based on what components are present on the runtime path and whether metrics is configured to be enabled or disabled.
You control which implementation your Helidon SE service uses by which dependency you add to your project.
Implementations of the Helidon metrics REST service API.
Helidon provides two—minimal and full-featured—and selects which one to use at runtime.
Your Helidon SE app provides this feature (if at all) by explicitly using the
MetricsSupportinterface.Most Helidon SE applications are web-based and their developers choose to expose the built-in metrics web service. But by separating the parts of metrics this way, Helidon allows non-web apps to work with metrics as well, just without the web service support.
As you plan and write Helidon components and applications, you make some choices about exactly how your code will use metrics. This document gives some background information, describes each option and its effect, and provides some code examples.
Usage
This section helps you decide how incorporate metrics into your software by describing the categories of metrics usage, explaining generally how Helidon implements metrics, and illustrating how to write the metrics-related code accordingly.
Categorizing Metrics Usage
We can place each Helidon component and Helidon application into one of three categories based on how it relies on metrics. The type of module dictates the compile-time dependency you declare in the project pom.xml.
| Registers, updates, removes metrics? | Refers to metrics values? | Category |
|---|---|---|
| times | times | metrics-independent |
| check | times | metrics-capable |
| check | check | metrics-dependent |
Whenever possible, if your component or application uses metrics, then write it as metrics-capable code.
Understanding the Two Metrics Implementations
Helidon provides two metrics implementations:
Full-featured metrics allows registering, removing, and updating metrics and observing metrics' changing values. The
helidon-metricscomponent contains full-featured metrics.Minimal metrics supports registering, removing, and updating metrics. The metrics objects provided by the minimal implementation are no-ops: their values never change. The minimal implementation is part of the
helidon-metrics-apicomponent.
Any code compiled with helidon-metrics-api can assume that the runtime path will include the minimal implementation.
Both implementations support all the operations of the RegistryFactory and the MetricRegistry. The full implementation provides fully-functional metrics instances (counters, timers, etc.). In the minimal implementations, metrics do not update their values.
For Helidon to use the full implementation, two conditions must hold:
The
helidon-metricscomponent must be on the runtime path.Metrics must be enabled, using either a builder or configuration. (Enabled is the default.)
Otherwise, provided that the runtime path includes helidon-metrics-api, Helidon activates the minimal implementation.
Understanding the Two Metrics Service Implementations
Helidon includes two implementations of support for the metrics web service endpoint /metrics (or whatever context value is configured).
The full-service implementation sends responses which describe the metadata and current values for the metrics registered in metric registries. The helidon-metrics component contains this implementation.
The helidon-metrics-service-api component contains the API for the metrics web service support (the MetricsSupport interface) and also a minimal implementation. This implementation simply responds with 404 and an explanatory message that metrics are disabled.
Any code compiled with helidon-metrics-service-api can assume that the runtime path will contain the minimal implementation.
Helidon activates the full implementation if the runtime path includes the full implementation and metrics is configured as enabled; Helidon uses the minimal implementation otherwise.
Enabling and Disabling Metrics
Using either builder-style settings or configuration, your component or Helidon SE application can let end users control at runtime whether Helidon should use full-featured metrics. If an end user sets metrics.enabled to false, then Helidon activates the minimal metrics and metrics service implementations provided they are in the runtime path.
Further, users can set component-name.metrics.enabled to false which disables metrics for just that component so long as the component was written to check that setting and act on it accordingly.
Designing and Writing Metrics-Capable Applications and Components
Whoever packages and deploys your application or component can control what code will be on the runtime path and whether metrics is enabled or not. As a result, wherever possible, construct your modules which use metrics so that they do not make decisions based on the values of metrics; that is, design them to be metrics-capable, not metrics-dependent. Doing so allows your code to operate regardless of whether the full-featured metrics implementation is active at runtime.
Declaring Dependencies
- Include this dependency:Dependency for Helidon metrics API
<dependency> <groupId>io.helidon.metrics</groupId> <artifactId>helidon-metrics-api</artifactId> </dependency>content_copyThis module defines the metrics API:
RegistryFactory,MetricRegistry, and the various metrics themselves. - To permit the use of the built-in metrics web service support for the
/metricsendpoint, add this dependency:Dependency for metrics web service support<dependency> <groupId>io.helidon.metrics</groupId> <artifactId>helidon-metrics-service-api</artifactId> </dependency>content_copyThis module defines the metrics web service API:
MetricsSupport.Use the
MetricsSupportinterface fromhelidon-metrics-service-apiin your SE app initialization code to create a service you can register with the web server. (See the example below.) - Declare an explicit runtime dependency on the full-featured metrics implementation:Dependency for full metrics and metrics service implementations
<dependency> <groupId>io.helidon.metrics</groupId> <artifactId>helidon-metrics</artifactId> <scope>runtime</scope> </dependency>content_copy
Writing Metrics-Capable Code
The way you write a metrics-capable module depends on whether it is a component (that is, not an application) or an application.
Writing and Packaging a Metrics-capable Helidon SE Application
Write your SE application similarly, but do not use the ComponentMetricsSettings. Instead, build a MetricsSettings object from the configuration.
import io.helidon.config.Config;
import io.helidon.metrics.api.MetricsSettings;
import io.helidon.metrics.api.RegistryFactory;
import io.helidon.webserver.WebServer;
import org.eclipse.microprofile.metrics.MetricRegistry;
public class MyApp {
private static MetricsSettings metricsSettings;
static MetricRegistry metricRegistry;
public static void main(final String[] args) {
startServer();
}
static Single<WebServer> startServer() {
Config config = Config.create();
metricsSettings = MetricsSettings.builder()
.config(config)
.build();
metricRegistry = RegistryFactory.getInstance(metricsSettings)
.getRegistry(MetricRegistry.Type.APPLICATION);
WebServer server = WebServer.builder(createRouting(config))
.config(config.get("server"))
.addMediaSupport(JsonpSupport.create())
.build();
return server.start();
}
private static Routing createRouting(Config config) {
RestServiceSettings restServiceSettings = RestServiceSettings.create(config);
MetricsSupport metricsSupport = MetricsSupport.create(metricsSettings, restServiceSettings);
GreetService greetService = new GreetService(config);
return Routing.builder()
.register(metricsSupport)
.register("/greet", greetService)
.build();
}
}- Create and save
MetricsSettingsfrom config. - Use
MetricsSettingsto get a suitableRegistryFactory, and use that to get the application registry. - Pass
configtocreateRoutingwhich returns theRoutingto initialize the web server. - Use the
configto createRestServiceSettingswhich controls the routing name, web context, and CORS set-up for the metrics endpoint. - Create the
MetricsSupportinstance using the metrics and REST service settings. - Add the properly initialized
MetricsSupportinstance as a service to the routing, along with the app’s own service.
Helidon uses the enabled value from MetricsSettings in providing the correct implementations of both the RegistryFactory and the MetricsSupport.
Examples
The following example shows how useful metrics-capable code can be in the context of building Docker images.
You (or others) could assemble a Docker image with your metrics-capable app as its top layer or your metrics-capable component in a middle layer, built on a lower layer containing several Helidon modules including the full metrics implementation. When that Docker image runs, your app will run with full-featured metrics support.
Separately, someone could build a similar Docker image which does not include the Helidon metrics implementation. In this Docker image, your app or component will run successfully but will not incur the overhead of actually updating the metrics it uses.
Users can create different Docker images, some with full metrics support and some without, which all use a single version of your metrics-capable app or component which runs properly in either environment without change.
Additional Information
Advantages of Writing Metrics-Capable Modules
By writing a metrics-capable app or component, you give packagers and deployers of your code the flexibility to include or exclude the full metrics implementation at runtime as they see fit.
Because your one module works correctly in either environment:
The consumers of your app benefit by not needing to understand and choose between two different implementations of your module, or having to add both your main module and an optional add-on which adds metrics support to your module.
You benefit by writing and maintaining a single module, not two: one that is metrics-independent and one that is metrics-dependent.