Commit f7fa63bc authored by Dave Syer's avatar Dave Syer

Add status and error messages to /trace

[Fixes #57949108] [bs-323] Make sure /trace shows error responses
parent 1bdb2ce1
...@@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.trace.TraceRepository; import org.springframework.boot.actuate.trace.TraceRepository;
import org.springframework.boot.actuate.trace.WebRequestTraceFilter; import org.springframework.boot.actuate.trace.WebRequestTraceFilter;
import org.springframework.boot.actuate.web.BasicErrorController;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
...@@ -42,6 +43,9 @@ public class TraceWebFilterAutoConfiguration { ...@@ -42,6 +43,9 @@ public class TraceWebFilterAutoConfiguration {
@Autowired @Autowired
private TraceRepository traceRepository; private TraceRepository traceRepository;
@Autowired(required = false)
private BasicErrorController errorController;
@Value("${management.dump_requests:false}") @Value("${management.dump_requests:false}")
private boolean dumpRequests; private boolean dumpRequests;
...@@ -49,6 +53,9 @@ public class TraceWebFilterAutoConfiguration { ...@@ -49,6 +53,9 @@ public class TraceWebFilterAutoConfiguration {
public WebRequestTraceFilter webRequestLoggingFilter(BeanFactory beanFactory) { public WebRequestTraceFilter webRequestLoggingFilter(BeanFactory beanFactory) {
WebRequestTraceFilter filter = new WebRequestTraceFilter(this.traceRepository); WebRequestTraceFilter filter = new WebRequestTraceFilter(this.traceRepository);
filter.setDumpRequests(this.dumpRequests); filter.setDumpRequests(this.dumpRequests);
if (this.errorController != null) {
filter.setErrorController(this.errorController);
}
return filter; return filter;
} }
......
...@@ -34,6 +34,7 @@ import javax.servlet.http.HttpServletResponse; ...@@ -34,6 +34,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.boot.actuate.web.BasicErrorController;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
...@@ -56,6 +57,8 @@ public class WebRequestTraceFilter implements Filter, Ordered { ...@@ -56,6 +57,8 @@ public class WebRequestTraceFilter implements Filter, Ordered {
private ObjectMapper objectMapper = new ObjectMapper(); private ObjectMapper objectMapper = new ObjectMapper();
private BasicErrorController errorController;
/** /**
* @param traceRepository * @param traceRepository
*/ */
...@@ -122,6 +125,7 @@ public class WebRequestTraceFilter implements Filter, Ordered { ...@@ -122,6 +125,7 @@ public class WebRequestTraceFilter implements Filter, Ordered {
String value = response.getHeader(header); String value = response.getHeader(header);
headers.put(header, value); headers.put(header, value);
} }
headers.put("status", "" + response.getStatus());
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<String, Object> allHeaders = (Map<String, Object>) trace.get("headers"); Map<String, Object> allHeaders = (Map<String, Object>) trace.get("headers");
allHeaders.put("response", headers); allHeaders.put("response", headers);
...@@ -151,6 +155,13 @@ public class WebRequestTraceFilter implements Filter, Ordered { ...@@ -151,6 +155,13 @@ public class WebRequestTraceFilter implements Filter, Ordered {
trace.put("method", request.getMethod()); trace.put("method", request.getMethod());
trace.put("path", request.getRequestURI()); trace.put("path", request.getRequestURI());
trace.put("headers", allHeaders); trace.put("headers", allHeaders);
Throwable error = (Throwable) request
.getAttribute("javax.servlet.error.exception");
if (error != null) {
if (this.errorController != null) {
trace.put("error", this.errorController.error(request));
}
}
return trace; return trace;
} }
...@@ -162,4 +173,8 @@ public class WebRequestTraceFilter implements Filter, Ordered { ...@@ -162,4 +173,8 @@ public class WebRequestTraceFilter implements Filter, Ordered {
public void destroy() { public void destroy() {
} }
public void setErrorController(BasicErrorController errorController) {
this.errorController = errorController;
}
} }
...@@ -19,6 +19,7 @@ package org.springframework.boot.actuate.trace; ...@@ -19,6 +19,7 @@ package org.springframework.boot.actuate.trace;
import java.util.Map; import java.util.Map;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.actuate.web.BasicErrorController;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
...@@ -55,6 +56,38 @@ public class WebRequestTraceFilterTests { ...@@ -55,6 +56,38 @@ public class WebRequestTraceFilterTests {
this.filter.enhanceTrace(trace, response); this.filter.enhanceTrace(trace, response);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) trace.get("headers"); Map<String, Object> map = (Map<String, Object>) trace.get("headers");
assertEquals("{Content-Type=application/json}", map.get("response").toString()); assertEquals("{Content-Type=application/json, status=200}", map.get("response")
.toString());
}
@Test
public void filterHasResponseStatus() {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
MockHttpServletResponse response = new MockHttpServletResponse();
response.setStatus(404);
response.addHeader("Content-Type", "application/json");
Map<String, Object> trace = this.filter.getTrace(request);
this.filter.enhanceTrace(trace, response);
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) ((Map<String, Object>) trace
.get("headers")).get("response");
assertEquals("404", map.get("status").toString());
}
@Test
public void filterHasError() {
this.filter.setErrorController(new BasicErrorController());
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
MockHttpServletResponse response = new MockHttpServletResponse();
response.setStatus(500);
request.setAttribute("javax.servlet.error.exception", new IllegalStateException(
"Foo"));
response.addHeader("Content-Type", "application/json");
Map<String, Object> trace = this.filter.getTrace(request);
this.filter.enhanceTrace(trace, response);
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) trace.get("error");
System.err.println(map);
assertEquals("Foo", map.get("message").toString());
} }
} }
...@@ -16,6 +16,10 @@ ...@@ -16,6 +16,10 @@
package org.springframework.boot.sample.ops; package org.springframework.boot.sample.ops;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
...@@ -43,10 +47,6 @@ import org.springframework.security.crypto.codec.Base64; ...@@ -43,10 +47,6 @@ import org.springframework.security.crypto.codec.Base64;
import org.springframework.web.client.DefaultResponseErrorHandler; import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/** /**
* Basic integration tests for service demo application. * Basic integration tests for service demo application.
* *
...@@ -134,13 +134,27 @@ public class SampleActuatorApplicationTests { ...@@ -134,13 +134,27 @@ public class SampleActuatorApplicationTests {
@Test @Test
public void testErrorPage() throws Exception { public void testErrorPage() throws Exception {
ResponseEntity<String> entity = getRestTemplate().getForEntity(
"http://localhost:8080/health", String.class);
assertEquals(HttpStatus.OK, entity.getStatusCode());
assertEquals("ok", entity.getBody());
}
@Test
public void testTrace() throws Exception {
getRestTemplate().getForEntity(
"http://localhost:8080/health", String.class);
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
ResponseEntity<Map> entity = getRestTemplate("user", getPassword()).getForEntity( ResponseEntity<List> entity = getRestTemplate("user", getPassword()).getForEntity(
"http://localhost:8080/foo", Map.class); "http://localhost:8080/trace", List.class);
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, entity.getStatusCode()); assertEquals(HttpStatus.OK, entity.getStatusCode());
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<String, Object> body = entity.getBody(); List<Map<String,Object>> list = (List<Map<String, Object>>) entity.getBody();
assertEquals(500, body.get("status")); Map<String, Object> trace = list.get(list.size()-1);
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) ((Map<String, Object>) ((Map<String, Object>)
trace.get("info")).get("headers")).get("response");
assertEquals("200", map.get("status"));
} }
@Test @Test
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment