Week 13

Observability introduction

Logging in Spring Boot

Structured Logging

Shipping Logs to the Cloud

Debugging with Logs

Health & Metrics

Appendix: Alerting (optional)

Practice

Assignment

Backend Track

Do you really know your app is healthy?

In Week 11 you met the idea of a health check: your hosting platform can ping an endpoint on a schedule, and only send traffic to your app while that endpoint answers. But answering is not the same as being healthy.

Ask yourself: if your database goes down, what should a health check say? Your app is still running, but every real request fails. A check that only proves "the process is alive" is a smoke detector without a battery — it never goes off, no matter what is burning. What you really want is a check that tests whether the app can do its job: reach its database, its dependencies, everything a real request needs.

That is exactly what Spring Boot Actuator gives you, for free.

Actuator: production endpoints for free

Actuator is Spring Boot's standard module for exactly the signals this week is about. One dependency:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Restart, then open http://localhost:8080/actuator/health:

{"status":"UP"}

It returns the same kind of UP your health check wants — but this one is telling the truth. Actuator discovers what your app depends on and checks it: because you have a datasource, the health status includes a real database check. To see the parts behind the verdict locally, add:

management:
  endpoint:
    health:
      show-details: always

Now the response breaks down into components — db, diskSpace, ping — each with its own status. (In production you would use show-details: when-authorized instead, since the breakdown reveals your dependencies.)

<aside> ⌨️

Hands on: Run your app with Docker Compose, open /actuator/health, then stop the database container (docker compose stop db). Refresh: {"status":"DOWN"}, with the db component reporting the failure. Start the database again and watch it recover. Your health check finally has a battery.

</aside>

Now finish the upgrade in production:

  1. In your hosting platform's settings, change the health check path to /actuator/health.
  2. If you built the optional HealthController back in Week 11, delete it now — Actuator replaces it.
  3. Ship it through the pipeline.

Your platform now asks your app "are you really OK?" on every check — and during deploys it will only switch traffic to a container whose database connection actually works.

Metrics: the numbers your app keeps

Actuator brought a second gift. Logs record events; metrics record measurements over time — how many requests, how fast, how much memory. Expose the metrics endpoint alongside health:

management:
  endpoints:
    web:
      exposure:
        include: health,metrics

Open http://localhost:8080/actuator/metrics — a catalogue of everything being measured. Two are worth a look right now:

<aside> ⚠️

Exposure discipline. By default Actuator exposes only health — which is safe. Here we add metrics too. But never use include: * in production: it opens endpoints like env and heapdump that leak configuration and full memory contents (an attacker's heap dump is essentially a data breach). In a real job, Actuator sits behind authentication or on a separate management port the public cannot reach. For our training apps, health,metrics is fine.

</aside>

Your first dashboard

Reading numbers from JSON is not how anyone monitors a system — dashboards are. And you already ship everything needed for a genuinely useful first panel: your logs carry a level label, so Grafana can count log lines by level over time — a live overview of how much INFO, WARN and ERROR your app produces. Those counts are metrics, derived from your logs.

  1. In Grafana: Dashboards → New → New dashboard → Add visualization, choose the Loki data source.
  2. In the query builder, filter app = my-app (your app name).
  3. Add an aggregation: Operations → Aggregations → Count, then set it to count by level. This gives you one line per log level instead of a single total.
  4. Set the panel title to something like Log volume by level, and save the dashboard as My service.

You now see INFO, WARN and ERROR as separate lines over time — a healthy app is mostly INFO with ERROR flat at zero. Trigger one error in your app and watch the ERROR line twitch.

image.png

<aside> 🎉

Step back and look at what you built this week: an app that reports on itself, logs that survive anything, a health check that tells the truth, and a dashboard watching for trouble. That is a production service — and a screenshot worth having in your portfolio.

</aside>

<aside> 💡

Curious what "more" looks like? The optional Appendix: Alerting chapter turns this exact panel into an email that finds you when errors appear — no staring at dashboards required.

</aside>

The third signal: traces

One signal from the first chapter remains: traces. Here is why they exist — and why we only talk about them.

Your whole application is one service: a request enters your controller and every answer is found inside the same container. When something is slow, your logs and metrics point at the culprit, because there is only one suspect.

Now picture the systems you will meet at work: placing one order touches an order service, a payment service, a stock service, an email service — separate applications on separate machines, each with its own logs. The order service logs "payment took 4 seconds"… and the payment service logs a normal day. Who do you believe? Which of the four systems' logs do you even open first?

A trace answers that by following one request across every service it touches, recording how long each hop took — one timeline instead of four log files. The open standard that makes services emit these signals in a common format is called OpenTelemetry; you will see the name in job descriptions, and now you can say what problem it solves. Next week, when you study how systems are split into services, you will recognise exactly the moment traces become necessary.

Extra resources


The HackYourFuture curriculum is licensed under CC BY-NC-SA 4.0 *https://hackyourfuture.net/*

CC BY-NC-SA 4.0 Icons

Built with ❤️ by the HackYourFuture community · Thank you, contributors

Found a mistake or have a suggestion? Let us know in the feedback form.