Files
spring-boot-demo/docs/08-diagnostics.md
Ankur Mhatre 4b6cefa60a Spring Boot 4 Actuator in production: endpoints, security, custom health indicators
Companion repository for the ankurm.com article. Every transcript in docs/output/
was produced by running this project; scripts/run-all.sh regenerates all of them.

Verified against Spring Boot 4.1.1 / Framework 7.0.9 / Security 7.1.1 /
Micrometer 1.17.1 / kafka-clients 4.2.1 on Temurin JDK 25.0.4.1+1.
2026-09-04 10:40:04 +05:30

96 lines
3.7 KiB
Markdown

[← 07 Groups and probes](07-groups-and-probes.md) · **08 · The diagnostics endpoint** · [09 Testing Actuator →](09-testing-actuator.md)
# 08 — The diagnostics endpoint
[`DiagnosticsEndpoint`](../src/main/java/com/ankurm/actuator/web/DiagnosticsEndpoint.java) is a
custom `@Endpoint(id = "diag")` that prints the Actuator state no configuration file will tell
you: which endpoints were actually discovered and mapped onto HTTP, what paths and methods each
publishes, and which health contributors are registered.
**Delete it before you ship.** The list of exposed endpoints is itself reconnaissance.
## Why it exists
Reading `application.yaml` and predicting exposure is how people ship `/actuator/heapdump` to
the internet. `management.endpoints.web.exposure.include: "*"` looks like it exposes everything;
it does not expose `heapdump` or `shutdown` ([chapter 03](03-endpoint-catalogue.md)). Conditional
endpoints like `httpexchanges` and `startup` are absent unless a specific bean exists. Ask the
running application instead of predicting.
## Writing a custom endpoint
```java
@Component
@Endpoint(id = "diag")
public class DiagnosticsEndpoint {
@ReadOperation
public Map<String, Object> diagnostics() { ... }
}
```
`@ReadOperation` maps to GET, `@WriteOperation` to POST, `@DeleteOperation` to DELETE. The id
must be lowercase alphanumeric; it becomes the path segment and the JMX name. You still have to
expose it — `include: health,info,diag` or `"*"`.
The interesting part is the three beans it injects:
| Bean | Gives you |
|---|---|
| `WebEndpointsSupplier` | every `ExposableWebEndpoint`, with its `WebOperation` predicates |
| `HealthContributorRegistry` | the live contributor tree, composites included |
| `Environment` | the effective values of the `management.*` keys |
`HealthContributorRegistry` is in `org.springframework.boot.health.registry` — new in Boot 4
([chapter 02](02-boot-4-changes.md)). It iterates as `HealthContributors.Entry`, and nested
`HealthContributors` are composites, which is why the collection is recursive.
## The output
From [`output/02-endpoint-catalogue.txt`](output/02-endpoint-catalogue.txt):
```json
{
"activeProfiles": ["exposeall", "open"],
"serverPort": "8080",
"managementPort": "(same as server.port)",
"managementBasePath": "/actuator",
"exposureInclude": "*",
"healthShowDetails": "always",
"exposedWebEndpointCount": 14,
"exposedWebEndpoints": {
"loggers": ["GET loggers", "GET loggers/{name}", "POST loggers/{name}"],
"threaddump": ["GET threaddump", "GET threaddump"],
...
},
"healthContributors": [
"db (DataSourceHealthIndicator)",
"diskSpace (DiskSpaceHealthIndicator)",
"externalApi (ExternalApiHealthIndicator)",
"kafka (KafkaHealthIndicator)",
"livenessState (LivenessStateHealthIndicator)",
"ordersDatabase (OrdersDatabaseHealthIndicator)",
"ping (PingHealthIndicator)",
"readinessState (ReadinessStateHealthIndicator)",
"ssl (SslHealthIndicator)"
]
}
```
Two things worth pausing on.
`"loggers"` shows the `POST` operation explicitly. That is the write endpoint from
[chapter 03](03-endpoint-catalogue.md), visible in a list rather than remembered.
`"threaddump"` appears **twice** with the same path. It publishes two operations that differ
only in what they produce — `application/json` and `text/plain`. Content negotiation, not a bug.
Run the same endpoint under the `mgmtport` profile and `managementPort` reads `9001`,
`managementBasePath` reads `/manage`, and the endpoint count is unchanged — the endpoints moved,
they did not disappear. That is the fact that breaks path-string security rules
([chapter 04](04-securing-actuator.md)).
---
[← 07](07-groups-and-probes.md) · **08** · [09 Testing Actuator →](09-testing-actuator.md)