Hands on Monitoring a Spring Boot Application with Honeycomb š
Application observability - knowing the behavior of your application, on a per user basis - is a critical skill for any tech company. At my current role Iāve been using New Relic to monitor our applications in production. New Relic is great, however recently Honeycomb has broken onto the scene with a new observability platform. Their CEO, Charity Majors, has been leading the conversation around application observability for a while now so I wanted to give their platform a try.
As my experience has been using New Relic to monitor Spring Boot applications, Iāll do the same here. Iāll walk through setting up a basic Spring Boot application, and instrumenting it with Honeycomb. This review should be taken with a grain of salt, as itās not a formal evaluation. I wrote this as I went, so it reflects my thoughts at the time.
You can check out the source code here
Starting an application
First thingās first - we need something to monitor! Letās use the gold standard for bootstrapping a Spring Boot application, Spring Initializr
Letās build a Java 11, Spring Boot 2.3 service. Weāll call our application honeycomb-demo, and include Spring Web, Rest Repositories, Spring Data JPA & H2 Database. These libraries will allow us to quickly build functionality to persist objects to the database via REST endpoints.
If you want to try something similar, this link has my configuration.
After downloading, unzipping, and making sure I had configured jenv to use the right java version, we can give the application a run with
mvn spring-boot:run
Then from a seperate terminal window, we can run curl localhost:8080/
and see a response from our app:
Lets add some functionality
Seeing as instrumenting an autogenerated application endpoint wouldnāt be that interesting, letās add a POST and a GET endpoint. As weāre evaluating Honeycomb, letās build a product for beekeepers! Weāll expose a POST endpoint for persisting Bees to our database, and a GET endpoint for seeing all the bees. Each Bee will have a name, and a bee catchphrase (duh!).
After a trip to my favorite Spring tutorial site Baeldung for a refresher on Spring Data Rest, letās get started.
First, weāll make a Bee domain object. Each Bee will have an autogenerated Id, a name, and itās catchprase. Since weāre not doing Kotlin, the domain object will also have some autogenerated getters and setters that Iāll spare you from seeing.
Weāll also need to define a Data Repository, which will autoconfigure our Bee CRUD endpoints for us:
Now that the repository and the domain obect are setup, after rerunning the application we can use curl
to send a POST request to persist a Bee object:
Spring Data repository is incredibly powerful. With only those two classes, itās configured CRUD endpoints for interacting with Bee objects and collections. It even sets up pagination over the collection of Bees for us.
Setting up Honeycomb
Now that we have something built, letās intrument it š
Honeycomb recently restructured their pricing tiers, and now offer a generous free tier. It includes 20 million events per month and 60 days data retention. More than plenty for our purposes! The only thing not available in the free tier is their SLO product.
Upon setting up an account, you land on their above homepage. For a free account, your stuck with a blue top bar prompting you to upgrade. However if it bothers you as much as it bothers me, you can use Stylebot to hide the element, so you donāt have to see it. Maybe itās things like this that makes it impossible for me to stay focused on one taskā¦
Well once youāre finished ruining their carefully crafted css, we can click āCreate a Datasetā, and choose Java as the language.
They bring us over to a page with instructions for integrating with Java. Particularly, they call out:
āThe Java Beeline provides automatic instrumentation for Spring Boot v2ā
Score! That makes it easy. Letās follow these instructions.
First - we need to add the Java Beeline to our pom.
Their guide specifies version 1.0.0 - but are they really only on version 1.0.0? No updates since its been published at all? Looking on Maven Central, it appears so - they havenāt updated it since it was originally published in early 2019. I guess they got it right the first time!
Next, we need to add some properties to our Spring application.properties
file. Honeycomb provides the configuration as part of their setup page, with API key and dataset names already filled in. Itās touches like that that really make you a happy non-paying customer!
I did have to modify their properties slightly - they use a :
in their properties file as a delimiter, which causes IntelliJ to complain about ābreaking code style conventionā. Switching them to =
instead did the trick, as IntelliJ has default code styles itās enforcing. According to the Java Properties documentation, either are perfectly valid deliminators.
There were also some optional config I removed to make things simpler. Hopefully I remember to delete that API key before commiting this to source control š¤
Now, after rebuilding the server and sending a test POST request from the terminal, our app is instrumented and Honeycomb is receiving data!! šš
Other than the slight visual bug where the y axis labels are squished, it looks great.
I particularly like the emphasis on the p50, p95 & p99 traffic. That already gave me my first insight - why did one of my curl
requests take 218 ms?
Clicking into the Latency chart, we can zoom in on the requests in question. There we see that it was the first request to the server that took 218 ms - which makes sense. The server had recently started, and Spring often needs a request or two to establish connections and āwarm upā.
Mocking some user traffic
Great! Now that we are instrumented, we need some actual data rather than me running curl
commands over and over again.
My performance testing tool of choice is Artillery. Itās powerful and flexible - it can be configured via command line arguments directly, or a configuration file. You can follow the setup guide here to get started using it.
I put together a configuration file to run against our local server. It will ramp up users over 60 seconds, have peak load for 60 seconds, than ramp back down. Each user will POST a Bee, and then make a GET to get a list of all the Bees.
After giving it a run with artillery run bee-test.yml
(and going to get some more tea) we can see the results in Honeycomb!
Perfect! In the Total Spans section we can clearly see the ramp up, the stable period, and the ramp down.
However, only ramping our Artillery test to 100 users? Thatās boring. Letās tweak that config to 11:
10,000 users in 1 minute? Now were cooking with gas!
After plugging my laptop in, running artillery run bee-test-insane.yml
, and crossing my fingers, here are our Honeycomb results:
Andā¦theyāre not great. It looks like our server maxed out at receiving around 250 events per second, when it should of been much higher. Artillery was likely the issue - the P90 response time of the demo application never exceeded 30 ms, it didnāt seem to have a problem processing the load. That implies Artillery was the problem, and it hit a limit on the number of requests it could generate concurrently. Alas, running a 10,000 user/minute test from a local machine doesnāt yet seem possible.
How much did that cost?
Now that weāve finished our load test, letās look at our Honeycomb usage. If thereās one thing Iāve learned from working with AWS - itās never forget to check the bill. Luckily, Honeycomb makes it quite easy to see your usage.
With some pretty hefty load tests weāve used only 0.125% of our events budget for the month. The free tier Honeycomb offers is super generous.
The End
So thatās my journey through instrumenting a Spring Boot app with Honeycomb. Since we had a lot of ground to cover weāve stuck to the surface level of Honeycomb in this post. In future posts weāll dig deeper into the Honeycomb query builder and custom instrumentation. For now - happy monitoring ššš