Spring Boot Actuator without Spring Boot
Asked Answered
G

8

87

I've been working on a Spring/Spring MVC application and I'm looking to add performance metrics. I've come across Spring Boot Actuator and it looks like a great solution. However my application is not a Spring Boot application. My application is running in a traditional container Tomcat 8.

I added the following dependencies

// Spring Actuator
compile "org.springframework.boot:spring-boot-starter-actuator:1.2.3.RELEASE"

I created the following config class.

@EnableConfigurationProperties
@Configuration
@EnableAutoConfiguration
@Profile(value = {"dev", "test"})
@Import(EndpointAutoConfiguration.class)
public class SpringActuatorConfig {

}

I even went as far as adding @EnableConfigurationProperties on every configuration class as suggested on another post on StackOverflow. However that didn't do anything. The endpoints are still not being created and return 404s.

Gomuti answered 29/4, 2015 at 19:47 Comment(5)
you probably know this already, but you can also use spring boot for an application bundled as a war; boot doesn't require you to use embedded tomcatCombinative
I'm actually not all that familiar with Spring Boot. How does Spring Boot differ from a traditional Spring application? From what I can tell it it simply a starter template with a specific Spring centric approach.Gomuti
It differs in that it removes the need for lots of the configuration as long as you are ok with the default configurations it auto-configures for you.Rompers
Are you able to post your build file?Punctate
Related question: https://mcmap.net/q/243391/-use-spring-boot-actuator-without-a-spring-boot-application-duplicate/466738Album
M
37

You can use actuator without spring boot. Add this to pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-actuator</artifactId>
    <version>1.3.5.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>4.3.5.RELEASE</version>
</dependency>

And then in your config class

@Configuration
@EnableWebMvc
@Import({
        EndpointAutoConfiguration.class , PublicMetricsAutoConfiguration.class , HealthIndicatorAutoConfiguration.class
})
public class MyActuatorConfig {

    @Bean
    @Autowired
    public EndpointHandlerMapping endpointHandlerMapping(Collection<? extends MvcEndpoint> endpoints) {
        return new EndpointHandlerMapping(endpoints);
    }

    @Bean
    @Autowired
    public EndpointMvcAdapter metricsEndPoint(MetricsEndpoint delegate) {
        return new EndpointMvcAdapter(delegate);
    }
}

And then you can see the metrics in your application

http://localhost:8085/metrics

Actutaor end point

Murder answered 11/5, 2017 at 20:18 Comment(5)
What other endpoints are enabled for this version of actuator 1.3.5.RELEASE?Peeress
@Murder When I do this I get the following error: Error creating bean with name 'org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration$InfoPropertiesConfiguration': Unsatisfied dependency expressed through field 'environment'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.core.env.ConfigurableEnvironment' available: expected at least 1 bean which qualifies as autowire candidate. Where do i configure this bean maybe?Fieldfare
Does your application start with out adding above to your pom.xml? I don't seem to recall having this error. ConfigurableEnvironment is not a part of actuator package.Murder
This does not work for me. And @EnableWebMvc is not found in above dependencies.Quean
Hello @vsingh, I have added the config as stated above, but when I make a hit on http://localhost:port/metrics it returns 404. Do we need to add additional properties in application.properties or yml filesTheatricals
P
37

First let's clarify that you cannot use Spring Boot Actuator without using Spring Boot.

I was wrong about not being able to it without Spring Boot. See @stefaan-neyts answer for an example of how to do it.

I created a sample project to show how you could convert a basic SpringMVC application using a minimal amount of Spring Boot auto-configuration.

Original source: http://www.mkyong.com/spring-mvc/gradle-spring-mvc-web-project-example

Converted source: https://github.com/Pytry/minimal-boot-actuator

I could have completely removed the dispatcher-servlet.xml and the web.xml files, but I kept them to show how to perform as minimal a change as possible and to simplify converting more complex projects.

Here is a list of steps I took to convert.

Conversion Process

  • Add a Java Configuration file annotated with @SpringBootApplication
  • Add the Application configuration file as a bean to the traditional xml configuration ( added it just after the context scan).
  • Move view resolvers into Application java configuration.

    Alternatively, add the prefix and suffix to application.properties. You can then inject them with @Value in your application, or delete it entirely and just use the provided spring boot view resolver. I went with the former.

  • Removed Default context listener from the spring context xml.

    This is important! Since spring boot will provide one you will get an "Error listener Start" exception if you do not.

  • Add the spring boot plugin to your build script dependencies (I was using gradle)

  • Add a mainClassName property to the build file, and set to an empty String (indicates not to create an executable).

  • Modify dependencies for spring boot actuator

Punctate answered 19/5, 2015 at 19:40 Comment(6)
very interisitng discussion but in this way you are a porting fro a classical spring mvc application to a spring boot application that use war as packagingCaridadcarie
@ValerioVaudi That is correct. The point is that it is not possible to sue Spring Boot Actuator without Spring Boot.Punctate
ok I'm sorry but i dont see the your first assersion:"First let's clarify that you cannot use Spring Boot Actuator without using Spring Boot"Caridadcarie
@ValerioVaudi I added that after you commented. You made me realize that I hadn't been clear about it in my answer.Punctate
You can use Spring boot actuator in a non spring boot applicationMurder
@Murder I believe you are correct, although I've never done it ... yet. I may just update this or add an example of how to do it in the future. If you already have an example, let's edit the answer and add that in as well.Punctate
M
37

You can use actuator without spring boot. Add this to pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-actuator</artifactId>
    <version>1.3.5.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>4.3.5.RELEASE</version>
</dependency>

And then in your config class

@Configuration
@EnableWebMvc
@Import({
        EndpointAutoConfiguration.class , PublicMetricsAutoConfiguration.class , HealthIndicatorAutoConfiguration.class
})
public class MyActuatorConfig {

    @Bean
    @Autowired
    public EndpointHandlerMapping endpointHandlerMapping(Collection<? extends MvcEndpoint> endpoints) {
        return new EndpointHandlerMapping(endpoints);
    }

    @Bean
    @Autowired
    public EndpointMvcAdapter metricsEndPoint(MetricsEndpoint delegate) {
        return new EndpointMvcAdapter(delegate);
    }
}

And then you can see the metrics in your application

http://localhost:8085/metrics

Actutaor end point

Murder answered 11/5, 2017 at 20:18 Comment(5)
What other endpoints are enabled for this version of actuator 1.3.5.RELEASE?Peeress
@Murder When I do this I get the following error: Error creating bean with name 'org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration$InfoPropertiesConfiguration': Unsatisfied dependency expressed through field 'environment'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.core.env.ConfigurableEnvironment' available: expected at least 1 bean which qualifies as autowire candidate. Where do i configure this bean maybe?Fieldfare
Does your application start with out adding above to your pom.xml? I don't seem to recall having this error. ConfigurableEnvironment is not a part of actuator package.Murder
This does not work for me. And @EnableWebMvc is not found in above dependencies.Quean
Hello @vsingh, I have added the config as stated above, but when I make a hit on http://localhost:port/metrics it returns 404. Do we need to add additional properties in application.properties or yml filesTheatricals
S
18

Allthough it is not a good idea to use Spring Boot features without Spring Boot, it is possible!

For example, this Java configuration makes Spring Boot Actuator Metrics available without using Spring Boot:

import java.util.Collection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.PublicMetricsAutoConfiguration;
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
import org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import({ EndpointAutoConfiguration.class, PublicMetricsAutoConfiguration.class })
public class SpringBootActuatorConfig {

    @Bean
    @Autowired
    public EndpointHandlerMapping endpointHandlerMapping(Collection<? extends MvcEndpoint> endpoints) {
        return new EndpointHandlerMapping(endpoints);
    }

    @Bean
    @Autowired
    public EndpointMvcAdapter metricsEndPoint(MetricsEndpoint delegate) {
        return new EndpointMvcAdapter(delegate);
    }
}

The Maven dependency:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-actuator</artifactId>
    <version>1.3.5.RELEASE</version>
</dependency>
Semivitreous answered 9/6, 2016 at 20:55 Comment(3)
Thanks for this great tipp @Stefaan, the only thing I need also to add to my Maven dependencies was a Bean Validation Provider dependency e.g Hibernate Validator (<groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId>).Liggitt
the @Autowired is not needed and in this case management.context-path=/manage in application.properties does not work you should set prefix in endpointHandlerMapping explicitlyLoesceke
Do you know how can I do it with version 2.7 of spring-boot-actuator? @Stefaan NeytsInaction
P
8

As we already have Spring Boot Actuator 2.x, a recipe to include actuator to an existing Spring MVC project can look like this:

@Configuration
@Import({
        EndpointAutoConfiguration.class,
        HealthIndicatorAutoConfiguration.class,

        InfoEndpointAutoConfiguration.class,
        HealthEndpointAutoConfiguration.class,

        WebEndpointAutoConfiguration.class,
        ServletManagementContextAutoConfiguration.class,
        ManagementContextAutoConfiguration.class,
})
@EnableConfigurationProperties(CorsEndpointProperties.class)
class ActuatorConfiguration {

    @Bean //taken from WebMvcEndpointManagementContextConfiguration.class
    public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
                                                                         ServletEndpointsSupplier servletEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier,
                                                                         EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,
                                                                         WebEndpointProperties webEndpointProperties) {
        List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
        Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
        allEndpoints.addAll(webEndpoints);
        allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
        allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
        EndpointMapping endpointMapping = new EndpointMapping(webEndpointProperties.getBasePath());
        return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
                corsProperties.toCorsConfiguration(),
                new EndpointLinksResolver(allEndpoints, webEndpointProperties.getBasePath()));
    }

    @Bean
    DispatcherServletPath dispatcherServletPath() {
        return () -> "/";
    }

}

I did include

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-actuator-autoconfigure</artifactId>
        <version>2.1.18.RELEASE</version>
    </dependency>

for compatibility with the baseline Spring version I've been using (5.1.19.RELEASE)

Preconceive answered 18/1, 2021 at 23:47 Comment(3)
HealthIndicatorAutoConfiguration cannot be foundKaput
@Kaput if you are using version 2.7 and above use > HealthContributorAutoConfiguration.class instead.Adamite
Newer spring boot versions have some changes in class names and WebMvcEndpointHandlerMapping constructor. Also dependency "org.springframework.boot:spring-boot-actuator-autoconfigure" needs to be added.Jeter
T
7

Though the answer is already accepted, I thought of updating my experience. I did not want to convert my application to spring boot using @SpringBootApplication. Refer to another question where I have mentioned the bare minimum code required.

Tautologism answered 30/10, 2015 at 6:0 Comment(1)
I added additional explanation for this way https://mcmap.net/q/243392/-spring-boot-health-check-on-existing-webappLagniappe
C
1

If your objective is to create an endpoint with metrics for Prometheus a.k.a. OpenMetrics, you can use the Prometheus JVM client which is compatible with Spring framework.

Add dependency:

    <dependency>
      <groupId>io.prometheus</groupId>
      <artifactId>simpleclient_servlet</artifactId>
      <version>0.16.0</version>
    </dependency>

To collect metrics of requests, add as first filter in web-app/WEB-INF/web.xml:

  <filter>
    <filter-name>prometheusFilter</filter-name>
    <filter-class>io.prometheus.client.filter.MetricsFilter</filter-class>
    <init-param>
      <param-name>metric-name</param-name>
      <param-value>webapp_metrics_filter</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>prometheusFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

To expose metrics as HTTP endpoint, add servlet:

  <servlet>
    <servlet-name>prometheus</servlet-name>
    <servlet-class>io.prometheus.client.exporter.MetricsServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>prometheus</servlet-name>
    <url-pattern>/metrics</url-pattern>
  </servlet-mapping>

After that you can see the metrics on the /metrics endpoint.

Colquitt answered 21/11, 2022 at 10:5 Comment(0)
P
1

Time passes, we have Spring 6, SpringBoot 3, JakartaEE as a baseline, but people are still looking to add actuator to legacy spring applications. So a small update: spring + actuator without spring-boot. In fact not much changes (and the changes have already been pointed out).

The dependencies

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>6.0.3</version>
    </dependency>
    <dependency>
       <groupId>jakarta.servlet</groupId>
       <artifactId>jakarta.servlet-api</artifactId>
       <version>6.0.0</version>
       <scope>provided</scope>
    </dependency>
    
    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-actuator-autoconfigure</artifactId>
       <version>3.0.1</version>
    </dependency>

The actuator configuration

@Configuration
@ImportAutoConfiguration({
    EndpointAutoConfiguration.class,
    WebEndpointAutoConfiguration.class,
    ServletManagementContextAutoConfiguration.class,
    ManagementContextAutoConfiguration.class,

    HealthContributorAutoConfiguration.class,

    InfoEndpointAutoConfiguration.class,
    HealthEndpointAutoConfiguration.class,

    HeapDumpWebEndpointAutoConfiguration.class,
    ThreadDumpEndpointAutoConfiguration.class,
    LoggersEndpointAutoConfiguration.class,
    PrometheusMetricsExportAutoConfiguration.class,
})
@EnableConfigurationProperties(CorsEndpointProperties.class)
class ActuatorConfiguration {

    @Bean //taken from WebMvcEndpointManagementContextConfiguration.class
    public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
        ServletEndpointsSupplier servletEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier,
        EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,
        WebEndpointProperties webEndpointProperties) {
        List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
        Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
        allEndpoints.addAll(webEndpoints);
        allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
        allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
        EndpointMapping endpointMapping = new EndpointMapping(webEndpointProperties.getBasePath());
        return new WebMvcEndpointHandlerMapping(endpointMapping,
            webEndpoints,
            endpointMediaTypes,
            corsProperties.toCorsConfiguration(),
            new EndpointLinksResolver(allEndpoints, webEndpointProperties.getBasePath()),
            true);
    }

    @Bean
    DispatcherServletPath dispatcherServletPath() {
        return () -> WebInitializer.APPLICATION_ROOT;
    }

}

The example is easy to run directly from maven jetty plugin (mvn jetty:run-war).

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>11.0.13</version>
            </plugin>

The final result

Preconceive answered 13/1, 2023 at 22:2 Comment(0)
H
-10

you have made the mistake by not introducing the @springboot annotation in your code.When you add @springboot ot will consider as boot program by the compiler automatically and addd the required dependency file for it and your actuator dependency file

Healey answered 10/11, 2017 at 13:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.