Drill Down into Spring Boot Actuator metrics

We’ve only seen this very useful feature documented in the official Spring Actuator API Documentation, so maybe not many are aware that you actually have some control over what the Spring Actuator metrics return to your requesting client.

The Spring Actuator API allows you to expose several useful metrics that you can use to monitor your Spring-based application. You can use these metrics to monitor your application health, the last few HTTP requests processed, system load, and so on. All this is rather well documented both by Spring themselves and other bloggers. However, when consuming the API, you may notice part of the response advertising “availableTags”, for example if we query the http.server.requests metric, we get:

In lines 5-18 we see the measurements array, which contains three statistics about all the requests made to the Spring App until that point in time. In the above example, we see COUNT, TOTAL_TIME, and MAX. However, we can also query Spring Actuator to return those statistics for only a subset of the requests that the Spring App has handled. Note the availableTags array that is defined in lines 19-48 in the above code snippet. This array informs you how to issue a request to Spring Actuator and limit the returned statistics to your chosen subset. For example, using the information we got from the above response, we now craft another GET request, like so:

http://localhost:8080/actuator/metrics/http.server.requests?tag=status:404

The difference is the ?tag=status:404 suffix at the end of the url. This query will now result in statistics for only those requests handled by Spring that have resulted in an HTTP status 404. Building the suffix is easy… Note the objects that make up the availableTags array in our code snippet above. Each object has two attributes, tag and values. The tag attribute is used in the first part of the query parameter value, while any option from the values array is used in the seconds part of the query parameter value. For example, the following object in the availableTags array:

{
     "tag":"uri",
     "values":[
            "NOT_FOUND"
    ],
}

results in the following possible queries:

/actuator/metrics/http.server.requests?tag=uri:NOT_FOUND

While the following object:

{
     "tag":"status",
     "values":[
           "404",
           "200",
           "500",
    ],
}

results in the following possible queries:

/actuator/metrics/http.server.requests?tag=status:404
/actuator/metrics/http.server.requests?tag=status:200
/actuator/metrics/http.server.requests?tag=status:500

Tip: The “values” array of each object gets populated dynamically depending on the different values the Spring App has generated. For example, in our above scenario using http.server.requests, the “values” array will not include a “204” option until your server responds to at least one request with that status. Therefore, monitoring the values array is a quick and easy way of getting the cardinality of a particular metric you are interested in.

Aside: For those of you looking for how to change the response returned by the “HTTP Trace” metric, this has changed between Spring v 1.5.x and Spring v2.0.x, so it’s best to have a look at the actual API documentation available here:

https://docs.spring.io/spring-boot/docs/2.0.x/api/org/springframework/boot/actuate/trace/http/Include.html

As a cheatsheet:

spring_boot_trace_comparison.png

The above constants can be used in the management.trace.http.include property in resources/application.properties, for example:

management.trace.http.include = remote_address, request_headers, response_headers
Advertisements

Notes on Google Firebase Cloud Messaging

I’m a huge fan of Firebase, so I’m very excited that Google Cloud Messaging [GCM] has been re-branded Firebase Cloud Messaging [FCM], which can be used for cross platform messaging.

Selection_025.png

It’s actually very simple to set this up on Android and IOS, but what’s more interesting is the web client. I was really hoping things got eaier in this department. Unfortunately, right off the bat when checking out FCM web messaging nothing much has changed yet, the FCM site provides a link to the older (but excellent) codelab which details how to implement this using service workers and the HTML5 Push API. 

Selection_026.png

The problem is the Push API is a very quickly evolving standard with plenty of activity revolving around it, and the above article does an excellent job of describing the nuts and bolts of it all, but leaves out some important information that would drive more widespread Push API adoption IMHO:

 

  • Which libraries are available to simplify the process?

I’m not discouraging anyone from trying this, it’s actually pretty easy, but there are quite a number of steps involved, as we can see below, not counting encrypting and sending Push API payloads:

Selection_027.png

Surely there must be some libraries to help us out?

Let me try to address these two issues with some notes from research I’ve done so far (suggestions for avenues of research are welcome!! see my contact page to contact me).

Frontend libraries

There isn’t too much to write about here. The most promising one I’ve found that automates registering the service worker and handles a lot of the background work for the Push API is Google’s own “Propel” library. It’s very simple to implement as you can see from the readme, and only requires some minimal manual work like getting an FCM/GCM key, adding a manifest and a minimal service worker file.

While the library does handle the service worker registration and subscription side of things, it doesn’t do anything (yet) to help with actually displaying the notifications. I suspect this is going to change very soon, it just needs to be documented properly. That being said, adding notifications manually to the service worker file is trivial.

All in all, the library definitely helps in getting you on your feet quickly and with less trouble

Custom Push data payloads and associated backend libraries

Ok, so we have push notifications working, but we want to send custom Push data payloads. As we previously mentioned, the payload needs to be encrypted before it’s sent to the client, meaning not even FCM would know what data is being passed through the data payload.

There are some excellent examples of how to achieve this in Mozilla’s service worker cookbook:

https://serviceworke.rs/push-payload_server_doc.html

In those examples they use Marco’s web-push npm library for NodeJS. This works across Chrome and Firefox. There’a similar NPM library provided by Google themselves (web-push-encryption):

https://github.com/GoogleChrome/web-push-encryption

For the python lovers, we can use Mozilla’s pywebpush library:

https://github.com/mozilla-services/pywebpush

Here’s a troubleshooting tip: almost all the libraries require you to send the endpoint subscription details to your server. The aforementioned Propel library shows an example of how to do this on their README. The above mentioned backend databases then use this information (which is basically a URL describing which endpoint to send the Push to, and two public keys that are used to encrypt the data). But, with the exception of Google’s we-push-encryption library, I was being returned with an HTTP 400 error: Unauthorized Registration. 

Weird, especially when the data I passed into all libraries was the same. Looking at the code from the web-push-encryption library, it seems that google is in a transition phase and while Chrome returns an endpoint similar to this:

{“endpoint”:”https://android.googleapis.com/gcm/send/[…]”,”keys”:{“p256dh”:”BIdjZil_ehfT_MQt95qRFB3qn-55ccb1qYrc-5g0lvWK3XYvF2drD08ulRO_2ljjZVb7vA9R3OydI7QMnHR6C24=”,”auth”:”75pCFtk04rNYL8ozHMEhfQ==”}}

We actually need to change the endpoint URL to something like:

{“endpoint”:”https://gcm-http.googleapis.com/gcm/%5B…%5D

Note the difference in URLs. In the web-push-encryption library they simply replace the string, so until Chrome starts returning the new endpoint you need to do this manually.

Once this is done, you can send custom payloads via Push and read that custom data via a call to:

event.data.json()

-or-

event.data.text()

In the service worker file, under the ‘push‘ event listener.

UPDATE: regarding the above idiosyncrasy, got an update from a Chrome dev:

Selection_028.png