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.
96 lines
3.7 KiB
Markdown
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)
|