© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2022
D. R. HeffelfingerPayara Micro Revealedhttps://doi.org/10.1007/978-1-4842-8161-1_6

6. Metrics

David R. Heffelfinger1  
(1)
Fairfax, VA, USA
 

The MicroProfile Metrics API allows us to easily generate monitoring data (things like CPU load, disk space usage, number of HTTP requests, etc.). Payara Micro provides a metrics endpoint that can provide this data with no additional effort on our part.

There are four MicroProfile metrics endpoints:
  • /metrics/base is defined by the MicroProfile standard, meaning that all MicroProfile implementations (such as Payara Micro) must implement it. It provides information about the JVM that is running our instance of Payara Micro, things like the number of Java classes loaded into memory, JVM uptime, JVM memory information, etc.

  • /metrics/vendor allows us to retrieve vendor-specific metric information.

  • /metrics/application allows us to retrieve our application-specific metrics, which we can generate via annotations.

  • /metrics displays all metric information, including the data in /metrics/base, /metrics/vendor, and metrics/application.

Data generated by the MicroProfile Metrics API is meant to be read by monitoring tools that can automatically alert us if an application is using too much CPU, memory, disk space, or any other number of warnings. By default, the output of the MicroProfile Config endpoints is in Prometheus format.

Prometheus is a very popular open source monitoring tool. Since Prometheus is so popular, the format it uses to read metrics data has been adopted by several other monitoring tools. By generating data in Prometheus format, MicroProfile Config is automatically compatible with several monitoring tools. If we wish to receive metric data in JSON format instead, all we need to do is set the Accept HTTP header in our request to application/json.

Base Metrics

We can access base metrics by sending a GET request to the /metrics/base endpoint of our Payara Micro instance.

For example, using curl to send a request to an instance of Payara Micro running on our local workstation
curl http://localhost:8080/metrics/base
would result in output similar to the following:
# TYPE base_classloader_loadedClasses_count gauge
# HELP base_classloader_loadedClasses_count Displays the number of classes that are currently loaded in the JVM.
base_classloader_loadedClasses_count 16396
# TYPE base_classloader_loadedClasses_total_total counter
# HELP base_classloader_loadedClasses_total_total Displays the total number of classes that have been loaded since the JVM has started execution.
base_classloader_loadedClasses_total_total 16396
# TYPE base_classloader_unloadedClasses_total_total counter
# HELP base_classloader_unloadedClasses_total_total Displays the total number of classes unloaded since the JVM has started execution.
base_classloader_unloadedClasses_total_total 0
# TYPE base_cpu_availableProcessors gauge
# HELP base_cpu_availableProcessors Displays the number of processors available to the JVM. This value may change during a particular invocation of the virtual machine.
base_cpu_availableProcessors 8
# TYPE base_cpu_systemLoadAverage gauge
# HELP base_cpu_systemLoadAverage Displays the system load average for the last minute. The system load average is the sum of the number of runnable entities queued to the available processors and the number of runnable entities running on the available processors averaged over a period of time. The way in which the load average is calculated is operating system specific but is typically a damped time-dependent average. If the load average is not available, a negative value is displayed. This attribute is designed to provide a hint about the system load and may be queried frequently. The load average may be unavailable on some platform where it is expensive to implement this method.
base_cpu_systemLoadAverage 0.32
# TYPE base_gc_time_total counter
# HELP base_gc_time_total Displays the approximate accumulated collection elapsed time in milliseconds. This attribute displays -1 if the collection elapsed time is undefined for this collector. The JVM implementation may use a high resolution timer to measure the elapsed time. This attribute may display the same value even if the collection count has been incremented if the collection elapsed time is very short.
base_gc_time_total{name="G1 Young Generation"} 226
base_gc_time_total{name="G1 Old Generation"} 0
# TYPE base_gc_total_total counter
# HELP base_gc_total_total Displays the total number of collections that have occurred. This attribute lists -1 if the collection count is undefined for this collector.
base_gc_total_total{name="G1 Young Generation"} 15
base_gc_total_total{name="G1 Old Generation"} 0
# TYPE base_jvm_uptime_seconds gauge
# HELP base_jvm_uptime_seconds Displays the uptime of the JVM in milliseconds.
base_jvm_uptime_seconds 4745.731
# TYPE base_memory_committedHeap_bytes gauge
# HELP base_memory_committedHeap_bytes Displays the amount of memory in bytes that is committed for the JVM to use.
base_memory_committedHeap_bytes 8.09500672E8
# TYPE base_memory_committedNonHeap_bytes gauge
# HELP base_memory_committedNonHeap_bytes Displays the amount of memory in bytes that is committed for the JVM to use.
base_memory_committedNonHeap_bytes 1.3787136E8
# TYPE base_memory_maxHeap_bytes gauge
# HELP base_memory_maxHeap_bytes Displays the maximum amount of memory in bytes that can be used for HeapMemory.
base_memory_maxHeap_bytes 1.0479468544E10
# TYPE base_memory_maxNonHeap_bytes gauge
# HELP base_memory_maxNonHeap_bytes Displays the maximum amount of memory in bytes that can be used for NonHeapMemory.
base_memory_maxNonHeap_bytes -1
# TYPE base_memory_usedHeap_bytes gauge
# HELP base_memory_usedHeap_bytes Displays the amount of used memory in bytes.
base_memory_usedHeap_bytes 3.10751824E8
# TYPE base_memory_usedNonHeap_bytes gauge
# HELP base_memory_usedNonHeap_bytes Displays the amount of used memory in bytes.
base_memory_usedNonHeap_bytes 1.31463504E8
# TYPE base_thread_count gauge
# HELP base_thread_count Displays the current number of live threads including both daemon and non-daemon threads.
base_thread_count 75
# TYPE base_thread_daemon_count gauge
# HELP base_thread_daemon_count Displays the current number of live daemon threads.
base_thread_daemon_count 62
# TYPE base_thread_max_count gauge
# HELP base_thread_max_count Displays the peak live thread count since the Java virtual machine started or peak was reset. This includes daemon and non-daemon threads.
base_thread_max_count 100
The preceding output is in the default Prometheus format; if we wish to receive the data in JSON format, we need to set the Accept request header to application/json; for instance, using curl
curl -H "Accept: application/json"  http://localhost:8080/metrics/base
would return output in JSON format.
{
    "classloader.loadedClasses.count": 16398.0,
    "classloader.loadedClasses.total": 16398,
    "classloader.unloadedClasses.total": 0,
    "cpu.availableProcessors": 8.0,
    "cpu.systemLoadAverage": 0.29,
    "gc.time;name=G1 Young Generation": 226,
    "gc.time;name=G1 Old Generation": 0,
    "gc.total;name=G1 Young Generation": 15,
    "gc.total;name=G1 Old Generation": 0,
    "jvm.uptime": 5249144.0,
    "memory.committedHeap": 809500672,
    "memory.committedNonHeap": 138002432,
    "memory.maxHeap": 10479468544,
    "memory.maxNonHeap": -1.0,
    "memory.usedHeap": 3.904436E+8,
    "memory.usedNonHeap": 131634184,
    "thread.count": 75.0,
    "thread.daemon.count": 62.0,
    "thread.max.count": 100.0
}

Vendor Metrics

At the time of writing, Payara Micro provides a single vendor metric; we can access it by sending an HTTP request to /metrics/vendor:
curl http://localhost:8080/metrics/vendor
which would result in output similar to the following:
# TYPE vendor_system_cpu_load gauge
# HELP vendor_system_cpu_load Display the "recent cpu usage" for the whole system. This value is a double in the [0.0,1.0] interval. A value of 0.0 means that all CPUs were idle during the recent period of time observed, while a value of 1.0 means that all CPUs were actively running 100% of the time during the recent period being observed. All values betweens 0.0 and 1.0 are possible depending of the activities going on in the system. If the system recent cpu usage is not available, the method returns a negative value.
vendor_system_cpu_load 0.021788129226145758
Or if we wish to receive Payara Micro’s vendor-specific metric data in JSON format, we set the Accept HTTP header as usual:
curl -H "Accept: application/json"  http://localhost:8080/metrics/vendor
which would, unsurprisingly, result in getting the Payara Micro vendor-specific metric data in JSON format.
{
    "system.cpu.load": 0.015595463137996219
}

Payara Server allows us to expose JMX beans as custom vendor metrics; at the time of writing, this functionality is not available in Payara Micro.

Application Metrics

MicroProfile metrics provides a number of annotations we can use to annotate our methods, which can provide application metrics with very little effort on our part.

Most MicroProfile metrics annotations have a common set of attributes:
  • absolute: A boolean value indicating if the name of the metric should be absolute or if it should be appended to the fully qualified name of the class.

  • description: A description for our metric.

  • displayName: A human-readable display for the metric.

  • name: The name of the metric, if not specified, defaults to the method name we are annotating.

  • tags: Used to differentiate metrics with the same name.

  • unit: The unit of measurement for the metric.

@Counted

The @Counted annotation indicates the number of times our method has been called; the counter value is increased automatically every time our method gets called.
@GET
@Counted
@Path("counted")
@Produces(MediaType.TEXT_PLAIN)
public String countedExample() {
   return "Counter was just increased ";
}
After calling our endpoint a few times, we can see the output by sending a GET request to the /metrics/application endpoint in Payara Micro:
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_countedExample_total counter
application_com_ensode_applicationmetrics_MetricsDemo_countedExample_total{_app="application-metrics-1.0-snapshot"} 3
Or in JSON format:
{
  "com.ensode.applicationmetrics.MetricsDemo.countedExample;_app=application-metrics-1.0-snapshot": 3
}

@Gauge

This annotation can only be applied to methods returning numeric objects (Long, Short, Integer, Float, Double) or their corresponding primitive types; it exposes the return value as a metric.@GET
@Gauge(unit = "some unit")
@Path("gauge")
@Produces(MediaType.TEXT_PLAIN)
public int gaugeExample() {
  gaugeVal += 2;
  return gaugeVal;
}

The unit attribute of @Gauge is required; we can assign any arbitrary string value to it; for instance, if we were returning the number of employees in an organization, the unit could be "employees"; if we were returning the number of widgets produced in a factory, the unit could be "widgets"; and so on and so forth.

Output for @Gauge in Prometheus format looks like the following:
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_gaugeExample_some_unit gauge
application_com_ensode_applicationmetrics_MetricsDemo_gaugeExample_some_unit{_app="application-metrics-1.0-snapshot"} 8
Or in JSON format:
"com.ensode.applicationmetrics.MetricsDemo.gaugeExample;_app=application-metrics-1.0-snapshot": 10
{
  "com.ensode.applicationmetrics.MetricsDemo.gaugeExample;_app=application-metrics-1.0-snapshot": 8
}

@ConcurrentGauge

This annotation displays the number of concurrent calls to a method (typically a REST endpoint) at any particular point in time.
@GET
@ConcurrentGauge
@Path("concurrentGauge")
@Produces(MediaType.TEXT_PLAIN)
public void concurrentGaugeExample() throws InterruptedException {
  TimeUnit.SECONDS.sleep(10);
}

In our example, we are simply sleeping for ten seconds; this allows us to make a few calls to the endpoint and call the metrics endpoint so that we can get relevant example data.

Output for @ConcurrentGauge looks like the following:
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_concurrentGaugeExample_current gauge
application_com_ensode_applicationmetrics_MetricsDemo_concurrentGaugeExample_current{_app="application-metrics-1.0-snapshot"} 3
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_concurrentGaugeExample_min gauge
application_com_ensode_applicationmetrics_MetricsDemo_concurrentGaugeExample_min{_app="application-metrics-1.0-snapshot"} 0
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_concurrentGaugeExample_max gauge
application_com_ensode_applicationmetrics_MetricsDemo_concurrentGaugeExample_max{_app="application-metrics-1.0-snapshot"} 3

@ConcurrentGauge returns not only the concurrent number of invocations to the method but also the minimum and maximum number of concurrent invocations to the method in the previous minute.

JSON format output of @ConcurrentGauge looks as follows:
{
  "com.ensode.applicationmetrics.MetricsDemo.concurrentGaugeExample": {
        "current;_app=application-metrics-1.0-snapshot": 3,
        "min;_app=application-metrics-1.0-snapshot": 0,
        "max;_app=application-metrics-1.0-snapshot": 3
    }
}

@Metered

This annotation generates the number of times a method has been called, as well as the rate per second of calls during the lifetime of the application, as well as the rate per second in the last minute, last five minutes, and last fifteen minutes.
@GET
@Metered
@Path("metered")
@Produces(MediaType.TEXT_PLAIN)
public String meteredExample() {
  return "Metered method invoked ";
}
Output of @Metered looks like the following:
application_com_ensode_applicationmetrics_MetricsDemo_meteredExample_total{_app="application-metrics-1.0-snapshot"} 5
18k
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_meteredExample_rate_per_second gauge
application_com_ensode_applicationmetrics_MetricsDemo_meteredExample_rate_per_second{_app="application-metrics-1.0-snapshot"} 0.007269820214059275
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_meteredExample_one_min_rate_per_second gauge
application_com_ensode_applicationmetrics_MetricsDemo_meteredExample_one_min_rate_per_second{_app="application-metrics-1.0-snapshot"} 0.01806938732711853
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_meteredExample_five_min_rate_per_second gauge
application_com_ensode_applicationmetrics_MetricsDemo_meteredExample_five_min_rate_per_second{_app="application-metrics-1.0-snapshot"} 0.012251339396869875
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_meteredExample_fifteen_min_rate_per_second gauge
application_com_ensode_applicationmetrics_MetricsDemo_meteredExample_fifteen_min_rate_per_second{_app="application-metrics-1.0-snapshot"} 0.005013244558508323
Equivalent JSON format:
{
  "com.ensode.applicationmetrics.MetricsDemo.meteredExample": {
        "count;_app=application-metrics-1.0-snapshot": 5,
        "meanRate;_app=application-metrics-1.0-snapshot": 0.0060812930956421875,
        "oneMinRate;_app=application-metrics-1.0-snapshot": 0.0019044994125862731,
        "fiveMinRate;_app=application-metrics-1.0-snapshot": 0.007811798894517148,
        "fifteenMinRate;_app=application-metrics-1.0-snapshot": 0.004314939579277629
    }
}

@Timed

This annotation generates statistics (mean, standard deviation, etc.) about the time it takes to finish a method invocation.
@GET
@Timed
@Path("timed")
@Produces(MediaType.TEXT_PLAIN)
public void timedExample() throws InterruptedException {
 TimeUnit.SECONDS.sleep(2);
}
Output of @Timed looks like the following:
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_timedExample_rate_per_second gauge
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_rate_per_second{_app="application-metrics-1.0-snapshot"} 0.1465568677874658
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_timedExample_one_min_rate_per_second gauge
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_one_min_rate_per_second{_app="application-metrics-1.0-snapshot"} 0.2
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_timedExample_five_min_rate_per_second gauge
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_five_min_rate_per_second{_app="application-metrics-1.0-snapshot"} 0.2
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_timedExample_fifteen_min_rate_per_second gauge
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_fifteen_min_rate_per_second{_app="application-metrics-1.0-snapshot"} 0.2
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_timedExample_mean_seconds gauge
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_mean_seconds{_app="application-metrics-1.0-snapshot"} 2.000146096
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_timedExample_max_seconds gauge
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_max_seconds{_app="application-metrics-1.0-snapshot"} 2.000146096
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_timedExample_min_seconds gauge
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_min_seconds{_app="application-metrics-1.0-snapshot"} 2.000146096
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_timedExample_stddev_seconds gauge
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_stddev_seconds{_app="application-metrics-1.0-snapshot"} 0
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_timedExample_seconds summary
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_seconds_count{_app="application-metrics-1.0-snapshot"} 1
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_seconds_sum{_app="application-metrics-1.0-snapshot"} 2.000146096
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_seconds{_app="application-metrics-1.0-snapshot",quantile="0.5"} 2.000146096
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_seconds{_app="application-metrics-1.0-snapshot",quantile="0.75"} 2.000146096
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_seconds{_app="application-metrics-1.0-snapshot",quantile="0.95"} 2.000146096
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_seconds{_app="application-metrics-1.0-snapshot",quantile="0.98"} 2.000146096
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_seconds{_app="application-metrics-1.0-snapshot",quantile="0.99"} 2.000146096
application_com_ensode_applicationmetrics_MetricsDemo_timedExample_seconds{_app="application-metrics-1.0-snapshot",quantile="0.999"} 2.000146096
Output of @Timed in JSON format looks like the following:
{
  "com.ensode.applicationmetrics.MetricsDemo.timedExample": {
        "elapsedTime;_app=application-metrics-1.0-snapshot": 2000,
        "count;_app=application-metrics-1.0-snapshot": 1,
        "meanRate;_app=application-metrics-1.0-snapshot": 0.005027283318233858,
        "oneMinRate;_app=application-metrics-1.0-snapshot": 0.008428768701855296,
        "fiveMinRate;_app=application-metrics-1.0-snapshot": 0.10616389011240278,
        "fifteenMinRate;_app=application-metrics-1.0-snapshot": 0.16193681939667523,
        "min;_app=application-metrics-1.0-snapshot": 2000146096,
        "max;_app=application-metrics-1.0-snapshot": 2000146096,
        "mean;_app=application-metrics-1.0-snapshot": 2000146096,
        "stddev;_app=application-metrics-1.0-snapshot": 0.0,
        "p50;_app=application-metrics-1.0-snapshot": 2000146096,
        "p75;_app=application-metrics-1.0-snapshot": 2000146096,
        "p95;_app=application-metrics-1.0-snapshot": 2000146096,
        "p98;_app=application-metrics-1.0-snapshot": 2000146096,
        "p99;_app=application-metrics-1.0-snapshot": 2000146096,
        "p999;_app=application-metrics-1.0-snapshot": 2000146096
}

@SimplyTimed

Sometimes, we don’t need all the data that @Timed provides; @SimplyTimed provides only a few pieces of data, namely, the elapsed time across all invocations, the number of times the method has been invoked, and the maximum and minimum times the method has taken to execute.
 @GET
  @SimplyTimed
  @Path("simplytimed")
  @Produces(MediaType.TEXT_PLAIN)
  public void simplyTimedExample() throws InterruptedException {
    TimeUnit.SECONDS.sleep(3);
  }
Output of @SimplyTimed looks like the following:
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_simplyTimedExample_elapsedTime_seconds gauge
application_com_ensode_applicationmetrics_MetricsDemo_simplyTimedExample_elapsedTime_seconds{_app="application-metrics-1.0-snapshot"} 18.001398226
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_simplyTimedExample_maxTimeDuration_seconds gauge
application_com_ensode_applicationmetrics_MetricsDemo_simplyTimedExample_maxTimeDuration_seconds{_app="application-metrics-1.0-snapshot"} 3.000302743
# TYPE application_com_ensode_applicationmetrics_MetricsDemo_simplyTimedExample_minTimeDuration_seconds gauge
100 11184   0 11184   0    0  1365k     0 --:--:-- --:--:-- --:--:-- 1365k
application_com_ensode_applicationmetrics_MetricsDemo_simplyTimedExample_minTimeDuration_seconds{_app="application-metrics-1.0-snapshot"} 3.000122495
Or in JSON format:
{
  "com.ensode.applicationmetrics.MetricsDemo.simplyTimedExample": {
        "count;_app=application-metrics-1.0-snapshot": 11,
        "elapsedTime;_app=application-metrics-1.0-snapshot": 33002,
        "maxTimeDuration;_app=application-metrics-1.0-snapshot": 3000,
        "minTimeDuration;_app=application-metrics-1.0-snapshot": 3000
    }
}

Programmatic Application Metrics

Most MicroProfile metrics annotations have an equivalent implementation we can use programmatically. For example, the Counter interface is the equivalent of the @Counted annotation. Implementing metrics programmatically allows us to exert more control over the value of our annotations; with Counter, for example, we can increase or even decrease the counter based on our business requirements, as opposed to the @Counted annotation, which only increases the counter when the annotated method is invoked, and there is no way to decrease the counter via the annotation.

The following example illustrates the usage of the MicroProfile metrics Counted interface.
package com.ensode.application.metrics.programmatic;
//imports omitted
@ApplicationScoped
@Path("employeeservice")
public class EmployeeResource {
  @Inject
  @Metric
  private Counter employeeCounter;
  private List<Employee> employeeList =
    snew CopyOnWriteArrayList<>(); //thread safe
  @PUT
  @Consumes(MediaType.APPLICATION_JSON)
  public void hireEmployee(Employee employee) {
    employeeList.add(employee);
    employeeCounter.inc();
  }
  @DELETE
  @Consumes(MediaType.APPLICATION_JSON)
  public void fireEmployee(@QueryParam("firstName") String firstName, @QueryParam("lastName") String lastName) {
    Optional<Employee> employeeToFire =
      employeeList.stream().filter(emp →
        emp.getFirstName().equals(firstName) &&
        emp.getLastName().equals(lastName)).findAny();
    employeeToFire.ifPresent(
            emp -> {
              employeeList.remove(emp);
              employeeCounter.inc(-1);
            });
  }
}

In the preceding example, we inject an implementation of the Counter interface via the CDI @Inject annotation and the MicroProfile @Metric annotation. @Metric identifies the counter instance as a metric and lets the MicroProfile Metrics API know it needs to use it to generate application-specific metrics.

Once we have injected a Counter implementation, we can increase or decrease the counter as our business requirements dictate. In our example, the counter is keeping track of the number of employees in a List; it increases every time an employee is hired and decreases every time an employee is fired.

Table 6-1 lists metrics we can use programmatically, along with their annotation equivalents.
Table 6-1

Programmatic Metrics

Metric Interface

Annotation

Counter

@Counted

ConcurrentGauge

@ConcurrentGauge

SimpleTimer

@SimpleTimer

Timer

@Timer

We already saw an example of the Counter interface; ConcurrentGauge works similarly, but it provides a dec() method we can use to decrement the counter. Timer and SimpleTimer both provide overloaded methods of a time() method; taking an instance of a Callable or Runnable interface implementation (typically implemented as a lambda expression), we can use to time-specific events in our application. For example, if we wanted to find out how long it takes to add an employee to the Employee list, we could do it as follows:
package com.ensode.application.metrics.programmatic;
//imports omitted
@ApplicationScoped
@Path("employeeservice")
public class EmployeeResource {
  @Inject
  @Metric
  private SimpleTimer employeeAddSimpleTimer;
  private List<Employee> employeeList = new CopyOnWriteArrayList<>(); //thread safe
  @PUT
  @Consumes(MediaType.APPLICATION_JSON)
  public void hireEmployee(Employee employee) {
    employeeAddSimpleTimer.time(() -> {
      employeeList.add(employee);
    });
  }
}

In this example, we inject an instance of SimpleTimer via the @Inject and @Metric annotations as usual, when we wrap the call to add an employee to the list in a lambda expression and pass the resulting Runnable implementation to the time() method in our SimpleTimer.

There is one more metric provided by the MicroProfile API called a Histogram, which calculates the distribution of a value. To use Histogram, we inject it as usual and then invoke its update() method to add values to the histogram, as illustrated in the following example.
package com.ensode.application.metrics.programmatic;
//imports omitted
@ApplicationScoped
@Path("employeeservice")
public class EmployeeResource {
  @Inject
  @Metric
  private Histogram histogram;
  private List<Employee> employeeList = new CopyOnWriteArrayList<>(); //thread safe
  @PUT
  @Consumes(MediaType.APPLICATION_JSON)
  public void hireEmployee(Employee employee) {
    employeeList.add(employee);
    histogram.update(employeeList.size());
  }
}

Configuring MicroProfile Metrics in Payara Micro

We can configure metrics in Payara Micro via the set-metrics-configuration asadmin command via a command file passed as a post boot command file or similar.

Disabling Metrics

Payara Micro enables metrics by default; if we wish to disable them, we can use the following asadmin command:
set-metrics-configuration --enabled=false

Securing Metrics

By default, the /metrics endpoint is unsecured, meaning any random unauthenticated user can access it.

If we wish to secure it, we can do so by issuing the following asadmin command:
set-metrics-configuation --securityenabled=true
When securing the /metrics endpoint, we can specify which roles have access to it as follows:
set-metrics-configuration --roles=role1,role2,role3

The value of the --roles argument is a comma-separated list of roles allowed to access the generated metrics.

Customizing the Metrics Endpoint

By default, metrics can be retrieved via the /metrics endpoint. We can use a different endpoint if we wish.
set-metrics-configuration --endpoint=foo

The value of the --endpoint argument is the context root of our custom metrics endpoint.

Static Metrics

By default, metrics are updated dynamically as our application runs; if, instead, we wish to have static metrics that won’t update until our application restarts, we can do so as follows:
set-metrics-configuration --dynamic=false

Summary

In this chapter, we covered Payara Micro support for the MicroProfile Metrics API. We generate metrics to be consumed by monitoring tools. We covered how to use annotations provided by MicroProfile metrics to generate metrics with almost no effort on our part; we also saw how we can generate metrics programmatically for cases when we need more control on how to generate those metrics.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.3.255