Skip to content

Actuator is not working with Jersey starter #2025

Closed
@ouaibsky

Description

@ouaibsky

Hi

I just cloned the starter-jersey sample then tried to add dependency spring-boot-starter-actuator.
Looks like any context mapped by actuator are working
The trouble is stdout looks fine, saying all endpoints are added, but when doing /health or /metrics .... nothing appears in a browser.
In fact it's a 404 error (displayed woth curl -i)
Looks like error page are not working as well.

I guess all this is due to Jersey but not able to do more troubleshooting.

Tested on 1.2.0-BUILD-SNAPSHOT

Christophe

Activity

philwebb

philwebb commented on Dec 1, 2014

@philwebb
Member

The actuator HTTP endpoints are exposed via Spring MVC and we currently don't provide equivalents for Jersey. I'm not sure if you can easily mix Jersey and Spring MVC (@dsyer might know).

celkins

celkins commented on Dec 1, 2014

@celkins

It can be done, but IME you do have to provide your own FilterRegistrationBean and tweak actuator endpoint paths. For example, with Jersey 1 (and Spring Boot 1.1):

@Bean
public FilterRegistrationBean jersey() {
    final FilterRegistrationBean jersey = new FilterRegistrationBean();
    jersey.setFilter(new ServletContainer(this.config));
    jersey.setMatchAfter(true);
    jersey.addInitParameter("com.sun.jersey.config.feature.FilterForwardOn404", "true");

    final String managementContextPath = stripTrailingSlash(this.management.getContextPath());
    if (managementContextPath.isEmpty()) {
        throw new IllegalStateException("Management context path must be non-empty");
    } else {
        final String managementContextRegex = managementContextPath + "/.+";
        jersey.addInitParameter("com.sun.jersey.config.property.WebPageContentRegex", managementContextRegex);
    }

    return jersey;
}

Jersey 2 would be trivially similar, with slightly different init parameter names. Getting it working with spring-boot-starter-jersey might be more problematic.

ouaibsky

ouaibsky commented on Dec 1, 2014

@ouaibsky
Author

@philwebb: if other starters cannot be used on top of spring-boot-starter-jersey, it doesn't make sense to provide support to another REST fwk
@celkins: Thx for jersey 1 clue. I'm gonna continue my investigation with Jersey 2 & starter-jersey but unfortunately, after playing a few day I'm wondering if philwebb is not right and probably give up jersey ... or find other alternatives.

Thx
Christophe

dsyer

dsyer commented on Dec 1, 2014

@dsyer
Member

I don't understand what the problem is really. Jersey (1 or 2) can be installed as either a servlet or a filter, and if you map those to the same path as the Actuator endpoints, of course it's not going to work. You don't need a custom registration for Jersey 2 for vanilla use cases either (filter and servlet and custom paths are supported out of the box, and Jersey has a ton of options that are supported through spring.jersey.*). Or am I missing something?

celkins

celkins commented on Dec 1, 2014

@celkins

@ouaibsky: One option is to set the server.servletPath property to move the default DispatcherServlet out of the way. Alternatively, if you are willing and able to re-route your Jersey resources, you can add @ApplicationPath to your ResourceConfig class to move them out of the way.

@dsyer: I think it's a matter of the perhaps unrealistic expectation that one can add a dependency on spring-boot-starter-actuator to a spring-boot-starter-jersey-based application and have everything just work.

ouaibsky

ouaibsky commented on Dec 3, 2014

@ouaibsky
Author

@dsyer, I'm exactly in the situation describe by @celkins below. Just putting spring-boot-starter-actuator to a spring-boot-starter-jersey and expecting it should work out of the box

But I understand now it's a bit more tricky (and has been designed first to work with Spring MVC)
I'm not an expert of Filter nor DispatchingServlet, Likely I need to read documentation more in details about Jesey configuration and Spring MVC.

@celkins Meaning if I move out DispatcherServlet, request will be automatically handle by jerseyServlet ?

For information the output when I start the example and doing some REST requests (in facto no more output if a request works or not)

[INFO] Attaching agents: []

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::  (v1.2.0.BUILD-SNAPSHOT)

2014-12-03 22:10:33.284  INFO 4190 --- [           main] org.icroco.haura.kra.KraMain             : Starting KraMain on legolas with PID 4190 (/home/christophe/git/haura/haura-kra/target/classes started by christophe in /home/christophe/git/haura/haura-kra)
2014-12-03 22:10:33.352  INFO 4190 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@64485a47: startup date [Wed Dec 03 22:10:33 CET 2014]; root of context hierarchy
2014-12-03 22:10:34.351  INFO 4190 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanNameViewResolver': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]
2014-12-03 22:10:35.125  INFO 4190 --- [           main] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2014-12-03 22:10:36.019  INFO 4190 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080/http
2014-12-03 22:10:36.454  INFO 4190 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2014-12-03 22:10:36.456  INFO 4190 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.0.15
2014-12-03 22:10:36.594  INFO 4190 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2014-12-03 22:10:36.594  INFO 4190 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3247 ms
2014-12-03 22:10:37.755  INFO 4190 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'metricFilter' to: [/*]
2014-12-03 22:10:37.756  INFO 4190 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'requestContextFilter' to: [/*]
2014-12-03 22:10:37.756  INFO 4190 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'webRequestLoggingFilter' to: [/*]
2014-12-03 22:10:37.756  INFO 4190 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2014-12-03 22:10:37.757  INFO 4190 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'applicationContextIdFilter' to: [/*]
2014-12-03 22:10:37.757  INFO 4190 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'characterEncodingFilter' to: [/*]
2014-12-03 22:10:37.757  INFO 4190 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'jerseyServlet' to [/*]
2014-12-03 22:10:37.760  INFO 4190 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2014-12-03 22:10:38.105  INFO 4190 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@64485a47: startup date [Wed Dec 03 22:10:33 CET 2014]; root of context hierarchy
2014-12-03 22:10:38.184  INFO 4190 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[text/html],custom=[]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
2014-12-03 22:10:38.184  INFO 4190 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2014-12-03 22:10:38.215  INFO 4190 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-12-03 22:10:38.215  INFO 4190 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-12-03 22:10:38.289  INFO 4190 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-12-03 22:10:38.773  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/dump],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.775  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/autoconfig],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.778  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/env/{name:.*}],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint.value(java.lang.String)
2014-12-03 22:10:38.778  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/env],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.779  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/mappings],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.781  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/shutdown],methods=[POST],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.ShutdownMvcEndpoint.invoke()
2014-12-03 22:10:38.782  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/health],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(java.security.Principal)
2014-12-03 22:10:38.782  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/metrics/{name:.*}],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String)
2014-12-03 22:10:38.783  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/metrics],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.784  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/configprops],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.785  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/info],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.795  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/beans],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.796  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/trace],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.822  INFO 4190 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2014-12-03 22:10:38.850  INFO 4190 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 0
2014-12-03 22:10:39.147  INFO 4190 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080/http
2014-12-03 22:10:39.149  INFO 4190 --- [           main] org.icroco.haura.kra.KraMain             : Started KraMain in 6.252 seconds (JVM running for 6.759)
celkins

celkins commented on Dec 3, 2014

@celkins

@ouaibsky These lines indicate the crux of your problem:

2014-12-03 22:10:37.757  INFO 4190 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'jerseyServlet' to [/*]
2014-12-03 22:10:37.760  INFO 4190 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]

jerseyServlet effectively shadows everything under the root, so dispatcherServlet never sees any requests that it would otherwise forward to the actuator endpoints.

Compare that to what happens when you override server.servletPath to, for example, /spring:

2014-12-03 15:49:26.904  INFO 91671 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'jerseyServlet' to [/*]
2014-12-03 15:49:26.907  INFO 91671 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/spring/*]

With such a configuration, the actuator endpoints (as well as everything else handled by dispatcherServlet) are exposed as /spring/health, /spring/metrics, etc. For example,

$ curl -i http://localhost:8080/spring/health
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 03 Dec 2014 23:52:39 GMT

{"status":"UP","diskSpace":{"status":"UP","free":181905625088,"threshold":10485760}}
ouaibsky

ouaibsky commented on Dec 7, 2014

@ouaibsky
Author

Thx @celkins

I confirm it works by adding a property server.servletPath.
Don know if it will be a "fragile" solution regarding future enhancement of spring-boot but it works
Thx

wujek-srujek

wujek-srujek commented on Jul 15, 2015

@wujek-srujek

I was also caught by this one, i.e. expecting the actuator to work with boot-starter-jersey. This was after we already committed to Jersey, so going back to webmvc is not an option. So now, it seems we have to depend on both webmvc (for example, via boot-starter-web) and jersey 2 (via boot-starter-jersey), i.e. have two REST libraries, which imho is not nice.
Anyways, I was able to configure it both ways:

  • add @ApplicationPath("api") on the ResourceConfig @component - in this case, all my custom resources are accessed with /api/hello etc.

  • remap the dispatcherServlet to /spring with server.servlet-path - the only thing I find strange is that while log says the dispatcher has been remapped, the endpoints are still reported under their original urls, for example:

    2015-07-15 23:15:24.292 INFO 2272 --- [ main] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/spring/]
    2015-07-15 23:15:26.218 INFO 2272 --- [ 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.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
    2015-07-15 23:15:26.219 INFO 2272 --- [ 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.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
    2015-07-15 23:15:26.249 INFO 2272 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
    2015-07-15 23:15:26.249 INFO 2272 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/
    ] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
    2015-07-15 23:15:26.290 INFO 2272 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/
    */favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
    2015-07-15 23:15:26.661 INFO 2272 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/configprops],methods=[GET]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()

Above, the /configprops URL is still reported although the one to use is /spring/configprops. Also, I don't really know if the /webjars/** is now /spring/webjars/**, the same for /error etc.

What makes things very, very confusing is that it is not documented anywhere that the actuator depends on webmvc; what is more, the spring-boot-actuator/pom.xml says the dependency on webmvc is optional (

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<optional>true</optional>
</dependency>
), i.e. webmvc is not really necessary for the actuator to work.

snicoll

snicoll commented on Jul 16, 2015

@snicoll
Member

I think the misunderstanding comes from the fact that the "web" exposure is just one feature of the actuator. You can access to the same features via JMX endpoints for instance. That's why it's optional

that it is not documented anywhere that the actuator depends on webmvc;

Granted it's not super obvious but this page on "Monitoring and management over HTTP" starts with:

If you are developing a Spring MVC application, Spring Boot Actuator will ....

I'll add an explicit tip in that section.

added a commit that references this issue on Jul 16, 2015
wujek-srujek

wujek-srujek commented on Jul 16, 2015

@wujek-srujek

Now I understand why it's marked optional, I didn't know about the other options (JMX, shell), now I read the full docs and know better.

As for the note you added - do you think it would be worth adding how both MVC and Jersey can be used together? It seems, even in this very issue, even the Boot core devs weren't sure if and how to make it work.

snicoll

snicoll commented on Jul 17, 2015

@snicoll
Member

I think we didn't try to make it work, indeed. You can always create a separate issue to ask for a sample. PR more than welcome.

21 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @dsyer@jokerr@celkins@snicoll@philwebb

        Issue actions

          Actuator is not working with Jersey starter · Issue #2025 · spring-projects/spring-boot