///////////////////////////////////////////////////////////////////////////////

    Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.

    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.

///////////////////////////////////////////////////////////////////////////////

= Metrics and Health Support
:description: Helidon Reactive WebServer metrics and health support
:keywords: helidon, reactive, reactive streams, reactive java, reactive webserver, metrics

== Metrics Support
Helidon WebServer includes support for MicroProfile Metrics. MicroProfile
Metrics has a variety of metric types and two reporting formats that
are exposed at the `/metrics` endpoint.


=== Prerequisites

Declare the following dependency in your project:

[source,xml,subs="verbatim,attributes"]
.Webserver Metrics Dependency
----
    <dependency>
        <groupId>io.helidon.microprofile.metrics</groupId>
        <artifactId>helidon-metrics-se</artifactId>
    </dependency>
----

=== Using Metrics in Your Application
To enable Metrics, register it with the WebServer.

[source,java]
.Configuring Metrics in WebServer
----
import io.helidon.metrics.MetricsSupport;
. . .

Routing.builder()
                .register(MetricsSupport.create())
                .register("/myapp", new MyService())
                .build();
----

Then you can use metrics in your service.

[source,java]
.Define and use a Metrics Counter
----
import io.helidon.metrics.RegistryFactory;
import org.eclipse.microprofile.metrics.Counter;
import org.eclipse.microprofile.metrics.MetricRegistry;
. . .

public class MyService implements Service {

    private final MetricRegistry registry = RegistryFactory.getRegistryFactory().get()
        .getRegistry(MetricRegistry.Type.APPLICATION); <1>
    private final Counter accessCtr = registry.counter("accessctr"); <2>

    @Override
    public void update(Routing.Rules rules) {
        rules
             .any(this::countAccess)
             .get("/", this::myGet);
    }

    private void countAccess(ServerRequest request, ServerResponse response) {
            accessCtr.inc(); //<3>
            request.next();
    }
}
----

<1> Get the application metrics registry
<2> Create a counter in that registry
<3> Increment the counter for every request

=== Accessing Metrics Endpoint

Access metrics data via the `/metrics` endpoint. Two reporting formats
are supported. The HTTP Accept header sent by the client determines
the reporting format:

1. JSON format - used when the HTTP Accept header matches `application/json`
2. Prometheus text format - used when the HTTP Accept header is `text/plain`
   or otherwise does not match `application/json`

[source,bash]
.Example Reporting: Prometheus format
----
curl -s -H 'Accept: text/plain' -X GET http://localhost:8080/metrics/
# TYPE base:classloader_total_loaded_class_count counter
# HELP base:classloader_total_loaded_class_count Displays the total number of classes that have been loaded since the Java virtual machine has started execution.
base:classloader_total_loaded_class_count 3157
. . .
----

[source,bash]
.Example Reporting: JSON format
----
curl -s -H 'Accept: application/json' -X GET http://localhost:8080/metrics/ | json_pp
{
   "base" : {
      "memory.maxHeap" : 3817865216,
      "memory.committedHeap" : 335544320,
. . .
----

In addition to your application metrics the reports contain other
metrics of interest such as system and VM information.

For full details see the
https://github.com/eclipse/microprofile-metrics/releases[MicroProfile Metrics]
specification.


== Implementing a Health Check

The WebServer does not include a dedicated health check feature, but you
can implement a health check by defining an appropriate endpoint. 

To create a health check that runs on a separate port from your main web application:

1. Define a second socket in the WebServer's configuration.
2. Create a health service to handle requests on the socket.
3. Add a route to the health service.

[source,yaml]
.Define a health check socket in application.yaml
----
server:
  port: 8080
  sockets:
    health:  // <1>
        port: 9090
----

<1> Name this socket "health"

[source,java]
.Create a health service
----
public class HealthCheckService implements Service {

    HealthCheckService() {
    }

    @Override
    public void update(Routing.Rules rules) {
        rules.get("/health", this::get);
    }

    public void get(ServerRequest req, ServerResponse res) {
        res.status(200).send();
    }
}
----

[source,java]
.Define a route to the HealthCheckService service on the socket
----
        // By default this picks up application.yaml from the classpath
        Config config = Config.create();

        // Get WebServer config from the "server" section of application.yaml
        ServerConfiguration serverConfig = ServerConfiguration.
            fromConfig(config.get("server"));

        WebServer server = WebServer.builder(createRouting())  //<1>
                        .configuration(serverConfig)
                        .addNamedRouting("health",  //<2>
                                Routing.builder()
                                .register(new HealthCheckService())  // <3>
                                .build())
                        .build();
----

<1> `createRouting()` creates a `Routing` object for your main application.
    See the <<getting-started/02_base-example.adoc#Quickstart Examples,Quickstart examples>>.
<2> Add routing for a named socket. This name must match the name of the socket
    used in the WebServer configuration.
<3> Register the health check service on that socket.

You can access your health check at `host:9090/health`
