本文共 5540 字,大约阅读时间需要 18 分钟。
在微服务架构中,日志的收集与存储对于问题定位和服务优化具有重要意义。Spring Cloud Gateway作为API网关,在处理大量请求时,日志的清晰收集和存储成为关键环节。本节将详细介绍在网关层统一日志收集的实现方案。
首先,我们需要定义一个日志模型 GatewayLog
来存储请求的相关信息。该模型应包含以下字段:
@Data@Documentpublic class GatewayLog { @Id private String id; /** 访问实例 */ private String targetServer; /** 请求路径 */ private String requestPath; /** 请求方法 */ private String requestMethod; /** 协议 */ private String schema; /** 请求体 */ private String requestBody; /** 响应体 */ private String responseData; /** 请求IP */ private String ip; /** 请求时间 */ private Date requestTime; /** 响应时间 */ private Date responseTime; /** 执行时间 */ private long executeTime;}
接下来,定义一个 AccessLogRepository
作为数据存储接口:
@Repositorypublic interface AccessLogRepository extends ReactiveMongoRepository{ @Query("{ gatewayLog.ip : ?0 }") Flux findByIp(String ip);}
在 AccessLogFilter
中,实现日志收集逻辑。该过滤器需要:
GatewayLog
对象中。@Slf4j@Componentpublic class AccessLogFilter implements GlobalFilter, Ordered { @Autowired private AccessLogService accessLogService; private final ListmessageReaders = HandlerStrategies.withDefaults().messageReaders(); @Override public int getOrder() { return -100; } @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); String requestPath = request.getPath().pathWithinApplication().value(); Route route = getGatewayRoute(exchange); String ipAddress = WebUtils.getServerHttpRequestIpAddress(request); GatewayLog gatewayLog = new GatewayLog(); gatewayLog.setSchema(request.getURI().getScheme()); gatewayLog.setRequestMethod(request.getMethodValue()); gatewayLog.setRequestPath(requestPath); gatewayLog.setTargetServer(route.getId()); gatewayLog.setRequestTime(new Date()); gatewayLog.setIp(ipAddress); if (isBodyReadable(request)) { return writeBodyLog(exchange, chain, gatewayLog); } else { return writeBasicLog(exchange, chain, gatewayLog); } } private boolean isBodyReadable(ServerWebExchange request) { return request.getHeaders().getContentType().isCompatibleWith( MediaType.APPLICATION_FORM_URLENCODED) || request.getHeaders().getContentType().isCompatibleWith(MediaType.APPLICATION_JSON); } private Mono writeBasicLog(...) { // 收集请求参数并封装到日志 // 获取响应体并记录日志 return chain.filter(exchange.mutate().response(decoratedResponse).build()) .then(Mono.fromRunnable(() -> writeAccessLog(gatewayLog))); } private Mono writeBodyLog(...) { // 处理请求体,避免只能读取一次的问题 return bodyInserter.insert(outputMessage, ...) .then(Mono.fromRunnable(() -> { decoratedRequest = requestDecorate(exchange, headers, outputMessage); decoratedResponse = recordResponseLog(exchange, gatewayLog); return chain.filter(exchange.mutate().request(decoratedRequest).response(decoratedResponse).build()) .then(Mono.fromRunnable(() -> writeAccessLog(gatewayLog))); })); } private void writeAccessLog(GatewayLog gatewayLog) { log.info(gatewayLog.toString()); accessLogService.saveAccessLog(gatewayLog); } private Route getGatewayRoute(ServerWebExchange exchange) { return exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR); } private ServerHttpRequestDecorator requestDecorate(...) { // 重新封装请求,处理分段传输问题 return new ServerHttpRequestDecorator(exchange.getRequest()) { @Override public HttpHeaders getHeaders() { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.putAll(super.getHeaders()); if (contentLength > 0) { httpHeaders.setContentLength(contentLength); } else { httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); } return httpHeaders; } @Override public Flux .getBody() { return outputMessage.getBody(); } }; } private ServerHttpResponseDecorator recordResponseLog(...) { // 处理响应体分段传输问题 return new ServerHttpResponseDecorator(response) { @Override public Mono writeWith(Publisher body) { // 处理响应体,生成执行时间和存储日志 return super.writeWith(body); } }; } }
在项目中引入MongoDB Reactive版本:
org.springframework.boot spring-boot-starter-data-mongodb-reactive
在配置中心(如Nacos)中添加MongoDB配置:
spring: data: mongodb: host: xxx.xx.x.xx port: 27017 database: accesslog username: accesslog password: xxxx
getOrder()
方法返回值必须为 -1
,否则标准过滤器会在获取后端响应之前发送响应。通过以上优化方案,我们可以在网关层统一收集和存储日志,支持后续问题定位和服务监控。
转载地址:http://cycoz.baihongyu.com/