se.guides.metrics.adoc Maven / Gradle / Ivy
///////////////////////////////////////////////////////////////////////////////
Copyright (c) 2019, 2024 Oracle and/or its affiliates.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
///////////////////////////////////////////////////////////////////////////////
= Helidon SE Metrics Guide
:description: Helidon metrics
:keywords: helidon, metrics, guide
:intro-project-name: {h1-prefix}
:rootdir: {docdir}/../..
include::{rootdir}/includes/se.adoc[]
:metric: meter
:metrics: meters
:metric_uc: Meter
:metrics_uc: Meters
:meter: meter
:meters: meters
:meter_uc: Meter
:meters_uc: Meters
:metrics-endpoint: /observe/metrics
include::{rootdir}/includes/guides/metrics.adoc[tag=intro]
include::{rootdir}/includes/guides/metrics.adoc[tag=create-sample-project]
include::{rootdir}/includes/guides/metrics.adoc[tag=using-built-in-metrics-intro]
The generated source code is already configured for both metrics and health checks, but the following example removes health checks.
[source,xml]
.Metrics dependencies in the generated `pom.xml`:
----
io.helidon.webserver.observe
helidon-webserver-observe-metrics
io.helidon.metrics
helidon-metrics-system-meters
runtime
----
<1> Includes the Helidon observability component for metrics and, as transitive dependencies, the Helidon neutral metrics API and a full-featured implementation of the API.
<2> Includes the built-in meters.
With these dependencies in your project, Helidon's auto-discovery of webserver features automatically finds and runs the metrics subsystem.
You do not need to change any of the generated source code.
include::{rootdir}/includes/guides/metrics.adoc[tag=build-and-run-intro]
[source,text]
.Text response:
----
include::{rootdir}/includes/guides/metrics.adoc[tag=metrics-prometheus-output]
----
You can get the same data in JSON format.
[source,bash,subs="attributes+"]
.Verify the metrics endpoint with an HTTP accept header:
----
curl -H "Accept: application/json" http://localhost:8080{metrics-endpoint}
----
[source,json]
.JSON response:
----
{
"base": {
include::{rootdir}/includes/guides/metrics.adoc[tag=base-metrics-json-output]
},
include::{rootdir}/includes/guides/metrics.adoc[tag=vendor-metrics-json-output]
}
----
include::{rootdir}/includes/guides/metrics.adoc[tag=get-single-metric]
include::{rootdir}/includes/guides/metrics.adoc[tag=built-in-metrics-discussion]
////
Controlling Metrics section
For the SE guide, we stitch in the shared content about controlling metrics around SE-specific content that is not shared. It makes for a bit choppy-looking source here, but it renders just fine and lets us easily share the content that's common between SE and MP.
////
include::{rootdir}/includes/guides/metrics.adoc[tag=controlling-intro]
Your Helidon SE application can also control metrics processing programmatically as described in the following sections.
include::{rootdir}/includes/guides/metrics.adoc[tag=disabling-whole-intro]
A Helidon SE application can disable metrics processing programmatically.
[source,java]
.Disable all metrics behavior
----
include::{rootdir}/../java/io/helidon/docs/se/guides/MetricsSnippets.java[tag=snippet_1, indent=0]
----
<1> Begin preparing the `ObserveFeature`.
<2> Begin preparing the `MetricsObserver`.
<3> Disable metrics.
<4> Complete the `MetricsObserver`.
<5> Complete the `ObserveFeature`.
<6> Create and start the `WebServer` with the `ObserveFeature` (and other settings).
These builders and interfaces also have methods which accept `Config` objects representing the `metrics` node from the application configuration.
include::{rootdir}/includes/guides/metrics.adoc[tag=disabling-whole-summary]
include::{rootdir}/includes/guides/metrics.adoc[tag=KPI]
Your Helidon SE application can also control the KPI settings programmatically.
[source,java]
.Assign KPI metrics behavior from code
----
include::{rootdir}/../java/io/helidon/docs/se/guides/MetricsSnippets.java[tag=snippet_2, indent=0]
----
<1> Create a link:{metrics-javadoc-base-url}/io/helidon/metrics/api/KeyPerformanceIndicatorMetricsConfig.html[`KeyPerformanceIndicatorMetricsConfig]` instance (via its link:{metrics-javadoc-base-url}/io/helidon/metrics/api/KeyPerformanceIndicatorMetricsConfig.Builder.html[`Builder`]) with non-default values.
<2> Enabled extended KPI {metrics}.
<3> Set the long-running request threshold.
<4> Prepare the metrics observer's builder.
<5> Update the metrics observer's builder using the just-prepared KPI metrics config.
<6> Add the metrics observer to the `ObserveFeature`.
<7> Add the `ObserveFeature` to the `WebServer`.
// end of Controlling Metrics section
include::{rootdir}/includes/guides/metrics.adoc[tag=metrics-metadata]
=== Application-Specific Metrics Data
This section demonstrates how to use application-specific {metrics} and integrate them with Helidon, starting from a Helidon SE QuickStart application.
It is the application's responsibility to create and update the {metrics} at runtime. The application has
complete control over when and how each {metric} is used. For example, an application may use the
same counter for multiple methods, or one counter per method. Helidon maintains a single meter registry which holds all {metrics}.
In all of these examples, the code uses a {metric} builder specific to the type of {metric} needed to register a new {metric} or locate a previous-registered {metric}.
==== Counter {metric_uc}
The `Counter` {metric} is a monotonically increasing number. The following example demonstrates how to use a `Counter` to track the number of times the `/cards` endpoint is called.
[source,java]
.Create a new class named `GreetingCards` with the following code:
----
include::{sourcedir}/se/guides/MetricsSnippets.java[tag=snippet_3, indent=0]
----
<1> Declare a `Counter` member field.
<2> Create and register the `Counter` {metric} in the global meter registry`. This `Counter` will exist for the lifetime of
the application.
<3> Increment the count.
[source,java]
.Update the `routing` method in the main class as follows:
----
include::{sourcedir}/se/guides/MetricsSnippets.java[tag=snippet_4, indent=0]
----
<1> Add the `GreetingCards` service to the routing. Helidon routes any REST requests with
the `/cards` root path to the `GreetingCards` service.
[source,bash,subs="attributes+"]
.Build and run the application, then invoke the endpoints below:
----
curl http://localhost:8080/cards
curl -H "Accept: application/json" 'http://localhost:8080{metrics-endpoint}?scope=application'
----
[source,hocon]
.JSON response:
----
{
"cardCount": 1 // <1>
}
----
<1> The count value is one since the method was called once.
==== Timer {metric_uc}
The `Timer` {metric} aggregates durations.
In the following example,
a `Timer` {metric} measures the duration of a method's execution. Whenever the REST `/cards`
endpoint is called, the code updates the `Timer` with additional timing information.
[source,java]
.Replace the `GreetingCards` class with the following code:
----
include::{sourcedir}/se/guides/MetricsSnippets.java[tag=snippet_5, indent=0]
----
<1> Declare a `Timer` member field.
<2> Create and register the `Timer` metric in the global meter registry.
<3> Create a timer sample which, among other things, automatically records the starting time.
<4> Arrange for the timer sample to be stopped and applied to the `cardTimer` once Helidon sends the response to the client.
[source,bash,subs="attributes+"]
.Build and run the application, then invoke the endpoints below:
----
curl http://localhost:8080/cards
curl http://localhost:8080/cards
curl -H "Accept: application/json" 'http://localhost:8080{metrics-endpoint}?scope=application'
----
[source,json]
.JSON response:
----
{
"cardTimer": {
"count": 2,
"max": 0.01439681,
"mean": 0.0073397075,
"elapsedTime": 0.014679415,
"p0.5": 0.000278528,
"p0.75": 0.01466368,
"p0.95": 0.01466368,
"p0.98": 0.01466368,
"p0.99": 0.01466368,
"p0.999": 0.01466368
}
}
----
Helidon updated the timer statistics for each of the two accesses to the `/cards` endpoint.
==== Distribution Summary {metrics_uc}
The `DistributionSummary` {metric} calculates the distribution of a set of values within ranges. This {metric} does
not relate to time at all. The following example records a set of random numbers in a `DistributionSummary` {metric} when
the `/cards` endpoint is invoked.
[source,java]
.Replace the `GreetingCards` class with the following code:
----
include::{sourcedir}/se/guides/MetricsSnippets.java[tag=snippet_6, indent=0]
----
<1> Declare a `DistributionSummary` member field.
<2> Create and register the `DistributionSummary` {metric} in the global meter registry
<3> Update the distribution summary with a random number multiple times for each request.
[source,bash,subs="attributes+"]
.Build and run the application, then invoke the endpoints below:
----
curl http://localhost:8080/cards
curl -H "Accept: application/json" 'http://localhost:8080{metrics-endpoint}?scope=application'
----
[source,json]
.JSON response:
----
{
"cardDist": {
"count": 1000,
"max": 1.999805150914427,
"mean": 1.4971440362723523,
"total": 1497.1440362723522,
"p0.5": 1.4375,
"p0.75": 1.6875,
"p0.95": 1.9375,
"p0.98": 1.9375,
"p0.99": 1.9375,
"p0.999": 1.9375
}
}
----
The `DistributionSummary.Builder` allows your code to configure other aspects of the summary, such as bucket boundaries and percentiles to track.
==== Gauge Metric
The `Gauge` {metric} measures a value that is maintained by code outside the metrics subsystem. As with other {metrics}, the application explicitly registers a gauge. When the `{metrics-endpoint}` endpoint
is invoked, Helidon retrieves the value of each registered `Gauge`. The following example demonstrates
how a `Gauge` is used to get the current temperature.
[source,java]
.Replace the `GreetingCards` class with the following code:
----
include::{sourcedir}/se/guides/MetricsSnippets.java[tag=snippet_7, indent=0]
----
<1> Register the `Gauge`, passing a `Supplier` which furnishes a random temperature from 0 to 100.0 each time the metrics system interrogates the gauge.
[source,bash,subs="attributes+"]
.Build and run the application, then invoke the endpoint below:
----
curl -H "Accept: application/json" 'http://localhost:8080{metrics-endpoint}?scope=application
----
[source,hocon]
.JSON response:
----
{
"temperature": 46.582132737739066 // <1>
}
----
<1> The current (random) temperature. Accessing the endpoint again returns a different value.
include::{rootdir}/includes/guides/metrics.adoc[tag=k8s-and-prometheus-integration]
=== Summary
This guide demonstrated how to use metrics in a Helidon SE application using various combinations of
{metrics} and scopes.
* Access {metrics} for all three built-in scopes: base, vendor, and application
* Configure {metrics} that are updated by the application when an application REST endpoint is invoked
* Configure a `Gauge` {metric}
* Integrate Helidon metrics with Kubernetes and Prometheus
Refer to the following references for additional information:
* link:{javadoc-base-url}/index.html?overview-summary.html[Helidon Javadoc]
© 2015 - 2025 Weber Informatics LLC | Privacy Policy