I recently wrote a tutorial demonstrating how to leverage the integrations between Spring Boot Actuator and Pivotal Cloud Foundry 1.11, posted here in the Pivotal content library.
Here is a quick summary of the articles content:
Adding Actuator to your Spring Boot application deployed on Pivotal Cloud Foundry gets you the following production-ready features:
Health Check column & expanded information in Instances section
git commit id indicator, navigable to your git repo
Summary git info under Settings tab (also navigable to repo)
Runtime adjustment of logging levels, exposed via Actuator endpoints
Heap Dump*
View Trace*
View Threads, dump/download for further analysis*
* New in Pivotal Cloud Foundry 1.11
TL;DR: Pivotal Cloud Foundry 1.11 provides some really nice integrations with Spring Boot Actuator-enabled applications/microservices, giving you vital tools for monitoring, introspection, and troubleshooting quickly and effectively.
As you begin to divide conglomerate functionality into discrete, decoupled microservices, you introduce a number of opportunities and challenges into your system(s). The opportunities are often well-known, including (and especially!) development velocity, fidelity/fit (functionality matches requirements), scalability, and a host of other “ilities”.
Challenges also exist of course, including the question of how to gain visibility into end-to-end interactions involving multiple microservices across process and network boundaries. Spring Cloud Sleuth provides a lightweight, configurable, and easy way to begin capturing trace information within your distributed system.
In 2012, Twitter created Zipkin during their first Hack Week, based upon the Dapper paper.
Briefly, an entire end-to-end interaction that completes a request cycle (regardless of transport/mechanism) is referred to as a “trace”, and each trace consists of multiple “spans” connecting the endpoints of each hop. From the Spring Cloud Sleuth project page:
A Span is the basic unit of work. For example, sending an RPC is a new span, as is sending a response to an RPC. Span’s are identified by a unique 64-bit ID for the span and another 64-bit ID for the trace the span is a part of. Spans also have other data, such as descriptions, key-value annotations, the ID of the span that caused them, and process ID’s (normally IP address). Spans are started and stopped, and they keep track of their timing information. Once you create a span, you must stop it at some point in the future. A set of spans forming a tree-like structure called a Trace. For example, if you are running a distributed big-data store, a trace might be formed by a put request.
Sometimes within the Spring space, you hear about Sleuth and Zipkin within the same discussion, often within the same breath…which understandably can result in a bit of confusion on the listener’s part. Without diving too far down the rabbit hole, Sleuth provides the means to instrument your Spring Boot/Spring Cloud applications; Zipkin can take that data and provide a means to monitor and evaluate it. Zipkin provides numerous integrations, but of course, you can also use other log monitoring & management tools to collect and analyze that vital data.
Minimum Viable Product
This post focuses upon Sleuth and provides a quick on-ramp to getting started capturing basic information for each span. To do that, I’ve created these two projects that allow us to quickly add trace & span (& more) information to our interactions and verify it in our logs.
Creating a provider service
Starting at the Spring Initializr, I added the following dependencies to a project and named the artifact sz-provider-service:
(click/tap to enlarge)
After generating the project and downloading, extracting, and opening it in our IDE, we see the selected dependencies in our Maven pom:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
To provide better context within our logs for our tracing data, we’ll add the following entry to our application.properties file:
spring.application.name=sz-provider-service
For this example, we’ll create a very simple RestController so we have something in our provider microservice to contact from a consumer service. Here is the entirety of the relevant code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The only thing of particular note is the @Log statement. Lombok provides this capability to reduce the usual boilerplate code required to get a logger via LogFactory.
Creating a consumer service
For the purpose of this introduction, little changes between provider and consumer project configuration & code. Here are the exceptions:
Revisiting the Spring Initializr, we change the artifact name to sz-consumer-service, keeping the same dependencies
We add the following entries to our consumer microservice’s application.properties file:
NOTE: We’re running the provider on port 8080 (Tomcat’s default port), so we change our consumer service’s port to 8081 to avoid conflict.
This is the code for our consumer:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The same note about Lombok’s @Log applies here as well, of course.
The results
Running the two applications, we can now access the consumer’s endpoint from httpie, cURL, or a browser:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Doing so results in the following log entries from our consumer service:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2017-06-27 15:21:45.029 INFO [sz-consumer-service,6cb9e5c7261f9d64,6cb9e5c7261f9d64,false] 3272 --- [nio-8081-exec-8] c.e.s.ConsumerController : Logging GET request to /greet for class com.example.szconsumerservice.ConsumerController
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2017-06-27 15:21:45.032 INFO [sz-provider-service,6cb9e5c7261f9d64,85714e4c9db87eaa,false] 3260 --- [nio-8080-exec-9] c.e.s.ProviderController : Logging GET request to /hi
Examining our log entries for both services (above), we see that Spring Cloud Sleuth has placed our spring.application.name (as designated in each service’s application.properties), the appropriate trace id, and the span id specific to this hop within the logged information.
Summary
Of course, Sleuth captures much more data and allows for extensive customization (including enabling additional elements you specify to be captured, adjusting sampling rates, & more), and Zipkin remains a topic for another day. But this post should have provided a quick springboard (!) into using Spring Cloud Sleuth for better insight into your microservices-based system of systems.
Many of us use JSON almost exclusively now, which is generally a good thing. But what happens when you need to “speak XML” with your Spring Boot REST endpoints?
XML support in Spring Boot’s REST endpoints is not enabled by default, but adding it isn’t difficult at all. Simply add the following dependency to your POM (or similar entry to your Gradle build file, if that’s the way you roll) and rebuild:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Now, to test our results. To do so, I’m using the excellent httpie, with its shortcut that allows the omission of the hostname for localhost.
JSON
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Note that no changes are required to your code, as Spring Boot assesses your classpath and adds XML support via auto-configuration. Simple and painless!
I was leading a workshop yesterday and this question arose: Is it possible to filter requests by header content using Spring’s various request mapping (@RequestMapping, @GetMapping, @PostMapping, et al) annotations?
Not only is it possible, it’s easy, and the implementation is concise & clean! Let’s take a look.
The code
Here is a simple example that filters based upon the content-type of the header:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
To test this, simply visit the Spring Initializr, create a simple Spring Boot app with a single dependency (Web), download & unzip it, and add the code above using your favorite IDE. Then build & run it (of course)!
The output
Using httpie (which is quickly becoming my favorite CLI HTTP client), we can verify our results:
Request content type of text/plain
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
If you’ve decided to try out Spring Boot Actuator – and if you haven’t you really should! – you may have run into one of two interesting hitches that are easily resolved:
You are unable to access any of the various Actuator endpoints (/beans, /env, et al)
You can access those endpoints and yet are unable to access /actuator, the primary (navigable) Actuator endpoint
Unable to access any Actuator endpoints
In the case of point #1 above, you may see this in your logs:
s.b.a.e.m.MvcEndpointSecurityInterceptor : Full authentication is required to access actuator endpoints. Consider adding Spring Security or set ‘management.security.enabled’ to false.
For testing, it’s adequate and acceptable to simply add the suggested entry to your app’s application.properties file:
management.security.enabled=false
This is far less likely to be a suitable solution for production apps, though. Enabling Spring Security properly to secure access to your application is a far more production-ready option.
Unable to access /actuator
If you can load successfully the various Spring Boot Actuator endpoints but get a 404 error on /actuator, the primary (navigable) Actuator endpoint, you are hitting a different (yet also easily resolved) snag. The hint is in how I phrased the difficulty: the primary (navigable) Actuator endpoint.
In order to access /actuator, which uses hypermedia to provide a navigable structure of links to Actuator endpoints, you must include HATEOAS (spring-boot-starter-hateoas) on your classpath. Adding this to your POM will fix that nicely: