Exclude path params from actuator metrics - java

I have a Spring boot application that uses the actuator metrics and I have the following issue:
I have an endpoint like this :
GET /users/{userId}
So every time I call this endpoint I use a different Id to get the specific user as you can think we can have hundreds of thousands. It is working correct, but i noticed that when calling my metrics endpoint :
GET /metrics
I get something like this:
counter.status.200.metrics: 1,
counter.status.200.api.users.4: 2,
counter.status.200.api.users.2: 3,
counter.status.200.api.users.3: 2,
So it makes me think that i will get a counter for every single call with different path params, so my question is how can i have a counter just for the endpoint /users/{anyId} and not for every single combination excluding the parameters?.
--- EDIT ---
I'm using Spring boot + Jersey (I'm not using Spring MVC), the following is my controller code:
#Component
#Path("/users")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class UserResource {
#GET
public Response getUsers() {
return Response.ok("It works !").build();
}
#GET
#Path("/{userId}")
public Response getUserById(#PathParam("userId") String id) {
return Response.ok("It works !").build();
}
}
And the following is the Jersey configuration:
#Component
#ApplicationPath("/api")
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(UserResource.class);
register(PingResource.class);
}
}

It's a known issue with Spring Boot 1.x when using Jersey. There's a workaround described in the issue, alternatively you can disable the metrics filter by adding the following to application.properties:
endpoints.metrics.filter.enabled=false

Related

Can I do a GET with request body in Spring Boot?

I'm using Spring Boot and Spring MVC and I need to make a GET with a request body. Is this possible?
I tried this but it's not working. I get 404.
#RestController
#RequestMapping("/api")
public class HomeController {
#GetMapping("/v1/foo")
public ApiRes postBody(#RequestBody ApiReq apiReq) {
...
}
}
Technically it is possible but it is against the HTTP API Design Guidelines.
Request-Bodys should only be used for POST or PUT.
For further information: https://swagger.io/resources/articles/best-practices-in-api-design/

Spring Boot - How to check specific application URLs for status 200

I have several applications monitored under Spring Boot Admin. Spring Boot Admin is great at telling me if an application is up or down and other various metrics.
I would also like to know that certain URLs exposed by these applications are returning an HTTP status of 200. Specifically, I would like to send a GET request to these URLs once a day. If it receives a non 200 status from any of these, it sends an email stating which URLs are reporting non 200.
Is something that Spring Boot Admin is able to do? I know about custom HealthIndicators but not sure if it can be scheduled or if it's appropriate for this.
Just wanted to see if there is something Spring Boot Admin offers to support doing this before I build my own app to make the GET calls and send the email.
Update
The URLs are exposed as Eureka services and I'm calling services from other services via Spring Cloud OpenFeign.
Update 2
I went ahead and built my own custom application to handle this. Details follow but still interested if Spring offers something out-of-the-box to do this.
application.yml
app:
serviceUrls:
- "http://car-service/cars?category=sedan"
- "http://truck-service/trucks"
cron: "0 0 10 * * *"
Urls are read into:
#Component
#ConfigurationProperties(prefix = "app")
#Getter
#Setter
public class ServiceUrls {
private String[] serviceUrls;
}
Via cron, scheduled to run once a day:
#Component
#RequiredArgsConstructor
#Slf4j
public class ServiceCheckRunner {
private final ServiceHealth serviceHealth;
#Scheduled(cron = "${cron}")
public void runCheck() {
serviceHealth.check();
}
}
This is the code that checks whether URLs return no errors:
#Service
#RequiredArgsConstructor
#Slf4j
public class ServiceHealth {
private final ServiceUrls serviceUrls;
private final RestTemplate rest;
public void check() {
List<String> failedServiceUrls = new ArrayList<>();
for (String serviceUrl : serviceUrls.getServiceUrls()) {
try {
ResponseEntity<String> response = rest.getForEntity(serviceUrl, String.class);
if (!response.getStatusCode().is2xxSuccessful()) {
failedServiceUrls.add(serviceUrl);
}
} catch (Exception e){
failedServiceUrls.add(serviceUrl);
}
}
// code to send an email with failedServiceUrls.
}
}
You can use Spring Boot Admin in order to send email notifications whenever a registered client changes his status from UP to OFFLINE or otherwise.
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>2.4.0</version>
</dependency>
application.properties
spring.mail.host=smtp.example.com
spring.mail.username=smtp_user
spring.mail.password=smtp_password
spring.boot.admin.notify.mail.to=admin#example.com
But, if you really need to check client status once per day, you need to implement a custom solution.

How to configure hot reload in Jhipster?

I am using Jhipster(Angular + Springboot) Application for my existing project.
I managed to create a controller(app.resource) manually apart from the ones already generated by jhiptser(using .jh file) for achieving a file download functionality.
So, when we start the server we usually initiate two servers i.e gradlew and npm start. The second runs on port 9000 which eventually supports hot reload functionality.(front-end development)
So the problem is, I am able to access those endpoints from the server running on standard 8000 port. However, from the port which is a proxy(9000), the method is returning 404.
I tried to clean build the application several times.
NOTE: The #RequestMapping value on the new controller is different then those present already.
Does this have to do something with spring security?
Thanks in advance.
Here is the previous controller:
#RestController
#RequestMapping("/api")
public class FGAppDiagramResource {
#GetMapping(value = "/fg-app-diagram-downloadFile")
public void getImage(String fileName,String folderName, HttpServletResponse
response){
// Some Code
}
}
Here is my New controller:
#RestController
#RequestMapping("/fileDownload")
public class DownloadFileController {
private final Logger log =
LoggerFactory.getLogger(DownloadFileController.class);
public DownloadFileController() {
super();
}
#Autowired
private ApplicationProperties applicationProperties;
#GetMapping(value = "/fg-app-diagram-downloadFile/{fileName}/{folderName}")
public void getImage(#PathVariable String fileName,#PathVariable String folderName, HttpServletResponse response) {
// Some Code
}
}
Your new controller does not use /api so you must add your endpoint URL /fileDownload to proxy configuration of webpack dev server in webpack/webpack.dev.js
proxy: [{
context: [
/* jhipster-needle-add-entity-to-webpack - JHipster will add entity api paths here */
'/api',
'/fileDownload',
You may want to use /api/fileDownload to avoid changing proxy configuration and also because /api is useful for many other aspects like security and also using HTML5 URL routing strategy in Angular to get rid of # in client routes (see https://github.com/jhipster/generator-jhipster/pull/9098).
/api and /management are namespaces to avoid route conflicts, so it is usually wise to use them for your new endpoints.

How do I use "/images" path in Spring boot Rest controller with security?

I have a Spring boot REST service (spring-boot-starter-parent:1.3.2) that exposes some endpoints using RestController defined methods. I am also using Spring security. Everything works fine until I try to define a controller method that is mapped to "/images". When I try to access this api path I get the following error. By debugging I can see that my controller handler is being mapped, but the preauthorize filter is not being called (it is called properly for other mappings). I have set the following properties, but with no change. How do I fix this so that I can use "/images"?
spring.resources.add-mappings=false
spring.mvc.static-path-pattern=/hide-me/**
Error:
"exception": "org.springframework.security.authentication.AuthenticationCredentialsNotFoundException",
"message": "An Authentication object was not found in the SecurityContext",
Code:
#RestController
#PreAuthorize(value = "hasAnyAuthority('SOMEUSER')")
public class ImageController {
...
#RequestMapping(value = { "/images/{imageId}" }, method = RequestMethod.GET)
#ResponseBody
public Image getImage(#PathVariable UUID imageId) {
return imageDataService.getImage(imageId);
}
...
If I change the mapping to the following then it works just fine.
#RequestMapping(value = { "/image/{imageId}" }, method = RequestMethod.GET)
#ResponseBody
public Image getImage(#PathVariable UUID imageId) {
return imageDataService.getImage(imageId);
}
I'm thinking that the config for static resources has a default entry that tells Spring security to ignore the "/images" path for the preauth filter. I'm debugging around trying to figure out where that might be overridden.
SpringBoot by default use some paths
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/" };
https://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot
And one of this paths is /images
Java Web Application. Spring Boot. Locating Images
Also you have the following restrictions when usind SpringSecurity
The basic features you get out of the box in a web application are:
An AuthenticationManager bean with in-memory store and a single user
(see SecurityProperties.User for the properties of the user). Ignored
(insecure) paths for common static resource locations (/css/,
/js/, /images/, /webjars/ and **/favicon.ico). HTTP Basic
security for all other endpoints. Security events published to
Spring’s ApplicationEventPublisher (successful and unsuccessful
authentication and access denied).
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/
Common low-level features (HSTS, XSS, CSRF, caching) provided by Spring Security are on by default.
You need to ensure, that security is done for every request. This can be done using the following SecurityConfiguration:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
}
}

spring boot actuator endpoint mapping root class

In spring we can design rest web service like below.
#RestController
public class HelloController {
#RequestMapping(value = "/hello", method = RequestMethod.GET)
public String printWelcome(ModelMap model) {
model.addAttribute("message", "Hello");
return "hello";
}
}
When we do so, #RestController & #RequestMapping will internally manage request mapping part. So when I will hit url i.e. http://localhost:8080/hello it will point to printWelcome method.
I was looking into spring boot actuator source code. If we will use spring boot actuator in our application it will provide us some endpoints, which has exposed as rest APIs like health, metrics, info. So in my application if I am using spring boot actuator, when I will hit the url like "localhost:8080/health" I will get response.
So now my question is in spring boot actuator source code where this URLs get mapped. I have debugged source code of spring boot actuator, but not able to find out the root class of mapping of endpoints.
Can anyone please help ?
here it is , In AbstractEndpoint it says
/**
* Endpoint identifier. With HTTP monitoring the identifier of the endpoint is mapped
* to a URL (e.g. 'foo' is mapped to '/foo').
*/
If you see HealthEndPoint it extends AbstractEndpoint and does a super("health", false); , thats where it maps to "localhost:8080/health".
All spring-boot-actuator endpoints extends AbstractEndpoint (In Health endpoint case for example: class HealthEndpoint extends AbstractEndpoint<Health>) which construcor has the id of the Endpoint.
/**
* Endpoint identifier. With HTTP monitoring the identifier of the endpoint is mapped
* to a URL (e.g. 'foo' is mapped to '/foo').
*/
private String id;
Otherwise, it has an invoke method (from interface Endpoint) through it is invoked the endpoint.
/**
* Called to invoke the endpoint.
* #return the results of the invocation
*/
T invoke();
Finally, this endpoints are configured in the class EndpointAutoConfiguration as Bean:
#Bean
#ConditionalOnMissingBean
public HealthEndpoint healthEndpoint() {
return new HealthEndpoint(this.healthAggregator, this.healthIndicators);
}
Take a look this post where explains how to custom your endpoint:
http://blog.codeleak.pl/2014/10/spring-boot-actuator-custom-endpoint.html

Categories

Resources