Skip to content

Commit ea72614

Browse files
Merge pull request #1609 from CMSgov/QPPA-11386
QPPA-11386: normalize 404 datadog logging issue
2 parents 90bc2a9 + a67ff5b commit ea72614

2 files changed

Lines changed: 52 additions & 0 deletions

File tree

rest-api/src/main/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandler.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@
1010
import org.springframework.http.HttpHeaders;
1111
import org.springframework.http.HttpStatus;
1212
import org.springframework.http.MediaType;
13+
import org.springframework.http.HttpStatusCode;
1314
import org.springframework.http.ResponseEntity;
15+
import org.springframework.web.context.request.WebRequest;
1416
import org.springframework.web.bind.annotation.ControllerAdvice;
1517
import org.springframework.web.bind.annotation.ExceptionHandler;
1618
import org.springframework.web.bind.annotation.ResponseBody;
1719
import org.springframework.web.multipart.MultipartException;
1820
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
21+
import org.springframework.web.servlet.resource.NoResourceFoundException;
1922

2023
/**
2124
* Modify the controller to send back different responses for exceptions
@@ -69,6 +72,25 @@ ResponseEntity<AllErrors> handleQppValidationException(QppValidationException ex
6972
return cope(exception);
7073
}
7174

75+
/**
76+
* Handles {@link NoResourceFoundException} for requests to non-existent paths/resources.
77+
* Returns a clean 404 and logs at DEBUG/TRACE to avoid ERROR-level noise.
78+
*/
79+
@Override
80+
protected ResponseEntity<Object> handleNoResourceFoundException(
81+
NoResourceFoundException ex,
82+
HttpHeaders headers,
83+
HttpStatusCode status,
84+
WebRequest request) {
85+
86+
API_LOG.debug("No resource found ({}): {}", status.value(), ex.getMessage());
87+
API_LOG.trace("NoResourceFoundException details", ex);
88+
89+
return ResponseEntity.status(status)
90+
.contentType(MediaType.TEXT_PLAIN)
91+
.body("Not found");
92+
}
93+
7294
/**
7395
* "Catch" the {@link NoFileInDatabaseException}.
7496
* Return the {@link AllErrors} with an HTTP status 404.

rest-api/src/test/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandlerTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@
2727
import org.springframework.http.HttpStatus;
2828
import org.springframework.http.MediaType;
2929
import org.springframework.http.ResponseEntity;
30+
import org.springframework.http.HttpHeaders;
31+
import org.springframework.http.HttpMethod;
3032
import org.springframework.test.web.servlet.MockMvc;
3133
import org.springframework.test.web.servlet.MvcResult;
3234
import org.springframework.test.web.servlet.RequestBuilder;
3335
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
3436
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
37+
import org.springframework.web.context.request.WebRequest;
38+
import org.springframework.web.servlet.resource.NoResourceFoundException;
3539

3640
import java.nio.file.Path;
3741
import java.util.UUID;
@@ -247,6 +251,32 @@ void testHandleInvalidPurposeExceptionResponseBodyDoesInterception() throws Exce
247251
.isEqualTo("Given Purpose (header) is too large. Max length is 25, yours was " + purpose.length());
248252
}
249253

254+
@Test
255+
void testHandleNoResourceFoundExceptionReturnsPlain404() throws Exception {
256+
NoResourceFoundException ex;
257+
try {
258+
ex = NoResourceFoundException.class
259+
.getConstructor(HttpMethod.class, String.class)
260+
.newInstance(HttpMethod.GET, "/test");
261+
} catch (NoSuchMethodException ignore) {
262+
ex = NoResourceFoundException.class
263+
.getConstructor(HttpMethod.class, String.class, String.class)
264+
.newInstance(HttpMethod.GET, "/test", "/test");
265+
}
266+
267+
ResponseEntity<Object> response = objectUnderTest.handleNoResourceFoundException(
268+
ex,
269+
new HttpHeaders(),
270+
HttpStatus.NOT_FOUND,
271+
Mockito.mock(WebRequest.class)
272+
);
273+
274+
Truth.assertThat(response.getStatusCodeValue()).isEqualTo(404);
275+
Truth.assertThat(response.getHeaders().getContentType())
276+
.isEquivalentAccordingToCompareTo(MediaType.TEXT_PLAIN);
277+
Truth.assertThat(response.getBody()).isEqualTo("Not found");
278+
}
279+
250280
@Override
251281
public Class<?> getLoggerType() {
252282
return GlobalExceptionHandler.class;

0 commit comments

Comments
 (0)