CrowFlo
CrowFlo

Reputation: 11

Spring Cloud Gateway, logging request/response

My GlobalFilter only logs successful requests (200). For example, code 500 does not pass through the ServerHttpRequestDecorator and ServerHttpResponseDecorator.

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        
    ServerHttpRequestDecorator requestMutated = new ServerHttpRequestDecorator(exchange.getRequest()) {
        @Override
        public Flux<DataBuffer> getBody() {
            Logger requestLogger = new Logger(getDelegate());
            if (LOGGABLE_CONTENT_TYPES.contains(String.valueOf(getHeaders().getContentType()).toLowerCase())) {
                return super.getBody().map(ds -> {
                    requestLogger.appendBody(ds.asByteBuffer());
                    return ds;
                }).doFinally(s -> requestLogger.log());
            } else {
                requestLogger.log();
                return super.getBody();
            }
        }
    };

    ServerHttpResponseDecorator responseMutated = new ServerHttpResponseDecorator(exchange.getResponse()) {
        @Override
        public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
            Logger responseLogger = new Logger(getDelegate());
            if (LOGGABLE_CONTENT_TYPES.contains(String.valueOf(getHeaders().getContentType()).toLowerCase())) {
                return join(body).flatMap(db -> {
                    responseLogger.appendBody(db.asByteBuffer());
                    responseLogger.log();
                    return getDelegate().writeWith(Mono.just(db));
                });
            } else {
                responseLogger.log();
                return getDelegate().writeWith(body);
            }
        }
    };

    return chain.filter(exchange.mutate().request(requestMutated).response(responseMutated).build());
}

ServerResponse.status(HttpStatus.valueOf(statusCode)) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(errorPropertiesMap)) => not log request and response;

What am I doing wrong? thanks for the help.

Upvotes: 1

Views: 7725

Answers (2)

harsha kumar Reddy
harsha kumar Reddy

Reputation: 1386

This will help

@Component
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {

    @Autowired
    private DataBufferWriter bufferWriter;

    Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
        HashMap<String, String> errorMap = new HashMap<String, String>();
        byte[] body = null;
        if (ex instanceof JwtException || ex instanceof UsernameNotFoundException) {
            exchange.getResponse().setRawStatusCode(HttpServletResponse.SC_UNAUTHORIZED);
            exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);

            status = HttpStatus.UNAUTHORIZED;
            errorMap.put("timestamp", LocalDateTime.now().toString());
            errorMap.put("message", ex.getLocalizedMessage());
            errorMap.put("error",ex.getClass().getName());
            errorMap.put("status", "401");
            log.error("Error in url :{} with error ", exchange.getRequest().getURI(), ex.getMessage(), ex);
        } else if (ex instanceof Throwable || ex instanceof IOException) {
            log.error("Exception occured in url :{}  while getting response. for trackingId= {} with exception : {}",
                    exchange.getRequest().getURI(), exchange.getRequest().getHeaders().getFirst("trackingId"),
                    ex.getLocalizedMessage(), ex);
            errorMap.put("timestamp", LocalDateTime.now().toString());
            errorMap.put("message", ex.getLocalizedMessage());
            errorMap.put("error",ex.getClass().getName());
            errorMap.put("status", "500");

        }

        if (exchange.getResponse().isCommitted()) {
            return Mono.error(ex);
        }

        exchange.getResponse().setStatusCode(status);

        return bufferWriter.write(exchange.getResponse(), errorMap);
    }
}

@Component
public class DataBufferWriter {
    Logger  log = LoggerFactory.getLogger(DataBufferWriter.class);
    public <T> Mono<Void> write(ServerHttpResponse httpResponse, HashMap<String, String> errorMap) {
        ObjectMapper objectMapper = new ObjectMapper();
        return httpResponse
            .writeWith(Mono.fromSupplier(() -> {
                DataBufferFactory bufferFactory = httpResponse.bufferFactory();
                try {
                    return bufferFactory.wrap(objectMapper.writeValueAsBytes(errorMap));
                } catch (Exception ex) {
                    log.warn("Error writing response", ex);
                    return bufferFactory.wrap(new byte[0]);
                }
            }));
    }
}

Upvotes: 0

cdan
cdan

Reputation: 3576

Try enable these properties in application.yml:

logging:
  level:
    org.springframework.web.HttpLogging: TRACE
    reactor.netty.http.server: DEBUG
    reactor.netty.http.client: DEBUG

spring
  cloud
    gateway
      httpserver
        wiretap: true

Upvotes: 1

Related Questions