Skip to content

Commit

Permalink
Document Customizing options
Browse files Browse the repository at this point in the history
  • Loading branch information
joshiste committed Jul 23, 2018
1 parent aac3f00 commit 1ebc75e
Show file tree
Hide file tree
Showing 28 changed files with 205 additions and 57 deletions.
1 change: 1 addition & 0 deletions spring-boot-admin-docs/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
<spring-cloud-version>${spring-cloud.version}</spring-cloud-version>
<samples-dir>${basedir}/../spring-boot-admin-samples/</samples-dir>
<main-dir>${basedir}/../</main-dir>
<github-src>https://github.com/codecentric/spring-boot-admin/tree/master</github-src>
</attributes>
</configuration>
</execution>
Expand Down
86 changes: 86 additions & 0 deletions spring-boot-admin-docs/src/main/asciidoc/customizing.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
[[customizing]]
== Customizing ==

[[customizing-notifiers]]
=== Custom Notifiers ===

You can add your own Notifiers by adding Spring Beans which implement the `Notifier` interface, at best by extending
`AbstractEventNotifier` or `AbstractStatusChangeNotifier`

[source,java,indent=0]
----
include::{samples-dir}/spring-boot-admin-sample-servlet/src/main/java/de/codecentric/boot/admin/CustomNotifier.java[tags=customization-notifiers]
----

[[customizing-headers]]
=== Injecting Custom HTTP Headers ===

In case you need to inject custom HTTP headers into the requests made to the monitored application's actuator endpoints you can easily add a `HttpHeadersProvider`:

[source,java,indent=0]
----
include::{samples-dir}/spring-boot-admin-sample-servlet/src/main/java/de/codecentric/boot/admin/SpringBootAdminApplication.java[tags=customization-http-headers-providers]
----

[[customizing-instance-filter]]
=== Intercepting Requests And Responses ===

You can intercept and modify requests and responses made to the monitored application's actuator endpoints by implementing the `InstanceExchangeFilterFunction` interface.
This can be useful for auditing or adding some extra security checks.

[source,java,indent=0]
----
include::{samples-dir}/spring-boot-admin-sample-servlet/src/main/java/de/codecentric/boot/admin/SpringBootAdminApplication.java[tags=customization-instance-exchange-filter-function]
----

[[customizing-custom-views]]
=== Custom Views ===

It is possible to add custom views to the ui. The views must be implemented as https://vuejs.org/[Vue.js] components.

The Javascript-Bundle and Css-Stlysheet must be placed on the classpath at `/META-INF/spring-boot-admin-server-ui/extensions/{name}/` so the server can pick them up.
The {github-src}/spring-boot-admin-samples/spring-boot-admin-sample-custom-ui/[spring-boot-admin-sample-custom-ui] module contains a sample which has the necessary maven setup to build such a module.

The custom extension registers itself by calling `SBA.use()` and need to expose a `install()` function, which is called by the ui when setting up the routes.
The `install()` function receives a parameter object referencing the {github-src}/spring-boot-admin-server-ui/src/main/frontend/viewRegistry.js[viewRegistry] and the {github-src}/spring-boot-admin-server-ui/src/main/frontend/store.js[applicationStore] in order to register views and/or callbacks.

[[customizing-custom-views-top-level]]
==== Adding a Top-Level View ====

Here is a simple top level view just listing all registered applications:
[source,html]
----
include::{samples-dir}/spring-boot-admin-sample-custom-ui/src/custom.vue[lines=17..-1]
----
<1> If you define a `applications` prop the component will receive all registered applications.

TIP: There are some helpful methods on the application and instances object available. Have a look at {github-src}/spring-boot-admin-server-ui/src/main/frontend/services/application.js[application.js] and {github-src}/spring-boot-admin-server-ui/src/main/frontend/services/instance.js[instance.js]

And this is how you register the top-level view.
[source,javascript]
----
include::{samples-dir}/spring-boot-admin-sample-custom-ui/src/index.js[tags=customization-ui-toplevel]
----
<1> Name of the view and the route to the view
<2> Path where the view will be accessible
<3> The imported custom component, which will be rendered on the route.
<4> The label for the custom view to be shown in the top navigation bar.
<5> Order for the view. Views in the top navigation bar are sorted by ascending order.

[[customizing-custom-views-instance]]
==== Visualizing a Custom Endpoint ====
Here is a view to show a custom endpoint:
[source,html]
----
include::{samples-dir}/spring-boot-admin-sample-custom-ui/src/custom-endpoint.vue[lines=17..-1]
----
<1> If you define a `instance` prop the component will receive the instance the view should be rendered for.
<2> Each instance has a preconfigured https://github.com/axios/axios[axios] instance to access the endpoints with the correct path and headers.

Registering the instance view works like for the top-level view with some additional properties:
[source,javascript]
----
include::{samples-dir}/spring-boot-admin-sample-custom-ui/src/index.js[tags=customization-ui-endpoint]
----
<1> The parent must be 'instances' in order to render the new custom view for a single instance.
<2> If you add a `isEnabled` callback you can figure out dynamically if the view should be show for the particular instance.
22 changes: 11 additions & 11 deletions spring-boot-admin-docs/src/main/asciidoc/getting-started.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ public class SpringBootAdminApplication {
}
----

NOTE: If you want to setup the Spring Boot Admin Server via war-deployment in a servlet-container, please have a look at the https://github.com/codecentric/spring-boot-admin/blob/master/spring-boot-admin-samples/spring-boot-admin-sample-war/[spring-boot-admin-sample-war].
NOTE: If you want to setup the Spring Boot Admin Server via war-deployment in a servlet-container, please have a look at the {github-src}/spring-boot-admin-samples/spring-boot-admin-sample-war/[spring-boot-admin-sample-war].

See also the https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-samples/spring-boot-admin-sample-servlet/[spring-boot-admin-sample-servlet] project, which also adds security.
See also the {github-src}/spring-boot-admin-samples/spring-boot-admin-sample-servlet/[spring-boot-admin-sample-servlet] project, which also adds security.

[[register-client-applications]]
=== Registering client applications ===
Expand Down Expand Up @@ -81,14 +81,14 @@ management.endpoints.web.exposure.include: "*" #<2>
+
[source,java]
----
@Configuration
public static class SecurityPermitAllConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll() //<1>
.and().csrf().disable();
}
@Configuration
public static class SecurityPermitAllConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll() //<1>
.and().csrf().disable();
}
}
----
<1> For the sake of brevity we're disabling the security for now. Have a look at the <<securing-spring-boot-admin,security section>> on how to deal with secured endpoints.

Expand All @@ -98,7 +98,7 @@ management.endpoints.web.exposure.include: "*" #<2>

If you already use Spring Cloud Discovery for your applications you don't need the SBA Client. Just add a DiscoveryClient to Spring Boot Admin Server, the rest is done by our AutoConfiguration.

The following steps uses Eureka, but other Spring Cloud Discovery implementations are supported as well. There are examples using https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-samples/spring-boot-admin-sample-consul/[Consul] and https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-samples/spring-boot-admin-sample-zookeeper/[Zookeeper].
The following steps uses Eureka, but other Spring Cloud Discovery implementations are supported as well. There are examples using {github-src}/spring-boot-admin-samples/spring-boot-admin-sample-consul/[Consul] and https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-samples/spring-boot-admin-sample-zookeeper/[Zookeeper].

Also have a look at the http://projects.spring.io/spring-cloud/spring-cloud.html[Spring Cloud documentation].

Expand Down Expand Up @@ -146,6 +146,6 @@ include::{samples-dir}/spring-boot-admin-sample-eureka/src/main/resources/applic
<1> Configuration section for the Eureka client
<2> As with Spring Boot 2 most of the endpoints aren't exposed via http by default, we expose all of them. For production you should carefully choose which endpoints to expose.

See also https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-samples/spring-boot-admin-sample-eureka/[spring-boot-admin-sample-eureka].
See also {github-src}/spring-boot-admin-samples/spring-boot-admin-sample-eureka/[spring-boot-admin-sample-eureka].

TIP: You can include the Spring Boot Admin Server to your Eureka server. Setup everything as described above and set `spring.boot.admin.context-path` to something different than `"/"` so that the Spring Boot Admin Server UI won't clash with Eureka's one.
2 changes: 2 additions & 0 deletions spring-boot-admin-docs/src/main/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ include::server.adoc[]

include::security.adoc[]

include::customizing.adoc[]

include::changes-2.x.adoc[]

include::faqs.adoc[]
4 changes: 2 additions & 2 deletions spring-boot-admin-docs/src/main/asciidoc/security.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Since there are several approaches on solving authentication and authorization i
By default `spring-boot-admin-server-ui` provides a login page and a logout button.

A Spring Security configuration could look like this:
[source,java]
[source,java,indent=0]
----
include::{samples-dir}/spring-boot-admin-sample-servlet/src/main/java/de/codecentric/boot/admin/SpringBootAdminApplication.java[tags=configuration-spring-security]
----
Expand All @@ -19,7 +19,7 @@ include::{samples-dir}/spring-boot-admin-sample-servlet/src/main/java/de/codecen
<6> Disables CRSF-Protection the endpoint the Spring Boot Admin Client uses to register.
<7> Disables CRSF-Protection for the actuator endpoints.

For a complete sample look at https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-samples/spring-boot-admin-sample-servlet/[spring-boot-admin-sample-servlet.
For a complete sample look at {github-src}/spring-boot-admin-samples/spring-boot-admin-sample-servlet/[spring-boot-admin-sample-servlet].

NOTE: If you protect the `/instances` endpoint don't forget to configure the username and password on your SBA-Client using `spring.boot.admin.client.username` and `spring.boot.admin.client.password`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ include::{samples-dir}/spring-boot-admin-sample-hazelcast/pom.xml[tags=dependenc

. Instantiate a HazelcastConfig:
+
[source,java]
[source,java,indent=0]
----
include::{samples-dir}/spring-boot-admin-sample-hazelcast/src/main/java/de/codecentric/boot/admin/SpringBootAdminApplication.java[tags=application-hazelcast]
----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ If you add a `FilteringNotifier` to your `ApplicationContext` a RESTful interfac
This notifier is useful if you don't want recieve notifications when deploying your applications. Before stopping the application you can add an (expiring) filter either via a `POST` request.

.How to configure filtering
[source,java]
[source,java,indent=0]
----
include::{samples-dir}/spring-boot-admin-sample-servlet/src/main/java/de/codecentric/boot/admin/SpringBootAdminApplication.java[tags=configuration-filtering-notifier]
----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<script>
export default {
props: {
instance: {
instance: { //<1>
type: Object,
required: true
}
Expand All @@ -33,7 +33,7 @@ export default {
text: ''
}),
async created() {
const response = await this.instance.axios.get('actuator/custom');
const response = await this.instance.axios.get('actuator/custom'); //<2>
this.text = response.data;
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<script>
export default {
props: {
applications: {
applications: { //<1>
type: Array,
required: true
}
Expand All @@ -31,6 +31,3 @@ export default {
}
};
</script>

<style>
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,36 @@
* limitations under the License.
*/

/* global SBA */
import custom from './custom';
import customEndpoint from './custom-endpoint';

/* global SBA */
SBA.extensions.push({
// tag::customization-ui-toplevel[]
SBA.use({
install({viewRegistry}) {
viewRegistry.addView({
name: 'custom',
path: '/custom',
component: custom,
props: true,
label: 'Custom',
order: 1000,
name: 'custom', //<1>
path: '/custom', //<2>
component: custom, //<3>
label: 'Custom', //<4>
order: 1000, //<5>
});
}
});
// end::customization-ui-toplevel[]

// tag::customization-ui-endpoint[]
SBA.use({
install({viewRegistry}) {
viewRegistry.addView({
name: 'instances/custom',
parent: 'instances',
parent: 'instances', // <1>
path: 'custom',
component: customEndpoint,
props: true,
label: 'Custom',
order: 1000,
isEnabled: ({instance}) => instance.hasEndpoint('custom')
isEnabled: ({instance}) => instance.hasEndpoint('custom') // <2>
});
}
});
// end::customization-ui-endpoint[]
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,19 @@
import com.hazelcast.config.InMemoryFormat;
import com.hazelcast.config.MapConfig;

// tag::application-hazelcast[]
@Configuration
@EnableAutoConfiguration
@EnableAdminServer
public class SpringBootAdminApplication {
// tag::application-hazelcast[]
@Bean
public Config hazelcastConfig() {
MapConfig mapConfig = new MapConfig("spring-boot-admin-event-store").setInMemoryFormat(InMemoryFormat.OBJECT)
.setBackupCount(1)
.setEvictionPolicy(EvictionPolicy.NONE);
return new Config().setProperty("hazelcast.jmx", "true").addMapConfig(mapConfig);
}
// end::application-hazelcast[]

@Profile("insecure")
@Configuration
Expand Down Expand Up @@ -97,4 +98,3 @@ public static void main(String[] args) {
}

}
// end::application-hazelcast[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2014-2018 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 de.codecentric.boot.admin;

import de.codecentric.boot.admin.server.domain.entities.Instance;
import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent;
import de.codecentric.boot.admin.server.notify.AbstractEventNotifier;
import de.codecentric.boot.admin.server.notify.LoggingNotifier;
import reactor.core.publisher.Mono;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

// tag::customization-notifiers[]
public class CustomNotifier extends AbstractEventNotifier {
private static final Logger LOGGER = LoggerFactory.getLogger(LoggingNotifier.class);

public CustomNotifier(InstanceRepository repository) {
super(repository);
}

@Override
protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
return Mono.fromRunnable(() -> {
if (event instanceof InstanceStatusChangedEvent) {
LOGGER.info("Instance {} ({}) is {}", instance.getRegistration().getName(), event.getInstance(),
((InstanceStatusChangedEvent) event).getStatusInfo().getStatus());
} else {
LOGGER.info("Instance {} ({}) {}", instance.getRegistration().getName(), event.getInstance(),
event.getType());
}
});
}
}
// end::customization-notifiers[]
Loading

0 comments on commit 1ebc75e

Please sign in to comment.