Learn how to provide system and application metrics from a microservice using MicroProfile Metrics.
You will learn how to use MicroProfile Metrics to provide metrics from a RESTful application. Having metrics in an application serves to pinpoint issues and provides long term trend data for capacity planning and pro-active discovery of issues such as disk usage growing without bounds. They can also help those scheduling systems to decide when to scale the application to run on more or fewer machines.
MicroProfile Metrics provides an endpoint where you can get the metrics results as a plain text format. This endpoint has three scopes: base, application and vendor. For the purpose of this guide, the focus is on the application scope. The metadata of the metrics in any scope has fields such as unit, type, description, etc. The type can be a counter, gauge, meter, histogram and timer. You will use the counter, gauge and timer types in your application.
You will apply the 'metrics type annotations' to the inventory application in order to provide metrics at the application scope.
After starting the provided application, you will be able to access this microservice:
-
http://localhost:9080/inventory/systems
which retrieves the information for a list of all previously registered hosts.
The fastest way to work through this guide is to clone the Git repository and use the starting project
that is provided in the start
directory. To do this, run the following commands:
git clone https://github.com/openliberty/guide-metrics-intro.git cd guide-metrics-intro/start
The finish
directory in the root of this guide contains the finished metrics implementation
for the application. Feel free to give it a try before you proceed with building your own.
To try out the application, first navigate to the finish
directory and then run the following.
Maven aims to build the application and run it inside Open Liberty:
mvn install liberty:start-server
Point your browser to /inventory/systems
endpoint. As you can see, there are no
hosts registered currently since you have just started the application.
Go to the MicroProfile Metrics endpoint:
-
http://localhost:9080/metrics
This shows the standard metrics, and also includes the application metrics, in Prometheus format.
The application metrics can also be accessed at /metrics/application
endpoint. This endpoint does
not expose metrics if you do not point your browser first to /inventory/systems/
endpoint.
This is because these metrics are application related.
Once you are done checking out the application, stop the Open Liberty server:
mvn liberty:stop-server
Now, navigate back to the start
directory to begin.
Begin by enabling the MicroProfile Metrics in your pom.xml file. This feature allows you to use the MicroProfile Metrics API to provide the metrics from your RESTful services.
Navigate to the start/pom.xml file and add the required dependency:
link:finish/pom.xml[role=include]
The mpMetrics-1.0
feature provides http://localhost:9080/metrics
endpoint.
This feature also requires you to secure the /metrics
endpoint.
To do this, open server.xml
in start/src/main/liberty/config/server.xml
:
link:finish/src/main/liberty/config/server.xml[role=include]
The keyStore
and quickStartSecurity
configurations elements allow you to add a
basic security setup for the purpose of this guide. Use these credentials to be able
to view the metrics endpoint when you browse it.
You also need to set the system property javax.net.ssl.trustStore
in the pom.xml
to point to
the SSL certificate:
<javax.net.ssl.trustStore>${project.build.directory}/liberty/wlp/usr/servers/defaultServer/resources/security/key.jks</javax.net.ssl.trustStore>
Proceed with the section below to add metrics to InventoryManager.
Open InventoryManager.java
class in /start/src/main/java/io/openliberty/guides/inventory/
link:finish/src/main/java/io/openliberty/guides/inventory/InventoryManager.java[role=include]
As you can see, there are two metrics annotations:
-
@Timed
annotation on theget()
method tracks how frequently the method is invoked and also how long it took for the invocation to complete. Most of the annotations are followed by fields that correspond to metadata fields and some of them are provided by default and others are just optional. Timer is a complex metric type comprised of multiple key/values. Thename
field sets the name of the metric. If not explicitly given, the name of the annotated method is used. For the@Timed
annotation the default value ofunit
isseconds
. Thedescription
field is optional and it provides a brief description of the purpose of the metric annotation. -
@Counted
annotation on thelist()
method counts how many times the list of systems method is requested. In other words, how many times we display the current contents of the inventory by going to/inventory/systems
endpoint. Theabsolute
field is used to make the name of this annotation take the name of the method. Like the previous annotation, this annotation has adescription
field too. Themonotonic
field has a default valuefalse
which means that the counter is incremented before the annotated method returns, counting current invocations of the annotated method. This is not what we want in this case, thus set the value totrue
.
Open InventoryList.java
class in /start/src/main/java/io/openliberty/guides/inventory/model
link:finish/src/main/java/io/openliberty/guides/inventory/model/InventoryList.java[role=include]
The @Gauge
annotation on the getTotal()
method tracks the number of systems stored
in the inventory (or tracks the inventory size). A system is stored in the inventory when you visit
/inventory/systems/localhost
endpoint. A value should be provided for the unit
field because
there is no default value for this annotation. The name
and description
are optional like in
the previous two annotations.
These three annotations are registered by default to the singleton object MetricRegistry
.
They send their metadata or metrics to the endpoint /metrics/application
through this object.
This application is provided for you in this guide. If you want to learn how to create a RESTful application, see Creating a RESTful web service.
To build the application, run the Maven install goal from the command line:
mvn install
This goal builds the application and creates a .war file in the target directory and also configures and installs Open Liberty into the target/liberty/wlp directory.
Next, run the Maven liberty:start-server goal:
mvn liberty:start-server
This goal starts an Open Liberty server instance. Your Maven pom.xml is already configured to start the application in this server instance.
Once the server is running, you can find the metrics endpoint showing useful JVM/server base details at the following URL:
-
http://localhost:9080/metrics
After you point your browser to /inventory/systems
endpoint, you can find specific
metrics about your application at the following URL:
-
http://localhost:9080/metrics/application
If you make changes to the code, use the Maven package command to rebuild the application and have the running Open Liberty server pick them up automatically:
mvn package
To stop the Open Liberty server, run the Maven liberty:stop-server goal:
mvn liberty:stop-server
While you can test your application manually, you should rely on automated tests since they will trigger a failure whenever a code change introduces a defect. JUnit and the JAX-RS Client API provide a simple environment for you to write tests.
Begin by creating a test class start/src/test/java/it/io/openliberty/guides/metrics/MetricsTest.java
:
link:finish/src/test/java/it/io/openliberty/guides/metrics/MetricsTest.java[role=include]
The @BeforeClass
annotation is placed on a method that executes before any of the test cases. In
this case, the oneTimeSetup method retrieves the port number for the Open Liberty server and builds
a base URL string that is used throughout the tests.
The @Before
and @After
annotations are placed on methods that execute before and after every
test case. These methods are generally used to perform any setup and teardown tasks.
In this case, the setup()
method creates a JAX-RS client which makes HTTP requests to the
inventory service. This client must also be registered with a JSON-P provider (JsrJsonpProvider)
to process JSON resources. The teardown()
simply destroys this client instance.
Let’s break down the test cases:
-
testListCount()
sends a request to/inventory/systems
endpoint then verifies the200
response code is returned usingconnectToEndpoint()
private method. Next, it makes a connection to/metrics/application
endpoint to get the content of the metrics as a plain text. After that, it asserts iflist()
method inInventoryManager
class was invoked once usingvalidateAMetric()
method. This test case tests@Counted
annotation. -
testHostsNumber()
sends a request to/inventory/systems/localhost
endpoint usingconnectToEndpoint()
method. because of this request, the inventory grows in size resulting ingetHostCount()
method inInventoryManager
class to return one host which represent the localhost. It then asserts that usingvalidateAMetric()
method. This test case tests@Gauge
annotation. -
testGetPropertiesTime()
tests the time needed to get the system properties of the localhost from the previous GET request. It asserts if the time is less than one second usingvalidateAMetric()
method.
To force these test cases to execute in a particular order, put them in a testSuite()
method and
label it with a @Test
annotation so that it automatically executes when your test class run.
Go to start
directory and run mvn clean install
. You should see two tests pass with the
following results:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.metrics.MetricsTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.778 sec - in it.io.openliberty.guides.metrics.MetricsTest
Running it.io.openliberty.guides.inventory.EndpointTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.128 sec - in it.io.openliberty.guides.inventory.EndpointTest
Results :
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
You have learned how to provide system and application metrics from microservices. Then you wrote tests to validate that.
You can continue to try one of the related guides, which demonstrate new technologies that you can learn and expand on top what you built in this guide.