Polish Actuator hypermedia support

This commit is contained in:
Phillip Webb
2015-07-05 20:06:44 -07:00
parent 67dd164dc3
commit e8085016ba
67 changed files with 1140 additions and 905 deletions

View File

@@ -1,20 +1,17 @@
=== /autoconfig
This endpoint is a report on the Spring Boot auto-configuration process that happened when
your application started up. It lists all the `@Conditional` annotations that were
evaluated as the context started and in each case it gives an indication of if (and why)
the condition matched. A positive match results in a bean being included in the context,
and a negative result means the opposite (the beans's class may not even be loaded).
This endpoint is a report on the Spring Boot Autoconfiguration process
that happened when your application started up. It lists all the
`@Conditional` annotations that were evaluated as the context started
and in each case it gives an indication of if (and why) the condition
matched. A positive match results in a bean being included in the context,
and a negative result means the opposite (the beans's class may not even
be loaded).
The report is split into 2 parts, positive matches first, and then negative. If the
context is a hierarchy, there is also a separate report on the parent context with the
same format (and recursively up to the top of the hierarchy).
The report is split into 2 parts, positive matches first, and then negative.
If the context is a hierarchy, there is also a separate report on the parent
context with the same format (and recursively up to the top of the hierarchy).
NOTE: the report is actually about `@Conditional` evaluation not autoconfiguration
per se, but most autoconfiguration features use `@Conditional` heavily, so there is
a lot of overlap.
NOTE: the report is actually about `@Conditional` evaluation not auto-configuration
per se, but most autoconfiguration features use `@Conditional` heavily, so there is a lot
of overlap.
Example curl request:
include::{generated}/autoconfig/curl-request.adoc[]

View File

@@ -1,11 +1,8 @@
=== /beans
This endpoint is a report on the Spring Boot `ApplicationContext`. It lists the beans in
the context and their dependencies, detailing the names and concrete classes of each bean.
This endpoint is a report on the Spring Boot `ApplicationContext`. It lists
the beans in the context and their dependencies, detailing the names and
concrete classes of each bean.
NOTE: some beans are pure configuration (any class that is annotated
`@Configuration`).
NOTE: some beans are pure configuration (any class that is annotated `@Configuration`).
Example curl request:
include::{generated}/beans/curl-request.adoc[]

View File

@@ -1,13 +1,10 @@
=== /configprops
This endpoint is a report on the Spring Boot `@ConfigurationProperties`
beans. Beans with this annotation are bound to the `Environment` on
startup, so they reflect the externalised configuration of the application.
Beans are listed by name.
A bean that is added using `@EnableConfigurationProperties` will have
a conventional name: `<prefix>.CONFIGURATION_PROPERTIES`, where
`<prefix>` is the environment key prefix specified in the
`@ConfigurationProperties` annotation.
This endpoint is a report on the Spring Boot `@ConfigurationProperties` beans. Beans with
this annotation are bound to the `Environment` on startup, so they reflect the
externalised configuration of the application. Beans are listed by name. A bean that is
added using `@EnableConfigurationProperties` will have a conventional name:
`<prefix>.CONFIGURATION_PROPERTIES`, where `<prefix>` is the environment key prefix
specified in the `@ConfigurationProperties` annotation.
Example curl request:
include::{generated}/configprops/curl-request.adoc[]

View File

@@ -1,13 +1,11 @@
=== /dump
This endpoint is a thread dump: the result is a list of threads each with their name,
monitor state and stack. It is the same information as you would get from `kill -3` of a
running Java process. Can be very useful for detecting issues at runtime, especially
sluggish behaviour caused by threads blocked by slow or unavailable I/O (e.g. if a
connection pool is exhausted).
This endpoint is a thread dump: the result is a list of threads each with
their name, monitor state and stack. It is the same information as you would
get from `kill -3` of a running Java process. Can be very useful for detecting
issues at runtime, especially sluggish behaviour caused by threads blocked
by slow or unavailable I/O (e.g. if a connection pool is exhausted).
NOTE: some `SecurityManager` implementations might prevent this endpoint
from working.
NOTE: some `SecurityManager` implementations might prevent this endpoint from working.
Example curl request:
include::{generated}/dump/curl-request.adoc[]

View File

@@ -1,11 +1,9 @@
=== /env
This endpoint is a dump of the Spring `Environment`. It lists the active
profiles and all the `PropertySources` in the `Environment` (the ones that
are listed first take precedence when binding to `@ConfigurationProperties`
or `@Value`). Normally you will see the Java `System` properties and the
OS environment variables in their own `PropertySources` plus any `.properties`
or `.yml` files used to configure the application on start up.
This endpoint is a dump of the Spring `Environment`. It lists the active profiles and all
the `PropertySources` in the `Environment` (the ones that are listed first take precedence
when binding to `@ConfigurationProperties` or `@Value`). Normally you will see the Java
`System` properties and the OS environment variables in their own `PropertySources` plus
any `.properties` or `.yml` files used to configure the application on start up.
Example curl request:
include::{generated}/env/curl-request.adoc[]

View File

@@ -1,13 +1,11 @@
=== /health
This endpoint is an indication of the health of the application. It has an overall status
("UP", "DOWN" etc.), which is the only thing you see unless either you are authenticated
or the endpoint is marked as `sensitive=false` (`endpoints.health.sensitive=false`).
This endpoint is an indication of the health of the application.
It has an overall status ("UP", "DOWN" etc.), which is the only thing
you see unless either you are authenticated or the endpoint is marked
as `sensitive=false` (`endpoints.health.sensitive=false`).
The HTTP code in the response reflects the status (e.g. "UP" = 200,
"OUT_OF_SERVICE"=503, "DOWN"=503). The mappings can be changed by
configuring `endpoints.health.mapping.<STATUS>=XXX`.
The HTTP code in the response reflects the status (e.g. "`UP`"=200,
"`OUT_OF_SERVICE`"=503, "`DOWN`"=503). The mappings can be changed by configuring
`endpoints.health.mapping.<STATUS>=XXX`.
Example curl request:
include::{generated}/health/curl-request.adoc[]

View File

@@ -10,12 +10,14 @@ The way that endpoints are exposed will depend on the type of technology that yo
Most applications choose HTTP monitoring, where the ID of the endpoint is mapped
to a URL. For example, by default, the `health` endpoint will be mapped to `/health`.
== List of Endpoints
== List of Endpoints
include::{generated}/endpoints.adoc[]
=== /logfile
=== /logfile
This endpoint (if available) contains the plain text logfile configured by the user
using `logging.file` or `logging.path` (by default logs are only emitted on stdout
so one of these properties has to be set for this endpoint to be active).
@@ -29,21 +31,23 @@ include::{generated}/logfile/http-request.adoc[]
Example HTTP response:
include::{generated}/logfile/http-response.adoc[]
=== /docs
=== /docs
This endpoint (if available) contains HTML documemtation for the other endpoints. Its path
can be "/docs" (if there is an existing home page) or "/" (otherwise, including if the
can be "/docs" (if there is an existing home page) or "/" (otherwise, including if the
HAL browser is not active).
== Hypermedia Support
If https://projects.spring.io/spring-hateoas[Spring HATEOAS] is enabled
(i.e. if it is on the classpath by default) then the Actuator
endpoint responses are enhanced with hypermedia in the form of "links". The default
media type for responses is http://stateless.co/hal_specification.html[HAL], resulting
in each resource having an extra property called "_links". You can change the
media type to another one supported by Spring HATEOAS by providing your own
`@EnableHypermedia` annotation and custom providers as necessary.
== Hypermedia Support
If https://projects.spring.io/spring-hateoas[Spring HATEOAS] is enabled (i.e. if it is
on the classpath by default) then the Actuator endpoint responses are enhanced with
hypermedia in the form of "links". The default media type for responses is
http://stateless.co/hal_specification.html[HAL], resulting in each resource having an
extra property called "_links". You can change the media type to another one supported by
Spring HATEOAS by providing your own `@EnableHypermedia` annotation and custom providers
as necessary.
Example enhanced "/metrics" endpoint with additional "_links":
@@ -55,94 +59,103 @@ The easiest way to avoid that is to use a `management.contextPath`, e.g. "/admin
TIP: You can disable the hypermedia support in Actuator endpoints by setting
`endpoints.links.enabled=false`.
=== Default home page
If the `management.contextPath` is empty, or if the home page provided
by the application happens to be a response body of type `ResourceSupport`, then it will
be enhanced with links to the actuator endpoints. The latter would happen for instance
if you use Spring Data REST to expose `Repository` endpoints.
Example vanilla "/" endpoint if the `management.contextPath` is empty (the "/admin"
page would be the same with different links if `management.contextPath=/admin`):
=== Default home page
If the `management.contextPath` is empty, or if the home page provided by the application
happens to be a response body of type `ResourceSupport`, then it will be enhanced with
links to the actuator endpoints. The latter would happen for instance if you use Spring
Data REST to expose `Repository` endpoints.
Example vanilla "/" endpoint if the `management.contextPath` is empty (the "/admin" page
would be the same with different links if `management.contextPath=/admin`):
include::{generated}/admin/http-response.adoc[]
=== Endpoints with format changes
Some endpoints in their "raw" form consist of an array (e.g. the "/beans" and the "/trace" endpoints).
These need to be converted to objects (maps) before they can be enhanced with
links, so their contents are inserted as a field named "content".
Example enhanced "/beans" endpoint with additional "_links":
=== Endpoints with format changes
Some endpoints in their "`raw`" form consist of an array (e.g. the `/beans` and the
`/trace` endpoints). These need to be converted to objects (maps) before they can be
enhanced with links, so their contents are inserted as a field named "`content`".
Example enhanced `/beans` endpoint with additional `_links`:
include::{generated}/beans/hypermedia/http-response.adoc[]
== HAL Browser
If Hypermedia is enabled and the HAL format is in use (which is the default), then
you can provide a browser for the resources by including a dependency
on the https://github.com/mikekelly/hal-browser[HAL browser] webjar.
== HAL Browser
If Hypermedia is enabled and the HAL format is in use (which is the default), then you
can provide a browser for the resources by including a dependency on the
https://github.com/mikekelly/hal-browser[HAL browser] webjar.
For example in Maven:
[source,xml]
[source,xml,indent=0]
----
<dependency>
<groupId>org.webjars</groupId>
<artifactId>hal-browser</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>hal-browser</artifactId>
</dependency>
----
or in Gradle
[source,groovy]
[source,groovy,indent=0]
----
dependencies {
...
compile('org.webjars:hal-browser')
...
}
dependencies {
...
compile('org.webjars:hal-browser')
...
}
----
NOTE: if you are using Spring Data REST, then a dependency on the `spring-data-rest-hal-browser`
will have an equivalent effect.
NOTE: if you are using Spring Data REST, then a dependency on the
`spring-data-rest-hal-browser` will have an equivalent effect.
If you do that then a new endpoint will appear at "/" or "/hal" (relative to the `management.contextPath`)
serving up a static HTML page with some JavaScript that lets you browse the available
resources. The default endpoint path depends on whether or not there is already a static home page
("index.html") - if there is not and the `management.contextPath` is empty, then the HAL browser
shows up on the home page. Example:
If you do that then a new endpoint will appear at `/` or `/hal` (relative to the
`management.contextPath`) serving up a static HTML page with some JavaScript that lets you
browse the available resources. The default endpoint path depends on whether or not there
is already a static home page ("`index.html`") - if there is not and the
`management.contextPath` is empty, then the HAL browser shows up on the home page.
Example:
image::hal-browser.png[HAL Browser]
TIP: The endpoint path can always, as with all MVC endpoints, be overridden using
`endpoints.hal.path=/yourpath` (note the leading slash).
`endpoints.hal.path=/yourpath` (note the leading slash).
== Actuator Documentation Browser
You can also provide a browser for the standard generated documentation for the Actuator
endpoints by including a dependency on the documentation jar.
You can also provide a browser for the standard generated documentation
for the Actuator endpoints by including a dependency on the documentation jar.
For example in Maven:
[source,xml]
[source,xml,indent=0]
----
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-hypermedia-docs</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-hypermedia-docs</artifactId>
</dependency>
----
or in Gradle
[source,groovy]
[source,groovy,indent=0]
----
dependencies {
...
compile('org.springframework.boot:spring-boot-hypermedia-docs')
...
}
dependencies {
...
compile('org.springframework.boot:spring-boot-hypermedia-docs')
...
}
----
If you do that then a new endpoint at "/" or "/docs" (relative to the `management.contextPath`)
will serve up a static HTML page with this documentation in it. The default endpoint path depends
on whether or not there is already a static home page
("index.html" or a HAL browser) - if there is not and the `management.contextPath` is empty,
then the docs browser shows up on the home page.
If you do that then a new endpoint at `/` or `/docs` (relative to the
`management.contextPath`) will serve up a static HTML page with this documentation in it.
The default endpoint path depends on whether or not there is already a static home page
("index.html" or a HAL browser) - if there is not and the `management.contextPath` is
empty, then the docs browser shows up on the home page.

View File

@@ -1,9 +1,7 @@
=== /info
This endpoint is empty and marked as `sensitive=false`
by default (so it is unauthenticated by default if Spring
Security is in use). It reflects the content of the `info.*` properties
in the `Environment`, as well as the properties in `git.properties`
This endpoint is empty and marked as `sensitive=false` by default (so it is
unauthenticated by default if Spring Security is in use). It reflects the content of the
`info.*` properties in the `Environment`, as well as the properties in `git.properties`
if such a file exists in the root of the classpath.
Example curl request:

View File

@@ -1,8 +1,6 @@
=== /mappings
This endpoint lists the Spring MVC request mappings, so users can
see the handlers registered for requests by path, method, media type,
etc.
This endpoint lists the Spring MVC request mappings, so users can see the handlers
registered for requests by path, method, media type, etc.
Example curl request:
include::{generated}/mappings/curl-request.adoc[]

View File

@@ -1,11 +1,9 @@
=== /metrics
This endpoint lists the public metrics exposed by the application.
By default this includes all the counters in the `CounterService`
and all the gauges in the `GaugeService`, plus a few JVM metrics about
memory and uptime. Users can register additional sources by creating
beans of type `PublicMetrics` and/or by registering counters and
gauges.
This endpoint lists the public metrics exposed by the application. By default this
includes all the counters in the `CounterService` and all the gauges in the
`GaugeService`, plus a few JVM metrics about memory and uptime. Users can register
additional sources by creating beans of type `PublicMetrics` and/or by registering
counters and gauges.
Example curl request:
include::{generated}/metrics/curl-request.adoc[]

View File

@@ -1,10 +1,8 @@
=== /trace
This endpoint lists contents of the `TraceRepository` (which
users can override by providing a bean of that type, or by
injecting that bean and adding stuff to it). By default
it is the last 100 HTTP requests, including all headers in the
request and response, and the path and HTTP status.
This endpoint lists contents of the `TraceRepository` (which users can override by
providing a bean of that type, or by injecting that bean and adding stuff to it). By
default it is the last 100 HTTP requests, including all headers in the request and
response, and the path and HTTP status.
Example curl request:
include::{generated}/trace/curl-request.adoc[]

View File

@@ -1,9 +1,21 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.hypermedia.test;
import static org.springframework.restdocs.RestDocumentation.document;
import static org.springframework.restdocs.RestDocumentation.documentationConfiguration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import groovy.text.Template;
import groovy.text.TemplateEngine;
@@ -40,6 +52,11 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.restdocs.RestDocumentation.document;
import static org.springframework.restdocs.RestDocumentation.documentationConfiguration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringBootHypermediaApplication.class)
@WebAppConfiguration
@@ -82,8 +99,7 @@ public class EndpointDocumentation {
@Test
public void logfile() throws Exception {
this.mockMvc.perform(get("/logfile").accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andDo(document("logfile"));
.andExpect(status().isOk()).andDo(document("logfile"));
}
@Test
@@ -98,10 +114,10 @@ public class EndpointDocumentation {
final String endpointPath = StringUtils.hasText(endpoint.getPath()) ? endpoint
.getPath() : "/";
if (!endpointPath.equals("/docs") && !endpointPath.equals("/logfile")) {
String output = endpointPath.substring(1);
output = output.length() > 0 ? output : "./";
this.mockMvc
if (!endpointPath.equals("/docs") && !endpointPath.equals("/logfile")) {
String output = endpointPath.substring(1);
output = output.length() > 0 ? output : "./";
this.mockMvc
.perform(get(endpointPath).accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andDo(document(output))
.andDo(new ResultHandler() {
@@ -111,7 +127,7 @@ public class EndpointDocumentation {
endpoints.add(endpoint);
}
});
}
}
}
File file = new File(this.restdocsOutputDir + "/endpoints.adoc");
file.getParentFile().mkdirs();

View File

@@ -1,9 +1,21 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.hypermedia.test;
import static org.springframework.restdocs.RestDocumentation.document;
import static org.springframework.restdocs.RestDocumentation.documentationConfiguration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import groovy.text.TemplateEngine;
import org.junit.Before;
@@ -22,11 +34,16 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.restdocs.RestDocumentation.document;
import static org.springframework.restdocs.RestDocumentation.documentationConfiguration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringBootHypermediaApplication.class)
@WebAppConfiguration
@TestPropertySource(properties = { "spring.jackson.serialization.indent_output=true",
"endpoints.health.sensitive=false" })
"endpoints.health.sensitive=false" })
@DirtiesContext
public class HealthEndpointDocumentation {
@@ -49,15 +66,13 @@ public class HealthEndpointDocumentation {
System.setProperty("org.springframework.restdocs.outputDir",
this.restdocsOutputDir);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration())
.build();
.apply(documentationConfiguration()).build();
}
@Test
public void health() throws Exception {
this.mockMvc.perform(get("/health").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("health/unsensitive"));
.andExpect(status().isOk()).andDo(document("health/unsensitive"));
}
}

View File

@@ -1,9 +1,21 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.hypermedia.test;
import static org.springframework.restdocs.RestDocumentation.document;
import static org.springframework.restdocs.RestDocumentation.documentationConfiguration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import groovy.text.TemplateEngine;
import org.junit.Before;
@@ -22,6 +34,11 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.restdocs.RestDocumentation.document;
import static org.springframework.restdocs.RestDocumentation.documentationConfiguration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringBootHypermediaApplication.class)
@WebAppConfiguration
@@ -48,29 +65,25 @@ public class HypermediaEndpointDocumentation {
System.setProperty("org.springframework.restdocs.outputDir",
this.restdocsOutputDir);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration())
.build();
.apply(documentationConfiguration()).build();
}
@Test
public void beans() throws Exception {
this.mockMvc.perform(get("/beans").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("beans/hypermedia"));
.andExpect(status().isOk()).andDo(document("beans/hypermedia"));
}
@Test
public void metrics() throws Exception {
this.mockMvc.perform(get("/metrics").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("metrics/hypermedia"));
.andExpect(status().isOk()).andDo(document("metrics/hypermedia"));
}
@Test
public void home() throws Exception {
this.mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("admin"));
.andExpect(status().isOk()).andDo(document("admin"));
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.hypermedia.test;
import groovy.text.GStringTemplateEngine;
@@ -18,4 +34,5 @@ public class SpringBootHypermediaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootHypermediaApplication.class, args);
}
}