Hot questions for Spring Boot Actuator

Top 10 Java Open Source / Spring / Spring Boot Actuator

Question:

I moved to Spring Boot 2.0.0 RC1 from 1.5.10 and I am stuck with actuator in the latest version. How can I enable expose and enable all actuator endpoints?

The only endpoints that get exposed are:

{
  "_links": {
    "self": {
      "href": "http://127.0.0.1:8080/actuator",
      "templated": false
    },
    "health": {
      "href": "http://127.0.0.1:8080/actuator/health",
      "templated": false
    },
    "info": {
      "href": "http://127.0.0.1:8080/actuator/info",
      "templated": false
    }
  }
}

This is my application.properties files. Any ideas?

#The three first ones seem to be obsolete
endpoints.configprops.enabled=true
endpoints.beans.enabled=true
endpoints.shutdown.enabled=true

management.endpoints.enabled-by-default=true
management.endpoints.sensitive=false
management.endpoints.enabled=true

management.endpoint.configprops.enabled=true
management.endpoint.beans.enabled=true
management.endpoint.shutdown.enabled=true

management.endpoints.web.exposure.include=*

Answer:

With Spring Boot 2.0.0.RC1, actuator endpoints must be 1) enabled and 2) exposed.

By default, all endpoints but shutdown are enabled and only health and info are exposed.

In your case, the following should work:

management.endpoints.web.expose=*
# if you'd like to expose shutdown:
# management.endpoint.shutdown.enabled=true

Note that this changes (again!) as of Spring Boot 2.0.0.RC2:

management.endpoints.web.exposure.include=*
# if you'd like to expose shutdown:
# management.endpoint.shutdown.enabled=true

In doubt, the dedicated migration guide is always up-to-date with the latest changes.

Edit

For easy copy and paste, here's the `yaml´ versions - as of Spring Boot 2.0.0.RC2:

management:
  endpoints:
    web:
      exposure:
        include: "*"

before:

management:
  endpoints:
    web:
      expose: "*"

Question:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

This will add several useful endpoints to your application. One of them is /health. When you start your application and navigate to the /health endpoint you will see it returns already some data.

{
    "status":"UP",
    "diskSpace": {
        "status":"UP",
        "free":56443746,
        "threshold":1345660
    }
}

How to add a custom health check in spring boot health?


Answer:

Adding a custom health check is easy. Just create a new Java class, extend it from the AbstractHealthIndicator and implement the doHealthCheck method. The method gets a builder passed with some useful methods. Call builder.up() if your health is OK or builder.down() if it is not. What you do to check the health is completely up to you. Maybe you want to ping some server or check some files.

@Component
public class CustomHealthCheck extends AbstractHealthIndicator {
    @Override
    protected void doHealthCheck(Health.Builder bldr) throws Exception {
        // TODO implement some check
        boolean running = true;
        if (running) {
          bldr.up();
        } else {
          bldr.down();
        }
    }
}

This is enough to activate the new health check (make sure @ComponentScan is on your application). Restart your application and locate your browser to the /health endpoint and you will see the newly added health check.

{
    "status":"UP",
    "CustomHealthCheck": {
        "status":"UP"
    },
    "diskSpace": {
        "status":"UP",
        "free":56443746,
        "threshold":1345660
    }
}

Question:

I have updated a Spring Boot application from 1.4.x to 1.5.1 and the Spring Actuator endpoints return a different MIME type now:

For example, /health is now application/vnd.spring-boot.actuator.v1+json instead simply application/json.

How can I change this back?


Answer:

The endpoints return a content type that honours what the client's request says it can accept. You will get an application/json response if the client send an Accept header that asks for it:

Accept: application/json

Question:

Is there an easy way to add a prefix to all the Actuator endpoints?

/env ->     /secure/env
/health ->  /secure/health
/info ->    /secure/info
...

Answer:

Jesper's answer is completely right, but I was looking for a more straightforward way of prefixing all endpoints, and it can be done with management.context-path, e.g.:

management:
  context-path: /secure

-> /secure/env
-> /secure/health
...

Question:

I started my first project on Spring Boot 2 (RC1). Thanks to the already good documentation this has not been to hard coming from Spring Boot 1.x.

However now that I want to integrate metrics I'm stumbeling. As far as I was able to find currently there is only documentation for the metrics shipped by default. But I'd like to also measure service level execution time as well as the time used in dynamodb.

EDIT I'm looking for a solution using Micrometer, the library used in the new actuator library shipped with spring-boot 2.

Is there any guide on how this should be done? From this I read that there is no easy annotation based solution for arbitrary spring beans yet. Could s.o. give me an example / link to documentation on how a method like below could be metered?

@Service
@Timed
public class MyService {
    public void doSomething() {
        ...;
    }
}

Answer:

@io.micrometer.core.annotation.Timed annotation seems to be out of order for custom calls due to reduction of scope, at it is mentioned in link in your question.

You need to manually setup an Aspect:

@Configuration
@EnableAspectJAutoProxy
public class AutoTimingConfiguration {
    @Bean
    public TimedAspect timedAspect(MeterRegistry registry) {
        return new TimedAspect(registry);
        }
}

This way method like this:

@Timed("GET_CARS")
public List<Car> getCars(){
        return Lists.newArrayList();
}

will result in GET_CARS metric in /actuator/metrics (default) endpoint.

Question:

Spring Boot Actuator's Trace does a good job of capturing input/output HTTP params, headers, users, etc. I'd like to expand it to also capture the body of the HTTP response, that way I can have a full view of what is coming in and going out of the the web layer. Looking at the TraceProperties, doesn't look like there is a way to configure response body capturing. Is there a "safe" way to capture the response body without messing up whatever character stream it is sending back?


Answer:

Recently, I wrote a blog post about customization of Spring Boot Actuator's trace endpoint and while playing with Actuator, I was kinda surprised that response body isn't one of the supported properties to trace.

I thought I may need this feature and came up with a quick solution thanks to Logback's TeeFilter.

To duplicate output stream of the response, I copied and used TeeHttpServletResponse and TeeServletOutputStream without too much examination.

Then, just like I explained in the blog post, extended WebRequestTraceFilter like:

@Component
public class RequestTraceFilter extends WebRequestTraceFilter {

    RequestTraceFilter(TraceRepository repository, TraceProperties properties) {
        super(repository, properties);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        TeeHttpServletResponse teeResponse = new TeeHttpServletResponse(response);

        filterChain.doFilter(request, teeResponse);

        teeResponse.finish();

        request.setAttribute("responseBody", teeResponse.getOutputBuffer());

        super.doFilterInternal(request, teeResponse, filterChain);
    }

    @Override
    protected Map<String, Object> getTrace(HttpServletRequest request) {
        Map<String, Object> trace = super.getTrace(request);

        byte[] outputBuffer = (byte[]) request.getAttribute("responseBody");

        if (outputBuffer != null) {
            trace.put("responseBody", new String(outputBuffer));
        }

        return trace;
    }
}

Now, you can see responseBody in the JSON trace endpoint serves.

Question:

I am writing a Spring Boot App

My requirements are - In the resources (src/main/resources) folder if I add new xml files.. I should read those files and get some url and other specific settings from each of it. and for those urls I need to download data everyday .. So a new scheduler job will start with url and some settings

The new jobs will run in different schedule time which will use cron expression present in the xml files Also files will be added dynamically at any point of time How to implenet it .


Answer:

If you want to dynamically schedule tasks you can do it without spring by using ExecutorService in particular ScheduledThreadPoolExecutor

Runnable task  = () -> doSomething();
ScheduledExecutorService executor = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
// Schedule a task that will be executed in 120 sec
executor.schedule(task, 120, TimeUnit.SECONDS);

// Schedule a task that will be first run in 120 sec and each 120sec
// If an exception occurs then it's task executions are canceled.
executor.scheduleAtFixedRate(task, 120, 120, TimeUnit.SECONDS);

// Schedule a task that will be first run in 120 sec and each 120sec after the last execution
// If an exception occurs then it's task executions are canceled.
executor.scheduleWithFixedDelay(task, 120, 120, TimeUnit.SECONDS);

With spring you can rely on the Task and Scheduling API

public class MyBean {

    private final TaskScheduler executor;

    @Autowired
    public MyBean(TaskScheduler taskExecutor) {
        this.executor = taskExecutor;
    }

    public void scheduling(final Runnable task) {
        // Schedule a task to run once at the given date (here in 1minute)
        executor.schedule(task, Date.from(LocalDateTime.now().plusMinutes(1)
            .atZone(ZoneId.systemDefault()).toInstant()));

        // Schedule a task that will run as soon as possible and every 1000ms
        executor.scheduleAtFixedRate(task, 1000);

        // Schedule a task that will first run at the given date and every 1000ms
        executor.scheduleAtFixedRate(task, Date.from(LocalDateTime.now().plusMinutes(1)
            .atZone(ZoneId.systemDefault()).toInstant()), 1000);

        // Schedule a task that will run as soon as possible and every 1000ms after the previous completion
        executor.scheduleWithFixedDelay(task, 1000);

        // Schedule a task that will run as soon as possible and every 1000ms after the previous completion
        executor.scheduleWithFixedDelay(task, Date.from(LocalDateTime.now().plusMinutes(1)
            .atZone(ZoneId.systemDefault()).toInstant()), 1000);

        // Schedule a task with the given cron expression
        executor.schedule(task, new CronTrigger("*/5 * * * * MON-FRI"));
    }
}

And you can provide your own trigger by implementing Trigger

Don't forget to enable the scheduling by usin @EnableScheduling on configuration class.

About listening to directory content you can use WatchService. Something like:

final Path myDir = Paths.get("my/directory/i/want/to/monitor");
final WatchService watchService = FileSystems.getDefault().newWatchService();
// listen to create event in the directory
myDir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
// Infinite loop don't forget to run this in a Thread
for(;;) {
   final WatchKey key = watchService.take();
   for (WatchEvent<?> event : key.pollEvents()) {
       WatchEvent<Path> watchEvent = (WatchEvent<Path>) event;
       Path newFilePath = myDir.resolve(watchEvent.context());
       //do something with the newFilePath
    }
    // To keep receiving event
    key.reset();
}

Take a look at this article: Watching a Directory for Changes for more details.

Question:

I'm using Spring Boot 2 M3 actuators. By default, the health endpoint is mapped to /application/health.

  • Is it possible to change this path to /health?

Answer:

In your application.properties file add this to set the base path to '/'

management.endpoints.web.base-path=/

Path will now be '/health'

Edit: Alternatively if you are using YAML use:

management:
  endpoints:
    web:
      base-path: /

Question:

Question1: In Spring Security, what exactly is the function

@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)

Spring Documentation States the below, but I am not sure I understand it clearly

To override the access rules without changing any other autoconfigured features add a @Bean of type WebSecurityConfigurerAdapter with @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER).

The ordering of various security features in Spring Security are as below as per my understanding (LowestValue i.e. Highest Precedence to Highest Value i.e. Lowest Precedence)

  1. Ordered.HIGHEST_PRECEDENCE = -2^31-1
  2. WebSecurityConfigurerAdapter = 100 (Based on @Order(100) mentioned in Docs)
    1. Access_Override_Order = Basic_Auth_Order -2 for Security Properties
    2. Access_Override_Order = Basic_Auth_Order -1 for ManagementServerProperties Basic_Auth_Order-2 = 2^31-7
  3. Basic_Auth_Order = Ordered.Lowest_Precendence -5 = 2^31-5
  4. Ordered.LOWEST_PRECEDENCE = 2^31

Question2 Based on the ordering of various security features above, If I want to override default rules for both Management Endpoints and the Rest of the application, should I use

  • SecurityPropertiesACCESS_OVERRIDE_ORDER or
  • ManagementServerProperties ACCESS_OVERRIDE_ORDER ?

I am currently using SecurityProperties ACCESS_OVERRIDE_ORDER but based on the suggestion here to get ACTUATOR working I need to enable ManagementServerProperties ACCESS_OVERRIDE_ORDER. Which one should I override if I want both working ?

Thanks.


Answer:

Q1. Question1: In Spring Security, what exactly does the annotation @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) do?

What it does is well explained in the documentation you quoted.

To override the access rules without changing any other autoconfigured features add a @Bean of type WebSecurityConfigurerAdapter with @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER).

But then WebSecurityConfigurerAdapter, which has @Order(100), takes higher priority.

No.

You should be careful about this part autoconfigured features. Using @EnableAutoConfiguration which is a part of @SpringBootApplication, a lot of things are auto-configured and 100 is not a auto-configured value but a hard-coded value on the WebSecurityConfigurerAdapter class.

You can find order values used for auto-configuring for Spring Security in SecurityProperties class and you can find out that the value of ACCESS_OVERRIDE_ORDER is the lowest which means it takes the highest priority.

Where are they auto-confitured?

You can find that @Order(SecurityProperties.BASIC_AUTH_ORDER) is used in SpringBootWebSecurityConfiguration class.

Then when is the annotation @Order(100) of WebSecurityConfigurerAdapter used?

For example, if you disable the auto-configuring by adding @EnableWebSecurity, the value would be used. As the value 100 takes too high priority, it'd be better to put @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) annotation in your custom class in the case.

Q2. Based on the ordering of various security features above, If I want to override default rules for both Management Endpoints and the Rest of the application, what should I use

Use ManagementServerProperties ACCESS_OVERRIDE_ORDER.

It takes higher priority so you must use it if you want to override default rules for all end points. You can see how the values are set if you open the ManagementServerProperties class.

In SecurityProperties

int ACCESS_OVERRIDE_ORDER = SecurityProperties.BASIC_AUTH_ORDER - 2; // 39
int BASIC_AUTH_ORDER = Ordered.LOWEST_PRECEDENCE - 5; // 41

In ManagementServerProperties

int BASIC_AUTH_ORDER = SecurityProperties.BASIC_AUTH_ORDER - 5; // 36
int ACCESS_OVERRIDE_ORDER = ManagementServerProperties.BASIC_AUTH_ORDER - 1; // 35

In the comment, 39 means 21474839, I've omitted the first 6 digits for readability.