Provide reference documentation for Actuator web endpoints
Closes gh-8042
This commit is contained in:
parent
4ff8126217
commit
4de208bc94
|
@ -419,6 +419,11 @@
|
||||||
<artifactId>spring-integration-jmx</artifactId>
|
<artifactId>spring-integration-jmx</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.restdocs</groupId>
|
||||||
|
<artifactId>spring-restdocs-mockmvc</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-test</artifactId>
|
<artifactId>spring-security-test</artifactId>
|
||||||
|
@ -435,4 +440,157 @@
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>full</id>
|
||||||
|
<activation>
|
||||||
|
<property>
|
||||||
|
<name>full</name>
|
||||||
|
</property>
|
||||||
|
</activation>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-antrun-plugin</artifactId>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ant-contrib</groupId>
|
||||||
|
<artifactId>ant-contrib</artifactId>
|
||||||
|
<version>1.0b3</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>ant</groupId>
|
||||||
|
<artifactId>ant</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.ant</groupId>
|
||||||
|
<artifactId>ant-nodeps</artifactId>
|
||||||
|
<version>1.8.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.tigris.antelope</groupId>
|
||||||
|
<artifactId>antelopetasks</artifactId>
|
||||||
|
<version>3.2.10</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>set-up-maven-properties</id>
|
||||||
|
<phase>prepare-package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>run</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<exportAntProperties>true</exportAntProperties>
|
||||||
|
<target>
|
||||||
|
<taskdef resource="net/sf/antcontrib/antcontrib.properties" />
|
||||||
|
<taskdef name="stringutil" classname="ise.antelope.tasks.StringUtilTask" />
|
||||||
|
<var name="version-type" value="${project.version}" />
|
||||||
|
<propertyregex property="version-type" override="true"
|
||||||
|
input="${version-type}" regexp=".*\.(.*)" replace="\1" />
|
||||||
|
<propertyregex property="version-type" override="true"
|
||||||
|
input="${version-type}" regexp="(M)\d+" replace="MILESTONE" />
|
||||||
|
<propertyregex property="version-type" override="true"
|
||||||
|
input="${version-type}" regexp="(RC)\d+" replace="MILESTONE" />
|
||||||
|
<propertyregex property="version-type" override="true"
|
||||||
|
input="${version-type}" regexp="BUILD-(.*)" replace="SNAPSHOT" />
|
||||||
|
<var name="github-tag" value="v${project.version}" />
|
||||||
|
<propertyregex property="github-tag" override="true"
|
||||||
|
input="${github-tag}" regexp=".*SNAPSHOT" replace="master" />
|
||||||
|
</target>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>package-docs-zip</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>run</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<target>
|
||||||
|
<zip
|
||||||
|
destfile="${project.build.directory}/${project.artifactId}-${project.version}-docs.zip">
|
||||||
|
<zipfileset dir="${project.build.directory}/generated-docs"
|
||||||
|
includes="index.html" prefix="html" />
|
||||||
|
<mappedresources>
|
||||||
|
<fileset dir="${project.build.directory}/generated-docs"
|
||||||
|
includes="index.pdf" />
|
||||||
|
<globmapper from="index.pdf"
|
||||||
|
to="pdf/spring-boot-actuator-web-api.pdf" />
|
||||||
|
</mappedresources>
|
||||||
|
</zip>
|
||||||
|
</target>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.asciidoctor</groupId>
|
||||||
|
<artifactId>asciidoctor-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>generate-html-documentation</id>
|
||||||
|
<phase>prepare-package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>process-asciidoc</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<backend>html</backend>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>generate-pdf-documentation</id>
|
||||||
|
<phase>prepare-package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>process-asciidoc</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<backend>pdf</backend>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<sourceDocumentName>index.adoc</sourceDocumentName>
|
||||||
|
<attributes>
|
||||||
|
<version-type>${version-type}</version-type>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<snippets>${project.build.directory}/generated-snippets/</snippets>
|
||||||
|
</attributes>
|
||||||
|
</configuration>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.asciidoctor</groupId>
|
||||||
|
<artifactId>asciidoctorj-pdf</artifactId>
|
||||||
|
<version>1.5.0-alpha.11</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>build-helper-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>attach-zip</id>
|
||||||
|
<goals>
|
||||||
|
<goal>attach-artifact</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<artifacts>
|
||||||
|
<artifact>
|
||||||
|
<file>${project.build.directory}/${project.artifactId}-${project.version}-docs.zip</file>
|
||||||
|
<type>zip</type>
|
||||||
|
<classifier>docs</classifier>
|
||||||
|
</artifact>
|
||||||
|
</artifacts>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
[[audit-events]]
|
||||||
|
= Audit Events (`auditevents`)
|
||||||
|
|
||||||
|
The `auditevents` endpoint provides information about the application's audit events.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[audit-events-retrieving]]
|
||||||
|
== Retrieving Audit Events
|
||||||
|
|
||||||
|
To retrieve the audit events, make a `GET` request to `/application/auditevents` as shown
|
||||||
|
in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}auditevents/filtered/curl-request.adoc[]
|
||||||
|
|
||||||
|
The preceding example retrieves `logout` events for the principal `alice` that occurred
|
||||||
|
after 09:37 on 7 November 2017 in the UTC timezone. The resulting response is similar to
|
||||||
|
the following::
|
||||||
|
|
||||||
|
include::{snippets}auditevents/filtered/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[audit-events-retrieving-query-parameters]]
|
||||||
|
=== Query Parameters
|
||||||
|
|
||||||
|
The endpoint uses query parameters to limit the events that it returns. The supported
|
||||||
|
query parameters are shown in the following table:
|
||||||
|
|
||||||
|
[cols="2,4"]
|
||||||
|
include::{snippets}auditevents/filtered/request-parameters.adoc[]
|
||||||
|
|
||||||
|
The `after` parameter is required. One or both of the `principal` and `type` parameters
|
||||||
|
can also be used to further limit the results.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[audit-events-retrieving-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of all of the audit events that matched the query. The
|
||||||
|
structure of the response is described in the following table:
|
||||||
|
|
||||||
|
[cols="2,1,3"]
|
||||||
|
include::{snippets}auditevents/after/response-fields.adoc[]
|
|
@ -0,0 +1,29 @@
|
||||||
|
[[beans]]
|
||||||
|
= Beans (`beans`)
|
||||||
|
|
||||||
|
The `beans` endpoint provides information about the application's beans.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[beans-retrieving]]
|
||||||
|
== Retrieving the Beans
|
||||||
|
|
||||||
|
To retrieve the beans, make a `GET` request to `/application/beans` as shown in the
|
||||||
|
following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}beans/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}beans/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[beans-retrieving-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the application's beans. The structure of the response is
|
||||||
|
described in the following table:
|
||||||
|
|
||||||
|
[cols="2,1,3"]
|
||||||
|
include::{snippets}beans/response-fields.adoc[]
|
|
@ -0,0 +1,30 @@
|
||||||
|
[[conditions]]
|
||||||
|
= Conditions Evaluation Report (`conditions`)
|
||||||
|
|
||||||
|
The `conditions` endpoint provides information about the evaluation of conditions on
|
||||||
|
configuration and auto-configuration classes.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[conditions-retrieving]]
|
||||||
|
== Retrieving the Report
|
||||||
|
|
||||||
|
To retrieve the report, make a `GET` request to `/application/conditions`, as shown in
|
||||||
|
the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}conditions/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}conditions/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[conditions-retrieving-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the application's condition evaluation. The following
|
||||||
|
table describes the structure of the response:
|
||||||
|
|
||||||
|
[cols="3,1,3"]
|
||||||
|
include::{snippets}conditions/response-fields.adoc[]
|
|
@ -0,0 +1,30 @@
|
||||||
|
[[configprops]]
|
||||||
|
= Configuration Properties (`configprops`)
|
||||||
|
|
||||||
|
The `configprops` endpoint provides information about the application's
|
||||||
|
`@ConfigurationProperties` beans.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[configprops-retrieving]]
|
||||||
|
== Retrieving the `@ConfigurationProperties` Bean
|
||||||
|
|
||||||
|
To retrieve the `@ConfigurationProperties` beans, make a `GET` request to
|
||||||
|
`/application/configprops` as shown in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}configprops/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}configprops/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[configprops-retrieving-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the application's `@ConfigurationProperties` beans. The
|
||||||
|
structure of the response is described in the following table:
|
||||||
|
|
||||||
|
[cols="2,1,3"]
|
||||||
|
include::{snippets}configprops/response-fields.adoc[]
|
|
@ -0,0 +1,55 @@
|
||||||
|
[[env]]
|
||||||
|
= Environment (`env`)
|
||||||
|
|
||||||
|
The `env` endpoint provides information about the application's `Environment`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[env-entire]]
|
||||||
|
== Retrieving the Entire Environment
|
||||||
|
|
||||||
|
To retrieve the entire environment, make a `GET` request to `/application/env` as shown in
|
||||||
|
the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}env/all/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}env/all/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[env-entire-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the application's `Environment`. The structure of the
|
||||||
|
response is described in the following table:
|
||||||
|
|
||||||
|
[cols="3,1,3"]
|
||||||
|
include::{snippets}env/all/response-fields.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[env-single-property]]
|
||||||
|
== Retrieving a Single Property
|
||||||
|
|
||||||
|
To retrieve a single property, make a `GET` request to `/application/env/{property.name}`
|
||||||
|
as shown in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}env/single/curl-request.adoc[]
|
||||||
|
|
||||||
|
The preceding example retrieves information about the property named
|
||||||
|
`com.example.cache.max-size`. The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}env/single/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[env-single-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the requested property. The structure of the response is
|
||||||
|
described in the following table:
|
||||||
|
|
||||||
|
[cols="3,1,3"]
|
||||||
|
include::{snippets}env/single/response-fields.adoc[]
|
|
@ -0,0 +1,29 @@
|
||||||
|
[[flyway]]
|
||||||
|
= Flyway (`flyway`)
|
||||||
|
|
||||||
|
The `flyway` endpoint provides information about database migrations performed by Flyway.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[flyway-retrieving]]
|
||||||
|
== Retrieving the Migrations
|
||||||
|
|
||||||
|
To retrieve the migrations, make a `GET` request to `/application/flyway` as shown in the
|
||||||
|
following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}flyway/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}flyway/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[flyway-retrieving-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the application's Flyway migrations. The structure of the
|
||||||
|
response is described in the following table:
|
||||||
|
|
||||||
|
[cols="2,1,3"]
|
||||||
|
include::{snippets}flyway/response-fields.adoc[]
|
|
@ -0,0 +1,29 @@
|
||||||
|
[[health]]
|
||||||
|
= Health (`health`)
|
||||||
|
|
||||||
|
The `health` endpoint provides detailed information about the health of the application.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[health-retrieving]]
|
||||||
|
== Retrieving the Health
|
||||||
|
|
||||||
|
To retrieve the health of the application, make a `GET` request to `/application/health`
|
||||||
|
as shown in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}health/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}health/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[health-retrieving-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the health of the application. The structure of the
|
||||||
|
response is described in the following table:
|
||||||
|
|
||||||
|
[cols="2,1,3"]
|
||||||
|
include::{snippets}health/response-fields.adoc[]
|
|
@ -0,0 +1,20 @@
|
||||||
|
[[heapdump]]
|
||||||
|
= Heap Dump (`heapdump`)
|
||||||
|
|
||||||
|
The `heapdump` endpoint provides a heap dump from the application's JVM.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[heapdump-retrieving]]
|
||||||
|
== Retrieving the Heap dump
|
||||||
|
|
||||||
|
To retrieve the heap dump, make a `GET` request to `/application/heapdump`. The response
|
||||||
|
is binary data in https://docs.oracle.com/javase/8/docs/technotes/samples/hprof.html[
|
||||||
|
HPROF] format and can be large. Typically, you should save the response to disk for
|
||||||
|
subsequent analysis. When using curl this can be achieved using the `-O` option as shown
|
||||||
|
in the following example:
|
||||||
|
|
||||||
|
include::{snippets}heapdump/curl-request.adoc[]
|
||||||
|
|
||||||
|
The preceding example results in a file named `heapdump` being written to the current
|
||||||
|
working directory.
|
|
@ -0,0 +1,47 @@
|
||||||
|
[[info]]
|
||||||
|
= Info (`info`)
|
||||||
|
|
||||||
|
The `info` endpoint provides general information about the application.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[info-retrieving]]
|
||||||
|
== Retrieving the Info
|
||||||
|
|
||||||
|
To retrieve the information about the application, make a `GET` request to
|
||||||
|
`/application/info` as shown in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}info/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}info/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[info-retrieving-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains general information about the application. Each section of the
|
||||||
|
response is contributed by an `InfoContributor`. Spring Boot provides `build` and `git`
|
||||||
|
contributions.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[info-retrieving-response-structure-build]]
|
||||||
|
==== `build` Response Structure
|
||||||
|
|
||||||
|
The structure of the `build` section of the response is described in the following table:
|
||||||
|
|
||||||
|
[cols="2,1,3"]
|
||||||
|
include::{snippets}info/response-fields-beneath-build.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[info-retrieving-response-structure-git]]
|
||||||
|
==== `git` Response Structure
|
||||||
|
|
||||||
|
The structure of the `git` section of the response is described in the following table:
|
||||||
|
|
||||||
|
[cols="2,1,3"]
|
||||||
|
include::{snippets}info/response-fields-beneath-git.adoc[]
|
|
@ -0,0 +1,30 @@
|
||||||
|
[[liquibase]]
|
||||||
|
= Liquibase (`liquibase`)
|
||||||
|
|
||||||
|
The `liquibase` endpoint provides information about database change sets applied by
|
||||||
|
Liquibase.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[liquibase-retrieving]]
|
||||||
|
== Retrieving the Changes
|
||||||
|
|
||||||
|
To retrieve the changes, make a `GET` request to `/application/liquibase` as shown in the
|
||||||
|
following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}liquibase/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}liquibase/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[liquibase-retrieving-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the application's Liquibase change sets. The structure of
|
||||||
|
the response is described in the following table:
|
||||||
|
|
||||||
|
[cols="2,1,3"]
|
||||||
|
include::{snippets}liquibase/response-fields.adoc[]
|
|
@ -0,0 +1,35 @@
|
||||||
|
[[log-file]]
|
||||||
|
= Log File (`logfile`)
|
||||||
|
|
||||||
|
The `logfile` endpoint provides access to the contents of the application's log file.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[logfile-retrieving]]
|
||||||
|
== Retrieving the Log File
|
||||||
|
|
||||||
|
To retrieve the log file, make a `GET` request to `/application/logfile` as shown in the
|
||||||
|
following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}logfile/entire/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}logfile/entire/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[logfile-retrieving-part]]
|
||||||
|
== Retrieving Part of the Log File
|
||||||
|
|
||||||
|
NOTE: Retrieving part of the log file is not supported when using Jersey.
|
||||||
|
|
||||||
|
To retrieve part of the log file, make a `GET` request to `/application/logfile` using
|
||||||
|
the `Range` header as shown in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}logfile/range/curl-request.adoc[]
|
||||||
|
|
||||||
|
The preceding example retrieves the first 1024 bytes of the log file. The resulting
|
||||||
|
response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}logfile/range/http-response.adoc[]
|
|
@ -0,0 +1,94 @@
|
||||||
|
[[loggers]]
|
||||||
|
= Loggers (`loggers`)
|
||||||
|
|
||||||
|
The `loggers` endpoint provides access to the application's loggers and configuration of
|
||||||
|
their levels.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[loggers-all]]
|
||||||
|
== Retrieving all Loggers
|
||||||
|
|
||||||
|
To retrieve the application's loggers, make a `GET` request to `/application/loggers` as
|
||||||
|
shown in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}loggers/all/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}loggers/all/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[loggers-all-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the application's loggers. The structure of the response
|
||||||
|
is described in the following table:
|
||||||
|
|
||||||
|
[cols="3,1,3"]
|
||||||
|
include::{snippets}loggers/all/response-fields.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[loggers-single]]
|
||||||
|
== Retrieving a Single Logger
|
||||||
|
|
||||||
|
To retrieve a single logger, make a `GET` request to `/application/loggers/{logger.name}`
|
||||||
|
as shown in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}loggers/single/curl-request.adoc[]
|
||||||
|
|
||||||
|
The preceding example retrieves information about the logger named `com.example`. The
|
||||||
|
resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}loggers/single/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[loggerse-single-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the requested logger. The structure of the response is
|
||||||
|
described in the following table:
|
||||||
|
|
||||||
|
[cols="3,1,3"]
|
||||||
|
include::{snippets}loggers/single/response-fields.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[loggers-setting-level]]
|
||||||
|
== Setting a Log Level
|
||||||
|
|
||||||
|
To set the level of a logger, make a `POST` request to
|
||||||
|
`/application/loggers/{logger.name}` with a JSON body that specifies the configured level
|
||||||
|
for the logger as shown in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}loggers/set/curl-request.adoc[]
|
||||||
|
|
||||||
|
The preceding example sets the `configuredLevel` of the `com.example` logger to `DEBUG`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[loggers-setting-level-request-structure]]
|
||||||
|
=== Request Structure
|
||||||
|
|
||||||
|
The request specifies the desired level of the logger. The structure of the request is
|
||||||
|
described in the following table:
|
||||||
|
|
||||||
|
[cols="3,1,3"]
|
||||||
|
include::{snippets}loggers/set/request-fields.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[loggers-clearing-level]]
|
||||||
|
== Clearing a Log Level
|
||||||
|
|
||||||
|
To clear the level of a logger, make a `POST` request to
|
||||||
|
`/application/loggers/{logger.name}` with a JSON body containing an empty object as shown
|
||||||
|
in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}loggers/clear/curl-request.adoc[]
|
||||||
|
|
||||||
|
The preceding example clears the configured level of the `com.example` logger.
|
|
@ -0,0 +1,80 @@
|
||||||
|
[[metrics]]
|
||||||
|
= Metrics (`metrics`)
|
||||||
|
|
||||||
|
The `metrics` endpoint provides access to application metrics.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[metrics-retrieving-names]]
|
||||||
|
== Retrieving Metric Names
|
||||||
|
|
||||||
|
To retrieve the names of the available metrics, make a `GET` request to
|
||||||
|
`/application/metrics` as shown in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}metrics/names/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}metrics/names/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[metrics-retrieving-names-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the metric names. The structure of the response is
|
||||||
|
described in the following table:
|
||||||
|
|
||||||
|
[cols="3,1,2"]
|
||||||
|
include::{snippets}metrics/names/response-fields.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[metrics-retrieving-metric]]
|
||||||
|
== Retrieving a Metric
|
||||||
|
|
||||||
|
To retrieve a metric, make a `GET` request to `/application/metrics/{metric.name}` as
|
||||||
|
shown in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}metrics/metric/curl-request.adoc[]
|
||||||
|
|
||||||
|
The preceding example retrieves information about the metric named `jvm.memory.max`. The
|
||||||
|
resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}metrics/metric/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[metrics-retrieving-metric-query-parameters]]
|
||||||
|
=== Query Parameters
|
||||||
|
|
||||||
|
The endpoint uses query parameters to <<metrics-drilling-down,drill down>> into a metric
|
||||||
|
using its tags. The single supported query parameter is shown in the following table:
|
||||||
|
|
||||||
|
[cols="2,4"]
|
||||||
|
include::{snippets}metrics/metric-with-tags/request-parameters.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[metrics-retrieving-metric-response-structure]]
|
||||||
|
=== Response structure
|
||||||
|
|
||||||
|
The response contains details of the metric. The structure of the response is described in
|
||||||
|
the following table:
|
||||||
|
|
||||||
|
include::{snippets}metrics/metric/response-fields.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
[[metrics-drilling-down]]
|
||||||
|
== Drilling Down
|
||||||
|
|
||||||
|
To drill down into a metric, make a `GET` request to `/application/metrics/{metric.name}`
|
||||||
|
using the `tag` query parameter as shown in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}metrics/metric-with-tags/curl-request.adoc[]
|
||||||
|
|
||||||
|
The preceding example retrieves the `jvm.memory.max` metric where the `area` tag has a
|
||||||
|
value of `nonheap` and the `id` attribute has a value of `Code Cache`. The resulting
|
||||||
|
response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}metrics/metric-with-tags/http-response.adoc[]
|
|
@ -0,0 +1,19 @@
|
||||||
|
[[prometheus]]
|
||||||
|
= Prometheus (`prometheus`)
|
||||||
|
|
||||||
|
The `prometheus` endpoint provides Spring Boot application's metrics in the format
|
||||||
|
required for scraping by a Prometheus server.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[prometheus-retrieving]]
|
||||||
|
== Retrieving the Metrics
|
||||||
|
|
||||||
|
To retrieve the metrics, make a `GET` request to `/application/prometheus` as shown in the
|
||||||
|
following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}prometheus/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}prometheus/http-response.adoc[]
|
|
@ -0,0 +1,30 @@
|
||||||
|
[[scheduled-tasks]]
|
||||||
|
= Scheduled Tasks (`scheduledtasks`)
|
||||||
|
|
||||||
|
The `scheduledtasks` endpoint provides information about the application's scheduled
|
||||||
|
tasks.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[scheduled-tasks-retrieving]]
|
||||||
|
== Retrieving the Scheduled Tasks
|
||||||
|
|
||||||
|
To retrieve the scheduled tasks, make a `GET` request to `/application/scheduledtasks`,
|
||||||
|
as shown in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}scheduled-tasks/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}scheduled-tasks/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[scheduled-tasks-retrieving-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the application's scheduled tasks. The following table
|
||||||
|
describes the structure of the response:
|
||||||
|
|
||||||
|
[cols="2,1,3"]
|
||||||
|
include::{snippets}scheduled-tasks/response-fields.adoc[]
|
|
@ -0,0 +1,84 @@
|
||||||
|
[[sessions]]
|
||||||
|
= Sessions (`sessions`)
|
||||||
|
|
||||||
|
The `sessions` endpoint provides information about the application's HTTP sessions that
|
||||||
|
are managed by Spring Session.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[sessions-retrieving]]
|
||||||
|
== Retrieving Sessions
|
||||||
|
|
||||||
|
To retrieve the sessions, make a `GET` request to `/application/sessions` as shown in the
|
||||||
|
following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}sessions/username/curl-request.adoc[]
|
||||||
|
|
||||||
|
The preceding examples retrieves all of the sessions for the user with the username
|
||||||
|
`alice`.
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}sessions/username/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[sessions-retrieving-query-parameters]]
|
||||||
|
=== Query Parameters
|
||||||
|
|
||||||
|
The endpoint uses query parameters to limit the sessions that it returns. The single
|
||||||
|
required query parameter is shown in the following table:
|
||||||
|
|
||||||
|
[cols="2,4"]
|
||||||
|
include::{snippets}sessions/username/request-parameters.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[sessions-retrieving-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the matching sessions. The structure of the response is
|
||||||
|
described in the following table:
|
||||||
|
|
||||||
|
[cols="3,1,3"]
|
||||||
|
include::{snippets}sessions/username/response-fields.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[sessions-retrieving-id]]
|
||||||
|
== Retrieving a Single Session
|
||||||
|
|
||||||
|
To retrieve a single session, make a `GET` request to `/application/sessions/{id}` as
|
||||||
|
shown in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}sessions/id/curl-request.adoc[]
|
||||||
|
|
||||||
|
The preceding example retrieves the session with the id
|
||||||
|
`4db5efcc-99cb-4d05-a52c-b49acfbb7ea9`. The resulting response is similar to the
|
||||||
|
following:
|
||||||
|
|
||||||
|
include::{snippets}sessions/id/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[sessions-retrieving-id-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the requested session. The structure of the response is
|
||||||
|
described in the following table:
|
||||||
|
|
||||||
|
[cols="3,1,3"]
|
||||||
|
include::{snippets}sessions/id/response-fields.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[sessions-deleting]]
|
||||||
|
== Deleting a Session
|
||||||
|
|
||||||
|
To delete a session, make a `DELETE` request to `/application/sessions/{id}` as shown in
|
||||||
|
the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}sessions/delete/curl-request.adoc[]
|
||||||
|
|
||||||
|
The preceding example deletes the session with the id
|
||||||
|
`4db5efcc-99cb-4d05-a52c-b49acfbb7ea9`.
|
|
@ -0,0 +1,29 @@
|
||||||
|
[[shutdown]]
|
||||||
|
= Shutdown (`shutdown`)
|
||||||
|
|
||||||
|
The `shutdown` endpoint is used to shut down the application.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[shutdown-shutting-down]]
|
||||||
|
== Shutting Down the Application
|
||||||
|
|
||||||
|
To shut down the application, make a `POST` request to `/application/shutdown` as shown in
|
||||||
|
the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}shutdown/curl-request.adoc[]
|
||||||
|
|
||||||
|
A response similar to the following is produced:
|
||||||
|
|
||||||
|
include::{snippets}shutdown/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[shutdowm-shutting-down-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the result of the shutdown request. The structure of the
|
||||||
|
response is described in the following table:
|
||||||
|
|
||||||
|
[cols="3,1,3"]
|
||||||
|
include::{snippets}shutdown/response-fields.adoc[]
|
|
@ -0,0 +1,29 @@
|
||||||
|
[[status]]
|
||||||
|
= Status (`status`)
|
||||||
|
|
||||||
|
The `status` endpoint provides an overview of the status of the application.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[status-retrieving]]
|
||||||
|
== Retrieving the Status
|
||||||
|
|
||||||
|
To retrieve the status of the application, make a `GET` request to `/application/status`
|
||||||
|
as shown in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}status/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}status/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[status-retrieving-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains the status of the application. The structure of the response is
|
||||||
|
described in the following table:
|
||||||
|
|
||||||
|
[cols="2,1,3"]
|
||||||
|
include::{snippets}status/response-fields.adoc[]
|
|
@ -0,0 +1,29 @@
|
||||||
|
[[threaddump]]
|
||||||
|
= Thread Dump (`threaddump`)
|
||||||
|
|
||||||
|
The `threaddump` endpoint provides a thread dump from the application's JVM.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[threaddump-retrieving]]
|
||||||
|
== Retrieving the Thread Dump
|
||||||
|
|
||||||
|
To retrieve the thread dump, make a `GET` request to `/application/threaddump` as shown
|
||||||
|
in the following curl-based example:
|
||||||
|
|
||||||
|
include::{snippets}threaddump/curl-request.adoc[]
|
||||||
|
|
||||||
|
The resulting response is similar to the following:
|
||||||
|
|
||||||
|
include::{snippets}threaddump/http-response.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[threaddump-retrieving-response-structure]]
|
||||||
|
=== Response Structure
|
||||||
|
|
||||||
|
The response contains details of the JVM's threads. The structure of the response is
|
||||||
|
described in the following table:
|
||||||
|
|
||||||
|
[cols="3,1,2"]
|
||||||
|
include::{snippets}threaddump/response-fields.adoc[]
|
|
@ -0,0 +1,65 @@
|
||||||
|
= Spring Boot Actuator Web API Documentation
|
||||||
|
Andy Wilkinson
|
||||||
|
:doctype: book
|
||||||
|
:toc: left
|
||||||
|
:toclevels: 4
|
||||||
|
:source-highlighter: prettify
|
||||||
|
:numbered:
|
||||||
|
:icons: font
|
||||||
|
:hide-uri-scheme:
|
||||||
|
|
||||||
|
This API documentation describes Spring Boot Actuators web endpoints.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[overview]]
|
||||||
|
== Overview
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[overview-endpoint-urls]]
|
||||||
|
=== URLs
|
||||||
|
|
||||||
|
By default, all web endpoints are available beneath the path `/application` with URLs of
|
||||||
|
the form `/application/{id}`. The `/application` base path can be configured using the
|
||||||
|
`management.endpoints.web.base-path` property, as shown in the following example:
|
||||||
|
|
||||||
|
[source,properties,indent=0]
|
||||||
|
----
|
||||||
|
management.endpoints.web.base-path=/manage
|
||||||
|
----
|
||||||
|
|
||||||
|
The preceding `application.properties` example changes the form of the endpoint URLs from
|
||||||
|
`/application/{id}` to `/manage/{id}`. For example, the URL `info` endpoint would become
|
||||||
|
`/manage/info`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[overview-timestamps]]
|
||||||
|
=== Timestamps
|
||||||
|
|
||||||
|
All timestamps that are consumed by the endpoints, either as query parameters or in the
|
||||||
|
request body, must be formatted as an offset date and time as specified in
|
||||||
|
https://en.wikipedia.org/wiki/ISO_8601[ISO 8601].
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
include::endpoints/auditevents.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/beans.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/conditions.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/configprops.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/env.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/flyway.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/health.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/heapdump.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/info.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/liquibase.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/logfile.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/loggers.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/metrics.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/prometheus.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/scheduledtasks.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/sessions.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/shutdown.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/status.adoc[leveloffset=+1]
|
||||||
|
include::endpoints/threaddump.adoc[leveloffset=+1]
|
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
import org.flywaydb.core.internal.util.StringUtils;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||||
|
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||||
|
import org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.restdocs.JUnitRestDocumentation;
|
||||||
|
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
|
||||||
|
import org.springframework.restdocs.operation.preprocess.ContentModifyingOperationPreprocessor;
|
||||||
|
import org.springframework.restdocs.operation.preprocess.OperationPreprocessor;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||||
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base class for tests that generate endpoint documentation using Spring REST
|
||||||
|
* Docs.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(properties = { "spring.jackson.serialization.indent_output=true",
|
||||||
|
"management.endpoints.web.expose=*" })
|
||||||
|
public abstract class AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||||
|
|
||||||
|
protected MockMvc mockMvc;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WebApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.applicationContext)
|
||||||
|
.apply(MockMvcRestDocumentation
|
||||||
|
.documentationConfiguration(this.restDocumentation).uris())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String describeEnumValues(Class<? extends Enum<?>> enumType) {
|
||||||
|
return StringUtils
|
||||||
|
.collectionToCommaDelimitedString(Stream.of(enumType.getEnumConstants())
|
||||||
|
.map((constant) -> "`" + constant.name() + "`")
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected OperationPreprocessor limit(String key) {
|
||||||
|
return limit(key, (candidate) -> true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected <T> OperationPreprocessor limit(String key, Predicate<T> filter) {
|
||||||
|
return new ContentModifyingOperationPreprocessor((content, mediaType) -> {
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper()
|
||||||
|
.enable(SerializationFeature.INDENT_OUTPUT);
|
||||||
|
try {
|
||||||
|
Map<String, Object> payload = objectMapper.readValue(content, Map.class);
|
||||||
|
Object entry = payload.get(key);
|
||||||
|
if (entry instanceof Map) {
|
||||||
|
payload.put(key, select((Map<String, Object>) entry, filter));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
payload.put(key, select((List<Object>) entry, filter));
|
||||||
|
}
|
||||||
|
return objectMapper.writeValueAsBytes(payload);
|
||||||
|
}
|
||||||
|
catch (IOException ex) {
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T> Map<String, Object> select(Map<String, Object> candidates,
|
||||||
|
Predicate<T> filter) {
|
||||||
|
Map<String, Object> selected = new HashMap<String, Object>();
|
||||||
|
candidates.entrySet().stream().filter((candidate) -> filter.test((T) candidate))
|
||||||
|
.limit(3)
|
||||||
|
.forEach((entry) -> selected.put(entry.getKey(), entry.getValue()));
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T> List<Object> select(List<Object> candidates, Predicate<T> filter) {
|
||||||
|
return candidates.stream().filter((candidate) -> filter.test((T) candidate))
|
||||||
|
.limit(3).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import({ JacksonAutoConfiguration.class,
|
||||||
|
HttpMessageConvertersAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||||
|
DispatcherServletAutoConfiguration.class, EndpointAutoConfiguration.class,
|
||||||
|
WebEndpointAutoConfiguration.class,
|
||||||
|
WebMvcEndpointManagementContextConfiguration.class,
|
||||||
|
PropertyPlaceholderAutoConfiguration.class })
|
||||||
|
static class BaseDocumentationConfiguration {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.audit.AuditEvent;
|
||||||
|
import org.springframework.boot.actuate.audit.AuditEventRepository;
|
||||||
|
import org.springframework.boot.actuate.audit.AuditEventsEndpoint;
|
||||||
|
import org.springframework.boot.actuate.audit.AuditEventsEndpointWebExtension;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||||
|
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing {@link AuditEventsEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class AuditEventsEndpointDocumentationTests
|
||||||
|
extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private AuditEventRepository repository;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void allAuditEventsAfter() throws Exception {
|
||||||
|
String queryTimestamp = "2017-11-07T09:37Z";
|
||||||
|
given(this.repository.find(any(), any(), any())).willReturn(
|
||||||
|
Arrays.asList(new AuditEvent("alice", "logout", Collections.emptyMap())));
|
||||||
|
this.mockMvc
|
||||||
|
.perform(get("/application/auditevents").param("after", queryTimestamp))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(document("auditevents/after", responseFields(
|
||||||
|
fieldWithPath("events").description("An array of audit events."),
|
||||||
|
fieldWithPath("events.[].timestamp")
|
||||||
|
.description("The timestamp of when the event occurred."),
|
||||||
|
fieldWithPath("events.[].principal")
|
||||||
|
.description("The principal that triggered the event."),
|
||||||
|
fieldWithPath("events.[].type")
|
||||||
|
.description("The type of the event."))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void filteredAuditEvents() throws Exception {
|
||||||
|
ZonedDateTime now = ZonedDateTime.now();
|
||||||
|
String queryTimestamp = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(now);
|
||||||
|
Date date = new Date(now.toEpochSecond() * 1000);
|
||||||
|
given(this.repository.find("alice", date, "logout")).willReturn(
|
||||||
|
Arrays.asList(new AuditEvent("alice", "logout", Collections.emptyMap())));
|
||||||
|
this.mockMvc
|
||||||
|
.perform(get("/application/auditevents").param("principal", "alice")
|
||||||
|
.param("after", queryTimestamp).param("type", "logout"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(document("auditevents/filtered",
|
||||||
|
requestParameters(
|
||||||
|
parameterWithName("after").description(
|
||||||
|
"Restricts the events to those that occurred "
|
||||||
|
+ "after the given time. Required."),
|
||||||
|
parameterWithName("principal").description(
|
||||||
|
"Restricts the events to those with the given "
|
||||||
|
+ "principal. Optional."),
|
||||||
|
parameterWithName("type").description(
|
||||||
|
"Restricts the events to those with the given "
|
||||||
|
+ "type. Optional."))));
|
||||||
|
verify(this.repository).find("alice", date, "logout");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AuditEventsEndpoint auditEventsEndpoint(AuditEventRepository repository) {
|
||||||
|
return new AuditEventsEndpoint(repository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AuditEventsEndpointWebExtension adAuditEventsWebEndpointExtension(
|
||||||
|
AuditEventsEndpoint delegate) {
|
||||||
|
return new AuditEventsEndpointWebExtension(delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.beans.BeansEndpoint;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.restdocs.payload.FieldDescriptor;
|
||||||
|
import org.springframework.restdocs.payload.JsonFieldType;
|
||||||
|
import org.springframework.restdocs.payload.ResponseFieldsSnippet;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||||
|
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing {@link BeansEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class BeansEndpointDocumentationTests extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void beans() throws Exception {
|
||||||
|
List<FieldDescriptor> beanFields = Arrays
|
||||||
|
.asList(fieldWithPath("aliases").description("Names of any aliases."),
|
||||||
|
fieldWithPath("scope")
|
||||||
|
.description("Scope of the bean."),
|
||||||
|
fieldWithPath("type").description("Fully qualified type of the bean."),
|
||||||
|
fieldWithPath("resource")
|
||||||
|
.description("Resource in which the bean was defined, if any.")
|
||||||
|
.optional(),
|
||||||
|
fieldWithPath("dependencies").description("Names of any dependencies."));
|
||||||
|
ResponseFieldsSnippet responseFields = responseFields(
|
||||||
|
fieldWithPath("contextId").description("ID of the application context."),
|
||||||
|
fieldWithPath("beans.*")
|
||||||
|
.description("Beans in the application context keyed by name."))
|
||||||
|
.andWithPrefix("beans.*.", beanFields)
|
||||||
|
.and(subsectionWithPath("parent")
|
||||||
|
.description("Beans in the parent application "
|
||||||
|
+ "context, if any.")
|
||||||
|
.type(JsonFieldType.OBJECT).optional());
|
||||||
|
this.mockMvc.perform(get("/application/beans")).andExpect(status().isOk())
|
||||||
|
.andDo(document("beans",
|
||||||
|
preprocessResponse(limit("beans", this::isIndependentBean)),
|
||||||
|
responseFields));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isIndependentBean(Entry<String, Map<String, Object>> bean) {
|
||||||
|
return CollectionUtils.isEmpty((Collection<?>) bean.getValue().get("aliases"))
|
||||||
|
&& CollectionUtils
|
||||||
|
.isEmpty((Collection<?>) bean.getValue().get("dependencies"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public BeansEndpoint beansEndpoint(ConfigurableApplicationContext context) {
|
||||||
|
return new BeansEndpoint(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
|
import org.springframework.boot.actuate.autoconfigure.condition.ConditionsReportEndpoint;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
|
||||||
|
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.restdocs.JUnitRestDocumentation;
|
||||||
|
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
|
||||||
|
import org.springframework.restdocs.payload.JsonFieldType;
|
||||||
|
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.operation.preprocess.Preprocessors.preprocessResponse;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing {@link ConditionsReportEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class ConditionsReportEndpointDocumentationTests
|
||||||
|
extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||||
|
|
||||||
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WebApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.applicationContext)
|
||||||
|
.apply(MockMvcRestDocumentation
|
||||||
|
.documentationConfiguration(this.restDocumentation).uris())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void conditions() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/conditions")).andExpect(status().isOk())
|
||||||
|
.andDo(MockMvcRestDocumentation.document("conditions",
|
||||||
|
preprocessResponse(limit("positiveMatches"),
|
||||||
|
limit("negativeMatches")),
|
||||||
|
responseFields(
|
||||||
|
fieldWithPath("positiveMatches").description(
|
||||||
|
"Classes and methods with conditions that were matched."),
|
||||||
|
fieldWithPath("positiveMatches.*.[].condition")
|
||||||
|
.description("Name of the condition."),
|
||||||
|
fieldWithPath("positiveMatches.*.[].message").description(
|
||||||
|
"Details of why the condition was matched."),
|
||||||
|
fieldWithPath("negativeMatches").description(
|
||||||
|
"Classes and methods with conditions that were not matched."),
|
||||||
|
fieldWithPath("negativeMatches.*.notMatched")
|
||||||
|
.description("Conditions that were matched."),
|
||||||
|
fieldWithPath("negativeMatches.*.notMatched.[].condition")
|
||||||
|
.description("Name of the condition."),
|
||||||
|
fieldWithPath("negativeMatches.*.notMatched.[].message")
|
||||||
|
.description(
|
||||||
|
"Details of why the condition was not matched."),
|
||||||
|
fieldWithPath("negativeMatches.*.matched")
|
||||||
|
.description("Conditions that were matched."),
|
||||||
|
fieldWithPath("negativeMatches.*.matched.[].condition")
|
||||||
|
.description("Name of the condition.")
|
||||||
|
.type(JsonFieldType.STRING).optional(),
|
||||||
|
fieldWithPath("negativeMatches.*.matched.[].message")
|
||||||
|
.description(
|
||||||
|
"Details of why the condition was matched.")
|
||||||
|
.type(JsonFieldType.STRING).optional(),
|
||||||
|
fieldWithPath("unconditionalClasses").description(
|
||||||
|
"Names of unconditional auto-configuration classes, if any."))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ConditionsReportEndpoint autoConfigurationReportEndpoint(
|
||||||
|
ConfigurableListableBeanFactory beanFactory) {
|
||||||
|
ConditionEvaluationReport conditionEvaluationReport = ConditionEvaluationReport
|
||||||
|
.get(beanFactory);
|
||||||
|
conditionEvaluationReport.recordEvaluationCandidates(
|
||||||
|
Arrays.asList(PropertyPlaceholderAutoConfiguration.class.getName()));
|
||||||
|
return new ConditionsReportEndpoint(conditionEvaluationReport);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
|
||||||
|
import org.springframework.restdocs.payload.JsonFieldType;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing
|
||||||
|
* {@link ConfigurationPropertiesReportEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class ConfigurationPropertiesReportEndpointDocumentationTests
|
||||||
|
extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void configProps() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/configprops")).andExpect(status().isOk())
|
||||||
|
.andDo(MockMvcRestDocumentation.document("configprops",
|
||||||
|
preprocessResponse(limit("beans")),
|
||||||
|
responseFields(
|
||||||
|
fieldWithPath("contextId")
|
||||||
|
.description("ID of the application context."),
|
||||||
|
fieldWithPath("beans.*").description(
|
||||||
|
"`@ConfigurationProperties` beans keyed by bean name."),
|
||||||
|
fieldWithPath("beans.*.prefix").description(
|
||||||
|
"Prefix applied to the names of the bean's properties."),
|
||||||
|
subsectionWithPath("beans.*.properties").description(
|
||||||
|
"Properties of the bean as name-value pairs."),
|
||||||
|
subsectionWithPath("parent")
|
||||||
|
.description(
|
||||||
|
"`@ConfigurationProperties` beans in the parent "
|
||||||
|
+ "context, if any.")
|
||||||
|
.optional().type(JsonFieldType.OBJECT))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ConfigurationPropertiesReportEndpoint endpoint() {
|
||||||
|
return new ConfigurationPropertiesReportEndpoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,179 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.env.EnvironmentEndpoint;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.core.env.AbstractEnvironment;
|
||||||
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
|
import org.springframework.core.env.EnumerablePropertySource;
|
||||||
|
import org.springframework.core.env.MutablePropertySources;
|
||||||
|
import org.springframework.core.env.PropertySource;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.restdocs.operation.preprocess.ContentModifyingOperationPreprocessor;
|
||||||
|
import org.springframework.restdocs.operation.preprocess.OperationPreprocessor;
|
||||||
|
import org.springframework.restdocs.payload.FieldDescriptor;
|
||||||
|
import org.springframework.test.context.TestPropertySource;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||||
|
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
|
||||||
|
import static org.springframework.restdocs.operation.preprocess.Preprocessors.replacePattern;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing the {@link EnvironmentEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
@TestPropertySource(properties = "spring.config.location=classpath:/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/")
|
||||||
|
public class EnvironmentEndpointDocumentationTests
|
||||||
|
extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
private static final FieldDescriptor activeProfiles = fieldWithPath("activeProfiles")
|
||||||
|
.description("Names of the active profiles, if any.");
|
||||||
|
|
||||||
|
private static final FieldDescriptor propertySources = fieldWithPath(
|
||||||
|
"propertySources").description("Property sources in order of precedence.");
|
||||||
|
|
||||||
|
private static final FieldDescriptor propertySourceName = fieldWithPath(
|
||||||
|
"propertySources.[].name").description("Name of the property source.");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void env() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/env")).andExpect(status().isOk())
|
||||||
|
.andDo(document("env/all",
|
||||||
|
preprocessResponse(replacePattern(
|
||||||
|
Pattern.compile(
|
||||||
|
"org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/"),
|
||||||
|
""), filterProperties()),
|
||||||
|
responseFields(activeProfiles, propertySources,
|
||||||
|
propertySourceName,
|
||||||
|
fieldWithPath("propertySources.[].properties")
|
||||||
|
.description(
|
||||||
|
"Properties in the property source keyed by property name."),
|
||||||
|
fieldWithPath("propertySources.[].properties.*.value")
|
||||||
|
.description("Value of the property."),
|
||||||
|
fieldWithPath("propertySources.[].properties.*.origin")
|
||||||
|
.description("Origin of the property, if any.")
|
||||||
|
.optional())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void singlePropertyFromEnv() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/env/com.example.cache.max-size"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(document("env/single",
|
||||||
|
preprocessResponse(replacePattern(
|
||||||
|
Pattern.compile(
|
||||||
|
"org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/"),
|
||||||
|
"")),
|
||||||
|
responseFields(
|
||||||
|
fieldWithPath("property").description(
|
||||||
|
"Property from the environment, if found.")
|
||||||
|
.optional(),
|
||||||
|
fieldWithPath("property.source").description(
|
||||||
|
"Name of the source of the property."),
|
||||||
|
fieldWithPath("property.value")
|
||||||
|
.description("Value of the property."),
|
||||||
|
activeProfiles, propertySources, propertySourceName,
|
||||||
|
fieldWithPath("propertySources.[].property").description(
|
||||||
|
"Property in the property source, if any.")
|
||||||
|
.optional(),
|
||||||
|
fieldWithPath("propertySources.[].property.value")
|
||||||
|
.description("Value of the property."),
|
||||||
|
fieldWithPath("propertySources.[].property.origin")
|
||||||
|
.description("Origin of the property, if any.")
|
||||||
|
.optional())));
|
||||||
|
}
|
||||||
|
|
||||||
|
private OperationPreprocessor filterProperties() {
|
||||||
|
return new ContentModifyingOperationPreprocessor(this::filterProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private byte[] filterProperties(byte[] content, MediaType mediaType) {
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper()
|
||||||
|
.enable(SerializationFeature.INDENT_OUTPUT);
|
||||||
|
try {
|
||||||
|
Map<String, Object> payload = objectMapper.readValue(content, Map.class);
|
||||||
|
List<Map<String, Object>> propertySources = (List<Map<String, Object>>) payload
|
||||||
|
.get("propertySources");
|
||||||
|
for (Map<String, Object> propertySource : propertySources) {
|
||||||
|
Map<String, String> properties = (Map<String, String>) propertySource
|
||||||
|
.get("properties");
|
||||||
|
Set<String> filteredKeys = properties.keySet().stream()
|
||||||
|
.filter(this::retainKey).limit(3).collect(Collectors.toSet());
|
||||||
|
properties.keySet().retainAll(filteredKeys);
|
||||||
|
}
|
||||||
|
return objectMapper.writeValueAsBytes(payload);
|
||||||
|
}
|
||||||
|
catch (IOException ex) {
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean retainKey(String key) {
|
||||||
|
return key.startsWith("java.") || key.equals("JAVA_HOME")
|
||||||
|
|| key.startsWith("com.example");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public EnvironmentEndpoint endpoint(ConfigurableEnvironment environment) {
|
||||||
|
return new EnvironmentEndpoint(new AbstractEnvironment() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void customizePropertySources(
|
||||||
|
MutablePropertySources propertySources) {
|
||||||
|
StreamSupport
|
||||||
|
.stream(environment.getPropertySources().spliterator(), false)
|
||||||
|
.filter(this::includedPropertySource)
|
||||||
|
.forEach(propertySources::addLast);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean includedPropertySource(PropertySource<?> propertySource) {
|
||||||
|
return propertySource instanceof EnumerablePropertySource
|
||||||
|
&& !"Inlined Test Properties"
|
||||||
|
.equals(propertySource.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.flywaydb.core.Flyway;
|
||||||
|
import org.flywaydb.core.api.MigrationState;
|
||||||
|
import org.flywaydb.core.api.MigrationType;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.flyway.FlywayEndpoint;
|
||||||
|
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||||
|
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
|
||||||
|
import org.springframework.restdocs.payload.FieldDescriptor;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing the {@link FlywayEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
@AutoConfigureTestDatabase
|
||||||
|
public class FlywayEndpointDocumentationTests extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void flyway() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/flyway")).andExpect(status().isOk())
|
||||||
|
.andDo(MockMvcRestDocumentation.document("flyway",
|
||||||
|
responseFields(fieldWithPath("*.migrations").description(
|
||||||
|
"Migrations performed by the Flyway instance, keyed by"
|
||||||
|
+ " bean name.")).andWithPrefix(
|
||||||
|
"*.migrations.[].",
|
||||||
|
migrationFieldDescriptors())));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<FieldDescriptor> migrationFieldDescriptors() {
|
||||||
|
return Arrays.asList(
|
||||||
|
fieldWithPath("checksum")
|
||||||
|
.description("Checksum of the migration, if any.").optional(),
|
||||||
|
fieldWithPath("description")
|
||||||
|
.description("Description of the migration, if any.").optional(),
|
||||||
|
fieldWithPath("executionTime")
|
||||||
|
.description(
|
||||||
|
"Execution time in milliseconds of an applied migration.")
|
||||||
|
.optional(),
|
||||||
|
fieldWithPath("installedBy")
|
||||||
|
.description("User that installed the applied migration, if any.")
|
||||||
|
.optional(),
|
||||||
|
fieldWithPath("installedOn").description(
|
||||||
|
"Timestamp of when the applied migration was installed, "
|
||||||
|
+ "if any.")
|
||||||
|
.optional(),
|
||||||
|
fieldWithPath("installedRank").description(
|
||||||
|
"Rank of the applied migration, if any. Later migrations have "
|
||||||
|
+ "higher ranks.")
|
||||||
|
.optional(),
|
||||||
|
fieldWithPath("script")
|
||||||
|
.description(
|
||||||
|
"Name of the script used to execute the migration, if any.")
|
||||||
|
.optional(),
|
||||||
|
fieldWithPath("state").description("State of the migration. ("
|
||||||
|
+ describeEnumValues(MigrationState.class) + ")"),
|
||||||
|
fieldWithPath("type").description("Type of the migration. ("
|
||||||
|
+ describeEnumValues(MigrationType.class) + ")"),
|
||||||
|
fieldWithPath("version").description(
|
||||||
|
"Version of the database after applying the migration, "
|
||||||
|
+ "if any.")
|
||||||
|
.optional());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import({ BaseDocumentationConfiguration.class, EmbeddedDataSourceConfiguration.class,
|
||||||
|
FlywayAutoConfiguration.class })
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FlywayEndpoint endpoint(Map<String, Flyway> flyways) {
|
||||||
|
return new FlywayEndpoint(flyways);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.health.CompositeHealthIndicator;
|
||||||
|
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||||
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
|
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
||||||
|
import org.springframework.boot.actuate.jdbc.DataSourceHealthIndicator;
|
||||||
|
import org.springframework.boot.actuate.system.DiskSpaceHealthIndicator;
|
||||||
|
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing the {@link HealthEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class HealthEndpointDocumentationTests extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void health() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/health")).andExpect(status().isOk())
|
||||||
|
.andDo(document("health",
|
||||||
|
responseFields(
|
||||||
|
fieldWithPath("status").description(
|
||||||
|
"Overall status of the application."),
|
||||||
|
fieldWithPath("details")
|
||||||
|
.description("Details of the health of the application."),
|
||||||
|
fieldWithPath("details.*.status").description(
|
||||||
|
"Status of a specific part of the application."),
|
||||||
|
subsectionWithPath("details.*.details").description(
|
||||||
|
"Details of the health of a specific part of the"
|
||||||
|
+ " application."))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
@ImportAutoConfiguration(DataSourceAutoConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public HealthEndpoint endpoint(Map<String, HealthIndicator> healthIndicators) {
|
||||||
|
return new HealthEndpoint(new CompositeHealthIndicator(
|
||||||
|
new OrderedHealthAggregator(), healthIndicators));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DiskSpaceHealthIndicator diskSpaceHealthIndicator() {
|
||||||
|
return new DiskSpaceHealthIndicator(new File("."), 1024 * 1024 * 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSourceHealthIndicator dataSourceHealthIndicator(
|
||||||
|
DataSource dataSource) {
|
||||||
|
return new DataSourceHealthIndicator(dataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.management.HeapDumpWebEndpoint;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.restdocs.cli.CliDocumentation;
|
||||||
|
import org.springframework.restdocs.cli.CurlRequestSnippet;
|
||||||
|
import org.springframework.restdocs.operation.Operation;
|
||||||
|
import org.springframework.util.FileCopyUtils;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing the {@link HeapDumpWebEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class HeapDumpWebEndpointDocumentationTests
|
||||||
|
extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void heapDump() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/heapdump")).andExpect(status().isOk())
|
||||||
|
.andDo(document("heapdump",
|
||||||
|
new CurlRequestSnippet(CliDocumentation.multiLineFormat()) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<String, Object> createModel(
|
||||||
|
Operation operation) {
|
||||||
|
Map<String, Object> model = super.createModel(operation);
|
||||||
|
model.put("options", "-O");
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public HeapDumpWebEndpoint endpoint() {
|
||||||
|
return new HeapDumpWebEndpoint() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HeapDumper createHeapDumper()
|
||||||
|
throws HeapDumperUnavailableException {
|
||||||
|
return (file, live) -> FileCopyUtils.copy("<<binary content>>",
|
||||||
|
new FileWriter(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.info.BuildInfoContributor;
|
||||||
|
import org.springframework.boot.actuate.info.GitInfoContributor;
|
||||||
|
import org.springframework.boot.actuate.info.InfoContributor;
|
||||||
|
import org.springframework.boot.actuate.info.InfoEndpoint;
|
||||||
|
import org.springframework.boot.info.BuildProperties;
|
||||||
|
import org.springframework.boot.info.GitProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
|
||||||
|
import org.springframework.restdocs.payload.JsonFieldType;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing the {@link InfoEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class InfoEndpointDocumentationTests extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void info() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/info")).andExpect(status().isOk())
|
||||||
|
.andDo(MockMvcRestDocumentation.document("info",
|
||||||
|
responseFields(beneathPath("git"),
|
||||||
|
fieldWithPath("branch")
|
||||||
|
.description("Name of the Git branch, if any."),
|
||||||
|
fieldWithPath("commit")
|
||||||
|
.description("Details of the Git commit, if any."),
|
||||||
|
fieldWithPath("commit.time")
|
||||||
|
.description("Timestamp of the commit, if any.")
|
||||||
|
.type(JsonFieldType.VARIES),
|
||||||
|
fieldWithPath("commit.id")
|
||||||
|
.description("ID of the commit, if any.")),
|
||||||
|
responseFields(beneathPath("build"),
|
||||||
|
fieldWithPath("artifact")
|
||||||
|
.description(
|
||||||
|
"Artifact ID of the application, if any.")
|
||||||
|
.optional(),
|
||||||
|
fieldWithPath("group")
|
||||||
|
.description(
|
||||||
|
"Group ID of the application, if any.")
|
||||||
|
.optional(),
|
||||||
|
fieldWithPath("name")
|
||||||
|
.description("Name of the application, if any.")
|
||||||
|
.type(JsonFieldType.STRING).optional(),
|
||||||
|
fieldWithPath("version")
|
||||||
|
.description(
|
||||||
|
"Version of the application, if any.")
|
||||||
|
.optional(),
|
||||||
|
fieldWithPath("time")
|
||||||
|
.description(
|
||||||
|
"Timestamp of when the application was built, if any.")
|
||||||
|
.type(JsonFieldType.VARIES).optional())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public InfoEndpoint endpoint(List<InfoContributor> infoContributors) {
|
||||||
|
return new InfoEndpoint(infoContributors);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public GitInfoContributor gitInfoContributor() {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.put("branch", "master");
|
||||||
|
properties.put("commit.id", "df027cf1ec5aeba2d4fedd7b8c42b88dc5ce38e5");
|
||||||
|
properties.put("commit.id.abbrev", "df027cf");
|
||||||
|
properties.put("commit.time", Long.toString(System.currentTimeMillis()));
|
||||||
|
GitProperties gitProperties = new GitProperties(properties);
|
||||||
|
return new GitInfoContributor(gitProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public BuildInfoContributor buildInfoContributor() {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.put("group", "com.example");
|
||||||
|
properties.put("artifact", "application");
|
||||||
|
properties.put("version", "1.0.3");
|
||||||
|
BuildProperties buildProperties = new BuildProperties(properties);
|
||||||
|
return new BuildInfoContributor(buildProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import liquibase.changelog.ChangeSet.ExecType;
|
||||||
|
import liquibase.integration.spring.SpringLiquibase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.liquibase.LiquibaseEndpoint;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
|
||||||
|
import org.springframework.restdocs.payload.FieldDescriptor;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing the {@link LiquibaseEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class LiquibaseEndpointDocumentationTests
|
||||||
|
extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void liquibase() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/liquibase")).andExpect(status().isOk())
|
||||||
|
.andDo(MockMvcRestDocumentation.document("liquibase",
|
||||||
|
responseFields(fieldWithPath("*.changeSets").description(
|
||||||
|
"Change sets made by the Liquibase beans, keyed by "
|
||||||
|
+ "bean name.")).andWithPrefix("*.changeSets[].",
|
||||||
|
getChangeSetFieldDescriptors())));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<FieldDescriptor> getChangeSetFieldDescriptors() {
|
||||||
|
return Arrays.asList(
|
||||||
|
fieldWithPath("author").description("Author of the change set."),
|
||||||
|
fieldWithPath("changeLog")
|
||||||
|
.description("Change log that contains the change set."),
|
||||||
|
fieldWithPath("comments").description("Comments on the change set."),
|
||||||
|
fieldWithPath("contexts").description("Contexts of the change set."),
|
||||||
|
fieldWithPath("dateExecuted")
|
||||||
|
.description("Timestamp of when the change set was executed."),
|
||||||
|
fieldWithPath("deploymentId")
|
||||||
|
.description("ID of the deployment that ran the change set."),
|
||||||
|
fieldWithPath("description")
|
||||||
|
.description("Description of the change set."),
|
||||||
|
fieldWithPath("execType").description("Execution type of the change set ("
|
||||||
|
+ describeEnumValues(ExecType.class) + ")."),
|
||||||
|
fieldWithPath("id").description("ID of the change set."),
|
||||||
|
fieldWithPath("labels")
|
||||||
|
.description("Labels associated with the change set."),
|
||||||
|
fieldWithPath("checksum").description("Checksum of the change set."),
|
||||||
|
fieldWithPath("orderExecuted")
|
||||||
|
.description("Order of the execution of the change set."),
|
||||||
|
fieldWithPath("tag").description("Tag associated with the change set."));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import({ BaseDocumentationConfiguration.class, EmbeddedDataSourceConfiguration.class,
|
||||||
|
LiquibaseAutoConfiguration.class })
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LiquibaseEndpoint endpoint(Map<String, SpringLiquibase> liquibases) {
|
||||||
|
return new LiquibaseEndpoint(liquibases);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.logging.LogFileWebEndpoint;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
|
||||||
|
import org.springframework.test.context.TestPropertySource;
|
||||||
|
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing the {@link LogFileWebEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
@TestPropertySource(properties = "logging.file=src/test/resources/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/sample.log")
|
||||||
|
public class LogFileWebEndpointDocumentationTests
|
||||||
|
extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void logFile() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/logfile")).andExpect(status().isOk())
|
||||||
|
.andDo(MockMvcRestDocumentation.document("logfile/entire"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void logFileRange() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/logfile").header("Range", "bytes=0-1023"))
|
||||||
|
.andExpect(status().isPartialContent())
|
||||||
|
.andDo(MockMvcRestDocumentation.document("logfile/range"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LogFileWebEndpoint endpoint(Environment environment) {
|
||||||
|
return new LogFileWebEndpoint(environment);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.logging.LoggersEndpoint;
|
||||||
|
import org.springframework.boot.logging.LogLevel;
|
||||||
|
import org.springframework.boot.logging.LoggerConfiguration;
|
||||||
|
import org.springframework.boot.logging.LoggingSystem;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
|
||||||
|
import org.springframework.restdocs.payload.FieldDescriptor;
|
||||||
|
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing the {@link LoggersEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class LoggersEndpointDocumentationTests
|
||||||
|
extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
private static final List<FieldDescriptor> levelFields = Arrays.asList(
|
||||||
|
fieldWithPath("configuredLevel")
|
||||||
|
.description("Configured level of the logger, if any.").optional(),
|
||||||
|
fieldWithPath("effectiveLevel")
|
||||||
|
.description("Effective level of the logger."));
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private LoggingSystem loggingSystem;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void allLoggers() throws Exception {
|
||||||
|
given(this.loggingSystem.getSupportedLogLevels())
|
||||||
|
.willReturn(EnumSet.allOf(LogLevel.class));
|
||||||
|
given(this.loggingSystem.getLoggerConfigurations()).willReturn(Arrays.asList(
|
||||||
|
new LoggerConfiguration("ROOT", LogLevel.INFO, LogLevel.INFO),
|
||||||
|
new LoggerConfiguration("com.example", LogLevel.DEBUG, LogLevel.DEBUG)));
|
||||||
|
this.mockMvc.perform(get("/application/loggers")).andExpect(status().isOk())
|
||||||
|
.andDo(MockMvcRestDocumentation.document("loggers/all",
|
||||||
|
responseFields(
|
||||||
|
fieldWithPath("levels").description(
|
||||||
|
"Levels support by the logging system."),
|
||||||
|
fieldWithPath("loggers").description("Loggers keyed by name."))
|
||||||
|
.andWithPrefix("loggers.*.", levelFields)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void logger() throws Exception {
|
||||||
|
given(this.loggingSystem.getLoggerConfiguration("com.example")).willReturn(
|
||||||
|
new LoggerConfiguration("com.example", LogLevel.INFO, LogLevel.INFO));
|
||||||
|
this.mockMvc.perform(get("/application/loggers/com.example"))
|
||||||
|
.andExpect(status().isOk()).andDo(MockMvcRestDocumentation
|
||||||
|
.document("loggers/single", responseFields(levelFields)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setLogLevel() throws Exception {
|
||||||
|
this.mockMvc
|
||||||
|
.perform(post("/application/loggers/com.example")
|
||||||
|
.content("{\"configuredLevel\":\"debug\"}")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent())
|
||||||
|
.andDo(MockMvcRestDocumentation
|
||||||
|
.document("loggers/set",
|
||||||
|
requestFields(fieldWithPath("configuredLevel")
|
||||||
|
.description("Level for the logger. May be"
|
||||||
|
+ " omitted to clear the level.")
|
||||||
|
.optional())));
|
||||||
|
verify(this.loggingSystem).setLogLevel("com.example", LogLevel.DEBUG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clearLogLevel() throws Exception {
|
||||||
|
this.mockMvc
|
||||||
|
.perform(post("/application/loggers/com.example").content("{}")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent())
|
||||||
|
.andDo(MockMvcRestDocumentation.document("loggers/clear"));
|
||||||
|
verify(this.loggingSystem).setLogLevel("com.example", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LoggersEndpoint endpoint(LoggingSystem loggingSystem) {
|
||||||
|
return new LoggersEndpoint(loggingSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import io.micrometer.core.instrument.Statistic;
|
||||||
|
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
|
||||||
|
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.metrics.MetricsEndpoint;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||||
|
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing the {@link MetricsEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class MetricsEndpointDocumentationTests
|
||||||
|
extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void metricNames() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/metrics")).andExpect(status().isOk())
|
||||||
|
.andDo(document("metrics/names", responseFields(fieldWithPath("names")
|
||||||
|
.description("Names of the known metrics."))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void metric() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/metrics/jvm.memory.max"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(document("metrics/metric",
|
||||||
|
responseFields(
|
||||||
|
fieldWithPath("name").description("Name of the metric"),
|
||||||
|
fieldWithPath("measurements")
|
||||||
|
.description("Measurements of the metric"),
|
||||||
|
fieldWithPath("measurements[].statistic")
|
||||||
|
.description("Statistic of the measurement. ("
|
||||||
|
+ describeEnumValues(Statistic.class) + ")."),
|
||||||
|
fieldWithPath("measurements[].value")
|
||||||
|
.description("Value of the measurement."),
|
||||||
|
fieldWithPath("availableTags")
|
||||||
|
.description("Tags that are available for drill-down."),
|
||||||
|
fieldWithPath("availableTags[].tag")
|
||||||
|
.description("Name of the tag."),
|
||||||
|
fieldWithPath("availableTags[].values")
|
||||||
|
.description("Possible values of the tag."))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void metricWithTags() throws Exception {
|
||||||
|
this.mockMvc
|
||||||
|
.perform(get("/application/metrics/jvm.memory.max")
|
||||||
|
.param("tag", "area:nonheap").param("tag", "id:Code Cache"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(document("metrics/metric-with-tags",
|
||||||
|
requestParameters(parameterWithName("tag").description(
|
||||||
|
"A tag to use for drill-down in the form `name:value`."))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MetricsEndpoint endpoint() {
|
||||||
|
SimpleMeterRegistry registry = new SimpleMeterRegistry();
|
||||||
|
new JvmMemoryMetrics().bindTo(registry);
|
||||||
|
return new MetricsEndpoint(registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import io.micrometer.core.instrument.Clock;
|
||||||
|
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
|
||||||
|
import io.micrometer.prometheus.PrometheusConfig;
|
||||||
|
import io.micrometer.prometheus.PrometheusMeterRegistry;
|
||||||
|
import io.prometheus.client.CollectorRegistry;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusScrapeEndpoint;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing the {@link PrometheusScrapeEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class PrometheusScrapeEndpointDocumentationTests
|
||||||
|
extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void prometheus() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/prometheus")).andExpect(status().isOk())
|
||||||
|
.andDo(document("prometheus"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PrometheusScrapeEndpoint endpoint() {
|
||||||
|
CollectorRegistry collectorRegistry = new CollectorRegistry(true);
|
||||||
|
PrometheusMeterRegistry meterRegistry = new PrometheusMeterRegistry(
|
||||||
|
new PrometheusConfig() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get(String key) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}, collectorRegistry, Clock.SYSTEM);
|
||||||
|
new JvmMemoryMetrics().bindTo(meterRegistry);
|
||||||
|
return new PrometheusScrapeEndpoint(collectorRegistry);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.restdocs.payload.FieldDescriptor;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.scheduling.config.ScheduledTaskHolder;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||||
|
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
|
||||||
|
import static org.springframework.restdocs.operation.preprocess.Preprocessors.replacePattern;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing the {@link ScheduledTasksEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class ScheduledTasksEndpointDocumentationTests
|
||||||
|
extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void scheduledTasks() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/scheduledtasks"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(document("scheduled-tasks",
|
||||||
|
preprocessResponse(replacePattern(
|
||||||
|
Pattern.compile(
|
||||||
|
"org.*\\.ScheduledTasksEndpointDocumentationTests\\$"
|
||||||
|
+ "TestConfiguration"),
|
||||||
|
"com.example.Processor")),
|
||||||
|
responseFields(
|
||||||
|
fieldWithPath("cron").description("Cron tasks, if any."),
|
||||||
|
targetFieldWithPrefix("cron.[]"),
|
||||||
|
fieldWithPath("cron.[].expression")
|
||||||
|
.description("Cron expression."),
|
||||||
|
fieldWithPath("fixedDelay")
|
||||||
|
.description("Fixed delay tasks, if any."),
|
||||||
|
targetFieldWithPrefix("fixedDelay.[]"),
|
||||||
|
initialDelayWithPrefix("fixedDelay.[]."),
|
||||||
|
fieldWithPath("fixedDelay.[].interval").description(
|
||||||
|
"Interval, in milliseconds, between the end of the last"
|
||||||
|
+ " execution and the start of the next."),
|
||||||
|
fieldWithPath("fixedRate")
|
||||||
|
.description("Fixed rate tasks, if any."),
|
||||||
|
targetFieldWithPrefix("fixedRate.[]."),
|
||||||
|
fieldWithPath("fixedRate.[].interval").description(
|
||||||
|
"Interval, in milliseconds, between the start of each execution."),
|
||||||
|
initialDelayWithPrefix("fixedRate.[]."))));
|
||||||
|
}
|
||||||
|
|
||||||
|
private FieldDescriptor targetFieldWithPrefix(String prefix) {
|
||||||
|
return fieldWithPath(prefix + "runnable.target")
|
||||||
|
.description("Target that will be executed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private FieldDescriptor initialDelayWithPrefix(String prefix) {
|
||||||
|
return fieldWithPath(prefix + "initialDelay")
|
||||||
|
.description("Delay, in milliseconds, before first execution.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableScheduling
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ScheduledTasksEndpoint endpoint(Collection<ScheduledTaskHolder> holders) {
|
||||||
|
return new ScheduledTasksEndpoint(holders);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scheduled(cron = "0 0 0/3 1/1 * ?")
|
||||||
|
public void processOrders() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scheduled(fixedDelay = 5000, initialDelay = 5000)
|
||||||
|
public void purge() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scheduled(fixedRate = 3000, initialDelay = 10000)
|
||||||
|
public void retrieveIssues() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.context.ShutdownEndpoint;
|
||||||
|
import org.springframework.boot.actuate.session.SessionsEndpoint;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.restdocs.payload.FieldDescriptor;
|
||||||
|
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||||
|
import org.springframework.session.MapSession;
|
||||||
|
import org.springframework.session.Session;
|
||||||
|
import org.springframework.test.context.TestPropertySource;
|
||||||
|
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||||
|
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing the {@link ShutdownEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
@TestPropertySource(properties = "spring.jackson.serialization.write-dates-as-timestamps=false")
|
||||||
|
public class SessionsEndpointDocumentationTests
|
||||||
|
extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
private static final Session sessionOne = createSession(
|
||||||
|
Instant.now().minusSeconds(60 * 60 * 12), Instant.now().minusSeconds(45));
|
||||||
|
|
||||||
|
private static final Session sessionTwo = createSession(
|
||||||
|
"4db5efcc-99cb-4d05-a52c-b49acfbb7ea9",
|
||||||
|
Instant.now().minusSeconds(60 * 60 * 5), Instant.now().minusSeconds(37));
|
||||||
|
|
||||||
|
private static final Session sessionThree = createSession(
|
||||||
|
Instant.now().minusSeconds(60 * 60 * 2), Instant.now().minusSeconds(12));
|
||||||
|
|
||||||
|
private static final List<FieldDescriptor> sessionFields = Arrays
|
||||||
|
.asList(fieldWithPath("id").description("ID of the session."),
|
||||||
|
fieldWithPath("attributeNames").description(
|
||||||
|
"Names of the attributes stored in the session."),
|
||||||
|
fieldWithPath("creationTime")
|
||||||
|
.description("Timestamp of when the session was created."),
|
||||||
|
fieldWithPath("lastAccessedTime")
|
||||||
|
.description("Timestamp of when the session was last accessed."),
|
||||||
|
fieldWithPath("maxInactiveInterval")
|
||||||
|
.description("Maximum permitted period of inactivity, in seconds, "
|
||||||
|
+ "before the session will expire."),
|
||||||
|
fieldWithPath("expired").description("Whether the session has expired."));
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private FindByIndexNameSessionRepository<Session> sessionRepository;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void sessionsForUsername() throws Exception {
|
||||||
|
Map<String, Session> sessions = new HashMap<>();
|
||||||
|
sessions.put(sessionOne.getId(), sessionOne);
|
||||||
|
sessions.put(sessionTwo.getId(), sessionTwo);
|
||||||
|
sessions.put(sessionThree.getId(), sessionThree);
|
||||||
|
given(this.sessionRepository.findByIndexNameAndIndexValue(
|
||||||
|
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, "alice"))
|
||||||
|
.willReturn(sessions);
|
||||||
|
this.mockMvc.perform(get("/application/sessions").param("username", "alice"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(document("sessions/username",
|
||||||
|
responseFields(fieldWithPath("sessions")
|
||||||
|
.description("Sessions for the given username."))
|
||||||
|
.andWithPrefix("sessions.[].", sessionFields),
|
||||||
|
requestParameters(parameterWithName("username")
|
||||||
|
.description("Name of the user."))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void sessionWithId() throws Exception {
|
||||||
|
Map<String, Session> sessions = new HashMap<>();
|
||||||
|
sessions.put(sessionOne.getId(), sessionOne);
|
||||||
|
sessions.put(sessionTwo.getId(), sessionTwo);
|
||||||
|
sessions.put(sessionThree.getId(), sessionThree);
|
||||||
|
given(this.sessionRepository.findById(sessionTwo.getId())).willReturn(sessionTwo);
|
||||||
|
this.mockMvc.perform(get("/application/sessions/{id}", sessionTwo.getId()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(document("sessions/id", responseFields(sessionFields)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteASession() throws Exception {
|
||||||
|
this.mockMvc.perform(delete("/application/sessions/{id}", sessionTwo.getId()))
|
||||||
|
.andExpect(status().isNoContent()).andDo(document("sessions/delete"));
|
||||||
|
verify(this.sessionRepository).deleteById(sessionTwo.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MapSession createSession(Instant creationTime,
|
||||||
|
Instant lastAccessedTime) {
|
||||||
|
return createSession(UUID.randomUUID().toString(), creationTime,
|
||||||
|
lastAccessedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MapSession createSession(String id, Instant creationTime,
|
||||||
|
Instant lastAccessedTime) {
|
||||||
|
MapSession session = new MapSession(id);
|
||||||
|
session.setCreationTime(creationTime);
|
||||||
|
session.setLastAccessedTime(lastAccessedTime);
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SessionsEndpoint endpoint(
|
||||||
|
FindByIndexNameSessionRepository<?> sessionRepository) {
|
||||||
|
return new SessionsEndpoint(sessionRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.context.ShutdownEndpoint;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
|
||||||
|
import org.springframework.test.context.TestPropertySource;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing the {@link ShutdownEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
@TestPropertySource(properties = "endpoints.shutdown.enabled=true")
|
||||||
|
public class ShutdownEndpointDocumentationTests
|
||||||
|
extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shutdown() throws Exception {
|
||||||
|
this.mockMvc.perform(post("/application/shutdown")).andExpect(status().isOk())
|
||||||
|
.andDo(MockMvcRestDocumentation.document("shutdown",
|
||||||
|
responseFields(fieldWithPath("message").description(
|
||||||
|
"Message describing the result of the request."))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ShutdownEndpoint endpoint(Environment environment) {
|
||||||
|
ShutdownEndpoint endpoint = new ShutdownEndpoint();
|
||||||
|
endpoint.setApplicationContext(new AnnotationConfigApplicationContext());
|
||||||
|
return endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.health.CompositeHealthIndicator;
|
||||||
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
|
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
||||||
|
import org.springframework.boot.actuate.health.StatusEndpoint;
|
||||||
|
import org.springframework.boot.actuate.jdbc.DataSourceHealthIndicator;
|
||||||
|
import org.springframework.boot.actuate.system.DiskSpaceHealthIndicator;
|
||||||
|
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing the {@link StatusEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class StatusEndpointDocumentationTests extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void health() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/status")).andExpect(status().isOk())
|
||||||
|
.andDo(document("status", responseFields(fieldWithPath("status")
|
||||||
|
.description("Overall status of the application."))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
@ImportAutoConfiguration(DataSourceAutoConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public StatusEndpoint endpoint(Map<String, HealthIndicator> healthIndicators) {
|
||||||
|
return new StatusEndpoint(new CompositeHealthIndicator(
|
||||||
|
new OrderedHealthAggregator(), healthIndicators));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DiskSpaceHealthIndicator diskSpaceHealthIndicator() {
|
||||||
|
return new DiskSpaceHealthIndicator(new File("."), 1024 * 1024 * 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSourceHealthIndicator dataSourceHealthIndicator(
|
||||||
|
DataSource dataSource) {
|
||||||
|
return new DataSourceHealthIndicator(dataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.autoconfigure.endpoint.web.documentation;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.management.ThreadDumpEndpoint;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
|
||||||
|
import org.springframework.restdocs.payload.JsonFieldType;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for generating documentation describing {@link ThreadDumpEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class ThreadDumpEndpointDocumentationTests
|
||||||
|
extends AbstractEndpointDocumentationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void threadDump() throws Exception {
|
||||||
|
this.mockMvc.perform(get("/application/threaddump")).andExpect(status().isOk())
|
||||||
|
.andDo(MockMvcRestDocumentation.document("threaddump",
|
||||||
|
preprocessResponse(limit("threads")),
|
||||||
|
responseFields(
|
||||||
|
fieldWithPath("threads").description("JVM's threads."),
|
||||||
|
fieldWithPath("threads.[].threadName")
|
||||||
|
.description("Name of the thread."),
|
||||||
|
fieldWithPath("threads.[].threadId")
|
||||||
|
.description("ID of the thread."),
|
||||||
|
fieldWithPath("threads.[].blockedTime").description(
|
||||||
|
"Time in milliseconds that the thread has spent "
|
||||||
|
+ "blocked. -1 if thread contention "
|
||||||
|
+ "monitoring is disabled."),
|
||||||
|
fieldWithPath("threads.[].blockedCount").description(
|
||||||
|
"Total number of times that the thread has been "
|
||||||
|
+ "blocked."),
|
||||||
|
fieldWithPath("threads.[].waitedTime").description(
|
||||||
|
"Time in milliseconds that the thread has spent "
|
||||||
|
+ "waiting. -1 if thread contention "
|
||||||
|
+ "monitoring is disabled"),
|
||||||
|
fieldWithPath("threads.[].waitedCount").description(
|
||||||
|
"Total number of times that the thread has waited"
|
||||||
|
+ " for notification."),
|
||||||
|
fieldWithPath("threads.[].lockName")
|
||||||
|
.description(
|
||||||
|
"Description of the object on which the "
|
||||||
|
+ "thread is blocked, if any.")
|
||||||
|
.optional(),
|
||||||
|
fieldWithPath("threads.[].lockOwnerId").description(
|
||||||
|
"ID of the thread that owns the object on which "
|
||||||
|
+ "the thread is blocked. `-1` if the "
|
||||||
|
+ "thread is not blocked."),
|
||||||
|
fieldWithPath("threads.[].lockOwnerName")
|
||||||
|
.description(
|
||||||
|
"Name of the thread that owns the object "
|
||||||
|
+ "on which the thread is blocked.")
|
||||||
|
.optional(),
|
||||||
|
fieldWithPath("threads.[].inNative").description(
|
||||||
|
"Whether the thread is executing native code."),
|
||||||
|
fieldWithPath("threads.[].suspended")
|
||||||
|
.description("Whether the thread is suspended."),
|
||||||
|
fieldWithPath("threads.[].threadState")
|
||||||
|
.description("State of the thread ("
|
||||||
|
+ describeEnumValues(Thread.State.class)
|
||||||
|
+ ")."),
|
||||||
|
fieldWithPath("threads.[].stackTrace")
|
||||||
|
.description("Stack trace of the thread."),
|
||||||
|
fieldWithPath("threads.[].stackTrace.[].methodName")
|
||||||
|
.description("Name of the method."),
|
||||||
|
fieldWithPath("threads.[].stackTrace.[].fileName")
|
||||||
|
.description(
|
||||||
|
"Name of the source file that contains "
|
||||||
|
+ "the execution point identified "
|
||||||
|
+ "by this entry, if any.")
|
||||||
|
.optional().type(JsonFieldType.STRING),
|
||||||
|
fieldWithPath("threads.[].stackTrace.[].lineNumber")
|
||||||
|
.description("Line number of the execution point "
|
||||||
|
+ "identified by this entry. Negative"
|
||||||
|
+ " if unknown."),
|
||||||
|
fieldWithPath("threads.[].stackTrace.[].className")
|
||||||
|
.description(
|
||||||
|
"Name of the class that contains the "
|
||||||
|
+ "execution point identified "
|
||||||
|
+ "by this entry."),
|
||||||
|
fieldWithPath("threads.[].stackTrace.[].nativeMethod")
|
||||||
|
.description(
|
||||||
|
"Whether the execution point is a native "
|
||||||
|
+ "method."),
|
||||||
|
fieldWithPath("threads.[].lockedMonitors").description(
|
||||||
|
"Monitors locked by this thread, if any"),
|
||||||
|
fieldWithPath("threads.[].lockedMonitors.[].className")
|
||||||
|
.description("Class name of the lock object.")
|
||||||
|
.optional().type(JsonFieldType.STRING),
|
||||||
|
fieldWithPath(
|
||||||
|
"threads.[].lockedMonitors.[].identityHashCode")
|
||||||
|
.description(
|
||||||
|
"Identity hash code of the lock "
|
||||||
|
+ "object.")
|
||||||
|
.optional().type(JsonFieldType.NUMBER),
|
||||||
|
fieldWithPath(
|
||||||
|
"threads.[].lockedMonitors.[].lockedStackDepth")
|
||||||
|
.description(
|
||||||
|
"Stack depth where the monitor "
|
||||||
|
+ "was locked.")
|
||||||
|
.optional().type(JsonFieldType.NUMBER),
|
||||||
|
subsectionWithPath(
|
||||||
|
"threads.[].lockedMonitors.[].lockedStackFrame")
|
||||||
|
.description(
|
||||||
|
"Stack frame that locked the "
|
||||||
|
+ "monitor.")
|
||||||
|
.optional().type(JsonFieldType.OBJECT),
|
||||||
|
fieldWithPath("threads.[].lockedSynchronizers")
|
||||||
|
.description(
|
||||||
|
"Synchronizers locked by this thread."),
|
||||||
|
fieldWithPath(
|
||||||
|
"threads.[].lockedSynchronizers.[].className")
|
||||||
|
.description("Class name of the locked "
|
||||||
|
+ "synchronizer.")
|
||||||
|
.optional().type(JsonFieldType.STRING),
|
||||||
|
fieldWithPath(
|
||||||
|
"threads.[].lockedSynchronizers.[].identifyHashCode")
|
||||||
|
.description(
|
||||||
|
"Identity hash code of the locked "
|
||||||
|
+ "synchronizer.")
|
||||||
|
.optional().type(JsonFieldType.NUMBER),
|
||||||
|
fieldWithPath("threads.[].lockInfo").description(
|
||||||
|
"Object for which the thread is blocked "
|
||||||
|
+ "waiting.")
|
||||||
|
.optional(),
|
||||||
|
fieldWithPath("threads.[].lockInfo.className")
|
||||||
|
.description(
|
||||||
|
"Fully qualified class name of the lock"
|
||||||
|
+ " object.")
|
||||||
|
.optional(),
|
||||||
|
fieldWithPath("threads.[].lockInfo.identityHashCode")
|
||||||
|
.description(
|
||||||
|
"Identity hash code of the lock object.")
|
||||||
|
.optional())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(BaseDocumentationConfiguration.class)
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ThreadDumpEndpoint endpoint() {
|
||||||
|
return new ThreadDumpEndpoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
com.example.cache.max-size: 1000
|
|
@ -0,0 +1,31 @@
|
||||||
|
. ____ _ __ _ _
|
||||||
|
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
|
||||||
|
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
|
||||||
|
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
|
||||||
|
' |____| .__|_| |_|_| |_\__, | / / / /
|
||||||
|
=========|_|==============|___/=/_/_/_/
|
||||||
|
:: Spring Boot ::
|
||||||
|
|
||||||
|
2017-08-08 17:12:30.910 INFO 19866 --- [ main] s.f.SampleWebFreeMarkerApplication : Starting SampleWebFreeMarkerApplication on host.local with PID 19866
|
||||||
|
2017-08-08 17:12:30.913 INFO 19866 --- [ main] s.f.SampleWebFreeMarkerApplication : No active profile set, falling back to default profiles: default
|
||||||
|
2017-08-08 17:12:30.952 INFO 19866 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@76b10754: startup date [Tue Aug 08 17:12:30 BST 2017]; root of context hierarchy
|
||||||
|
2017-08-08 17:12:31.878 INFO 19866 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
|
||||||
|
2017-08-08 17:12:31.889 INFO 19866 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||||
|
2017-08-08 17:12:31.890 INFO 19866 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.16
|
||||||
|
2017-08-08 17:12:31.978 INFO 19866 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
||||||
|
2017-08-08 17:12:31.978 INFO 19866 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1028 ms
|
||||||
|
2017-08-08 17:12:32.080 INFO 19866 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
|
||||||
|
2017-08-08 17:12:32.084 INFO 19866 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
|
||||||
|
2017-08-08 17:12:32.084 INFO 19866 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
|
||||||
|
2017-08-08 17:12:32.084 INFO 19866 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
|
||||||
|
2017-08-08 17:12:32.084 INFO 19866 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
|
||||||
|
2017-08-08 17:12:32.349 INFO 19866 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@76b10754: startup date [Tue Aug 08 17:12:30 BST 2017]; root of context hierarchy
|
||||||
|
2017-08-08 17:12:32.420 INFO 19866 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
|
||||||
|
2017-08-08 17:12:32.421 INFO 19866 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
|
||||||
|
2017-08-08 17:12:32.444 INFO 19866 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
|
||||||
|
2017-08-08 17:12:32.444 INFO 19866 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
|
||||||
|
2017-08-08 17:12:32.471 INFO 19866 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
|
||||||
|
2017-08-08 17:12:32.600 INFO 19866 --- [ main] o.s.w.s.v.f.FreeMarkerConfigurer : ClassTemplateLoader for Spring macros added to FreeMarker configuration
|
||||||
|
2017-08-08 17:12:32.681 INFO 19866 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
|
||||||
|
2017-08-08 17:12:32.744 INFO 19866 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http)
|
||||||
|
2017-08-08 17:12:32.750 INFO 19866 --- [ main] s.f.SampleWebFreeMarkerApplication : Started SampleWebFreeMarkerApplication in 2.172 seconds (JVM running for 2.479)
|
|
@ -117,7 +117,7 @@ public class LiquibaseEndpoint {
|
||||||
|
|
||||||
private final String comments;
|
private final String comments;
|
||||||
|
|
||||||
private final ContextExpression contextExpression;
|
private final Set<String> contexts;
|
||||||
|
|
||||||
private final Date dateExecuted;
|
private final Date dateExecuted;
|
||||||
|
|
||||||
|
@ -141,8 +141,7 @@ public class LiquibaseEndpoint {
|
||||||
this.author = ranChangeSet.getAuthor();
|
this.author = ranChangeSet.getAuthor();
|
||||||
this.changeLog = ranChangeSet.getChangeLog();
|
this.changeLog = ranChangeSet.getChangeLog();
|
||||||
this.comments = ranChangeSet.getComments();
|
this.comments = ranChangeSet.getComments();
|
||||||
this.contextExpression = new ContextExpression(
|
this.contexts = ranChangeSet.getContextExpression().getContexts();
|
||||||
ranChangeSet.getContextExpression().getContexts());
|
|
||||||
this.dateExecuted = ranChangeSet.getDateExecuted();
|
this.dateExecuted = ranChangeSet.getDateExecuted();
|
||||||
this.deploymentId = ranChangeSet.getDeploymentId();
|
this.deploymentId = ranChangeSet.getDeploymentId();
|
||||||
this.description = ranChangeSet.getDescription();
|
this.description = ranChangeSet.getDescription();
|
||||||
|
@ -167,8 +166,8 @@ public class LiquibaseEndpoint {
|
||||||
return this.comments;
|
return this.comments;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContextExpression getContextExpression() {
|
public Set<String> getContexts() {
|
||||||
return this.contextExpression;
|
return this.contexts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getDateExecuted() {
|
public Date getDateExecuted() {
|
||||||
|
|
|
@ -151,7 +151,7 @@
|
||||||
<spring-kafka.version>2.1.0.RC1</spring-kafka.version>
|
<spring-kafka.version>2.1.0.RC1</spring-kafka.version>
|
||||||
<spring-ldap.version>2.3.2.RELEASE</spring-ldap.version>
|
<spring-ldap.version>2.3.2.RELEASE</spring-ldap.version>
|
||||||
<spring-plugin.version>1.2.0.RELEASE</spring-plugin.version>
|
<spring-plugin.version>1.2.0.RELEASE</spring-plugin.version>
|
||||||
<spring-restdocs.version>2.0.0.RC1</spring-restdocs.version>
|
<spring-restdocs.version>2.0.0.BUILD-SNAPSHOT</spring-restdocs.version>
|
||||||
<spring-retry.version>1.2.1.RELEASE</spring-retry.version>
|
<spring-retry.version>1.2.1.RELEASE</spring-retry.version>
|
||||||
<spring-security.version>5.0.0.RC1</spring-security.version>
|
<spring-security.version>5.0.0.RC1</spring-security.version>
|
||||||
<spring-session.version>2.0.0.RC1</spring-session.version>
|
<spring-session.version>2.0.0.RC1</spring-session.version>
|
||||||
|
|
|
@ -980,6 +980,15 @@
|
||||||
<outputDirectory>${project.build.directory}/contents/gradle-plugin</outputDirectory>
|
<outputDirectory>${project.build.directory}/contents/gradle-plugin</outputDirectory>
|
||||||
<excludes>META-INF/**</excludes>
|
<excludes>META-INF/**</excludes>
|
||||||
</artifactItem>
|
</artifactItem>
|
||||||
|
<artifactItem>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
<classifier>docs</classifier>
|
||||||
|
<type>zip</type>
|
||||||
|
<outputDirectory>${project.build.directory}/contents/actuator-api</outputDirectory>
|
||||||
|
<excludes>META-INF/**</excludes>
|
||||||
|
</artifactItem>
|
||||||
</artifactItems>
|
</artifactItems>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
|
|
|
@ -35,6 +35,7 @@ Phillip Webb; Dave Syer; Josh Long; Stéphane Nicoll; Rob Winch; Andy Wilkinson;
|
||||||
:dc-spring-boot-test-autoconfigure: {dc-root}/org/springframework/boot/test/autoconfigure
|
:dc-spring-boot-test-autoconfigure: {dc-root}/org/springframework/boot/test/autoconfigure
|
||||||
:dependency-management-plugin: https://github.com/spring-gradle-plugins/dependency-management-plugin
|
:dependency-management-plugin: https://github.com/spring-gradle-plugins/dependency-management-plugin
|
||||||
:dependency-management-plugin-documentation: {dependency-management-plugin}/blob/master/README.md
|
:dependency-management-plugin-documentation: {dependency-management-plugin}/blob/master/README.md
|
||||||
|
:spring-boot-actuator-api: http://docs.spring.io/spring-boot/docs/{spring-boot-docs-version}/actuator-api/
|
||||||
:spring-boot-maven-plugin-site: http://docs.spring.io/spring-boot/docs/{spring-boot-docs-version}/maven-plugin/
|
:spring-boot-maven-plugin-site: http://docs.spring.io/spring-boot/docs/{spring-boot-docs-version}/maven-plugin/
|
||||||
:spring-boot-gradle-plugin: http://docs.spring.io/spring-boot/docs/{spring-boot-docs-version}/gradle-plugin/
|
:spring-boot-gradle-plugin: http://docs.spring.io/spring-boot/docs/{spring-boot-docs-version}/gradle-plugin/
|
||||||
:spring-reference: http://docs.spring.io/spring/docs/{spring-docs-version}/spring-framework-reference/
|
:spring-reference: http://docs.spring.io/spring/docs/{spring-docs-version}/spring-framework-reference/
|
||||||
|
|
|
@ -142,6 +142,12 @@ content.
|
||||||
|
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
To learn more about the Actuator's endpoints and their request and response formats,
|
||||||
|
please refer to the separate API documentation that is available in the following formats:
|
||||||
|
|
||||||
|
* {spring-boot-actuator-api}/html[HTML]
|
||||||
|
* {spring-boot-actuator-api}/pdf/spring-boot-actuator-web-api.pdf[PDF]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[production-ready-endpoints-exposing-endpoints]]
|
[[production-ready-endpoints-exposing-endpoints]]
|
||||||
|
|
|
@ -70,7 +70,7 @@
|
||||||
<module name="com.puppycrawl.tools.checkstyle.checks.imports.AvoidStarImportCheck" />
|
<module name="com.puppycrawl.tools.checkstyle.checks.imports.AvoidStarImportCheck" />
|
||||||
<module name="com.puppycrawl.tools.checkstyle.checks.imports.AvoidStaticImportCheck">
|
<module name="com.puppycrawl.tools.checkstyle.checks.imports.AvoidStaticImportCheck">
|
||||||
<property name="excludes"
|
<property name="excludes"
|
||||||
value="io.restassured.RestAssured.*, org.assertj.core.api.Assertions.*, org.junit.Assert.*, org.junit.Assume.*, org.junit.internal.matchers.ThrowableMessageMatcher.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*, org.springframework.boot.configurationprocessor.TestCompiler.*, org.springframework.boot.test.autoconfigure.AutoConfigurationImportedCondition.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.ArgumentMatchers.*, org.mockito.Matchers.*, org.springframework.restdocs.hypermedia.HypermediaDocumentation.*, org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*, org.springframework.restdocs.operation.preprocess.Preprocessors.*, org.springframework.restdocs.restassured3.operation.preprocess.RestAssuredPreprocessors.*, org.springframework.restdocs.restassured3.RestAssuredRestDocumentation.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*, org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*, org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo, org.springframework.test.web.client.ExpectedCount.*, org.springframework.test.web.client.match.MockRestRequestMatchers.*, org.springframework.test.web.client.response.MockRestResponseCreators.*" />
|
value="io.restassured.RestAssured.*, org.assertj.core.api.Assertions.*, org.junit.Assert.*, org.junit.Assume.*, org.junit.internal.matchers.ThrowableMessageMatcher.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*, org.springframework.boot.configurationprocessor.TestCompiler.*, org.springframework.boot.test.autoconfigure.AutoConfigurationImportedCondition.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.ArgumentMatchers.*, org.mockito.Matchers.*, org.springframework.restdocs.hypermedia.HypermediaDocumentation.*, org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*, org.springframework.restdocs.operation.preprocess.Preprocessors.*, org.springframework.restdocs.payload.PayloadDocumentation.*, org.springframework.restdocs.request.RequestDocumentation.*, org.springframework.restdocs.restassured3.operation.preprocess.RestAssuredPreprocessors.*, org.springframework.restdocs.restassured3.RestAssuredRestDocumentation.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*, org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*, org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo, org.springframework.test.web.client.ExpectedCount.*, org.springframework.test.web.client.match.MockRestRequestMatchers.*, org.springframework.test.web.client.response.MockRestResponseCreators.*" />
|
||||||
</module>
|
</module>
|
||||||
<module name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck" >
|
<module name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck" >
|
||||||
<property name="illegalPkgs" value="com.google.common"/>
|
<property name="illegalPkgs" value="com.google.common"/>
|
||||||
|
|
Loading…
Reference in New Issue