Закончилось это с помощью WebFilter, полученного из MetricsFilter
@Named
@Order(Ordered.LOWEST_PRECEDENCE)
public class AuditAccessLogFilter implements WebFilter {
private final Logger log = LoggerFactory.getLogger(getClass());
@Inject
private Logger AUDIT;
private Authentication anonymousUser = new AnonymousAuthenticationToken("key", "anonymous", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
private static final String hostname;
static {
try {
hostname = InetAddress.getLocalHost()
.getHostName();
} catch (UnknownHostException e) {
throw new RuntimeException("Could not find local hostname");
}
}
@Value("${spring.application.name}")
private String appName;
@Value("${server.port}")
private String serverPort;
public AuditAccessLogFilter() {
if (StringUtils.isEmpty(appName)) {
log.warn("Application name is not set, using run directory");
appName = "-";
}
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return chain.filter(exchange)
.compose(call -> filter(exchange, call));
}
private Publisher<Void> filter(ServerWebExchange exchange, Mono<Void> call) {
long start = System.currentTimeMillis();
ServerHttpResponse response = exchange.getResponse();
return Mono.subscriberContext()
.flatMap(context -> exchange.getPrincipal()
.switchIfEmpty(Mono.just(anonymousUser))
.flatMap(principal -> call.doOnSuccess(done -> success(exchange, principal, context, start))
.doOnError(cause -> {
if (response.isCommitted()) {
error(exchange, principal, start, context, cause);
}
else {
response.beforeCommit(() -> {
error(exchange, principal, start, context, cause);
return Mono.empty();
});
}
})));
}
private void success(ServerWebExchange exchange, Principal principal, Context context, long start) {
long timeTaken = System.currentTimeMillis() - start;
auditLog(() -> AUDIT.info("accesslog"), timeTaken, exchange, principal, context);
}
private void error(ServerWebExchange exchange, Principal principal, long start, Context context, Throwable cause) {
long timeTaken = System.nanoTime() - start;
auditLog(() -> AUDIT.error("accesslog", cause.getMessage()), timeTaken, exchange, principal, context);
}
private void auditLog(Runnable fun, long timeTaken, ServerWebExchange exchange, Principal principal, Context context) {
HttpStatus tmpStatusCode = exchange.getResponse()
.getStatusCode();
int statusCode = (tmpStatusCode == null ? 0 : tmpStatusCode.value());
String uri = exchange.getRequest()
.getURI()
.toString();
String queryParams = exchange.getRequest()
.getQueryParams()
.toString();
String reasonPhrase = exchange.getResponse()
.getStatusCode()
.getReasonPhrase();
try (MDC.MDCCloseable ignored = MDC.putCloseable("id", context.getOrDefault(GeneralConfig.REQUEST_HASH, "-"));
MDC.MDCCloseable ignored2 = MDC.putCloseable("responsetimeMs", Long.toString(timeTaken));
MDC.MDCCloseable ignored3 = MDC.putCloseable("uri", uri);
MDC.MDCCloseable ignored4 = MDC.putCloseable("user", principal.getName());
MDC.MDCCloseable ignored5 = MDC.putCloseable("params", queryParams);
MDC.MDCCloseable ignored6 = MDC.putCloseable("httpCode", Integer.toString(statusCode));
MDC.MDCCloseable ignored7 = MDC.putCloseable("httpReason", reasonPhrase);
MDC.MDCCloseable ignored8 = MDC.putCloseable("hostname", hostname + ":" + serverPort);
MDC.MDCCloseable ignored9 = MDC.putCloseable("appname", appName)) {
fun.run();
}
}
}