Spring Boot REST app here. I'm trying to configure Spring Boot request auditing to log each and every HTTP request that any resources/controllers receive with the following info:
My best attempt so far:
@Component
public class MyAppAuditor {
private Logger logger;
@EventListener
public void handleAuditEvent(AuditApplicationEvent auditApplicationEvent) {
logger.info(auditApplicationEvent.auditEvent);
}
}
public class AuditingTraceRepository implements TraceRepository {
@Autowired
private ApplicationEventPublisher applicationEventPublisher
@Override
List<Trace> findAll() {
throw new UnsupportedOperationException("We don't expose trace information via /trace!");
}
@Override
void add(Map<String, Object> traceInfo) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
AuditEvent traceRequestEvent = new AuditEvent(new Date(), "SomeUser", 'http.request.trace', traceInfo);
AuditApplicationEvent traceRequestAppEvent = new AuditApplicationEvent(traceRequestEvent);
applicationEventPublisher.publishEvent(traceRequestAppEvent);
}
}
However at runtime if I use the following curl command:
curl -i -H "Content-Type: application/json" -X GET 'http://localhost:9200/v1/data/profiles?continent=NA&country=US&isMale=0&height=1.5&dob=range('1980-01-01','1990-01-01')'
Then I only see the following log messages (where MyAppAuditor
send audit events):
{ "timestamp" : "14:09:50.516", "thread" : "qtp1293252487-17", "level" : "INFO", "logger" : "com.myapp.ws.shared.auditing.MyAppAuditor", "message" : {"timestamp":"2018-06-29T18:09:50+0000","principal":"SomeUser","type":"http.request.trace","data":{"method":"GET","path":"/v1/data/profiles","headers":{"request":{"User-Agent":"curl/7.54.0","Host":"localhost:9200","Accept":"*/*","Content-Type":"application/json"},"response":{"X-Frame-Options":"DENY","Cache-Control":"no-cache, no-store, max-age=0, must-revalidate","X-Content-Type-Options":"nosniff","Pragma":"no-cache","Expires":"0","X-XSS-Protection":"1; mode=block","X-Application-Context":"application:9200","Date":"Fri, 29 Jun 2018 18:09:50 GMT","Content-Type":"application/json;charset=utf-8","status":"200"}},"timeTaken":"89"}} }
So as you can see, the auditor is picking up the base path (/v1/data/profiles
) but is not logging any of the query string parameters. I also see a similar absence of request body info when I hit POST or PUT endpoints that do require a request body (JSON).
What do I need to do to configure these classes (or other Spring classes/configs) so that I get the level of request auditing that I'm looking for?
Fortunately, Actuator makes it very easy to configure those Trace
events.
Adding parameters to Trace info
You can take a look at all of the options. You'll notice the defaults (line 42
) are:
Include.REQUEST_HEADERS,
Include.RESPONSE_HEADERS,
Include.COOKIES,
Include.ERRORS,
Include.TIME_TAKEN
So you'll need to also add Include.PARAMETERS
and anything else you'd like to have in the trace. To configure that, there's a configuration property for that management.trace.include
.
So to get what you want (i.e. parameters
), plus the defaults, you'd have:
management.trace.include = parameters, request-headers, response-headers, cookies, errors, time-taken
Adding request body to Trace info
In order to get the body
, you're going to have to add in this Bean
to your Context
:
@Component
public class WebRequestTraceFilterWithPayload extends WebRequestTraceFilter {
public WebRequestTraceFilterWithPayload(TraceRepository repository, TraceProperties properties) {
super(repository, properties);
}
@Override
protected Map<String, Object> getTrace(HttpServletRequest request) {
Map<String, Object> trace = super.getTrace(request);
String body = null;
try {
body = request.getReader().lines().collect(Collectors.joining("\n"));
} catch (IOException e) {
throw new RuntimeException(e);
}
if(body != null) {
trace.put("body", body);
}
return trace;
}
}
The above code will override the AutoConfigure'd
WebRequestTraceFilter
bean (which, because it is @ConditionalOnMissingBean
will give deference to your custom bean), and pull the extra payload property off of the request
then add it to to the Map
properties that get published to your TraceRepository
!
Summary
TraceRepository trace events
by via the management.trace.include
propertyTraceRepository trace events
by creating an extended Bean
to read the body
off of the HTTP request and supplementing the trace events