通过gateway 打印日志全局控制日志

需求:

业务上经常需要打印日志,传统代码加日志,对代码侵入太强,不管是添加删除修改日志 都会改动代码,即使使用注解也需要添加注解,想实现且偶零侵入添加代码。

解决方法

gateway 自定义filter。
前置条件,项目中已经使用gateway 。

code


import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered
{

    /**
     * 数字越小优先级越高
     * @return
     */
    @Override
    public int getOrder()
    {
        return 0;
    }

    private static final String BEGIN_VISIT_TIME = "begin_visit_time";//开始访问时间
    /**
     *第2版,各种统计
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //先记录下访问接口的开始时间
        exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis());

        return chain.filter(exchange).then(Mono.fromRunnable(()->{
            Long beginVisitTime = exchange.getAttribute(BEGIN_VISIT_TIME);
            if (beginVisitTime != null){
                log.info("访问接口主机: " + exchange.getRequest().getURI().getHost());
                log.info("访问接口端口: " + exchange.getRequest().getURI().getPort());
                log.info("访问接口URL: " + exchange.getRequest().getURI().getPath());
                log.info("访问接口URL参数: " + exchange.getRequest().getURI().getRawQuery());
                log.info("访问接口时长: " + (System.currentTimeMillis() - beginVisitTime) + "ms");
                log.info("我是美丽分割线: ###################################################");
                System.out.println();
            }
        }));
    }

}

<think>好的,我需要帮助用户将Spring Cloud Gateway的请求调用日志存储到PostgreSQL数据库中。首先,我得理解整个流程需要哪些步骤。 用户提到他们已经在使用Spring Cloud Gateway,所以可能需要通过自定义过滤器或拦截器来捕获请求和响应信息。根据引用[3]中提到的,可以扩展Gateway的过滤器来实现日志记录。比如,GlobalFilter可能是一个切入点,因为它是全局的,可以拦截所有请求。 接下来,日志记录的内容需要确定。一般来说,请求的路径、方法、状态码、响应时间、请求头等信息是必要的。这些信息可以通过ServerWebExchange对象获取。在过滤器中,可以在pre和post阶段分别记录请求和响应数据。 然后,如何将这些数据写入PostgreSQL。用户的项目可能已经集成了Spring Data JPA或者MyBatis等持久层框架。引用[4]提到Eurynome Cloud使用了Spring Boot和相关的技术,所以可以假设用户的项目结构类似。需要创建一个实体类来映射日志表的结构,然后通过Repository接口保存数据。 另外,异步写入日志可能是个好主意,避免阻塞网关的主线程。可以使用Spring的@Async注解或者消息队列来异步处理日志存储,但这可能会增加系统复杂性,需要根据用户的需求权衡。 还要考虑日志的格式化和序列化问题。确保从请求和响应中提取的数据能够正确转换为实体类的字段。例如,日期时间可能需要格式化,请求头可能需要转换为JSON字符串存储。 测试环节也很重要。用户可以使用PostMan发起请求,检查日志是否被正确记录到数据库中,如引用[2]中提到的,通过查看Redis验证数据存储,类似的方法可以应用到PostgreSQL的验证中。 最后,配置数据源。在application.yml中设置PostgreSQL的连接信息,确保网关能够连接到数据库。同时,检查依赖是否正确添加,比如PostgreSQL的JDBC驱动和Spring Data JPA的依赖。 可能遇到的问题包括过滤器执行顺序、事务管理、性能影响等。需要确保过滤器在适当的位置执行,并且日志记录操作不会显著影响网关的性能。引用[3]中提到动态改变网关的路由配置,说明扩展Gateway需要谨慎处理,避免影响现有功能。 总结步骤:创建日志实体和Repository,实现GlobalFilter记录日志,配置数据源,处理异步存储,测试验证。这样应该能够实现用户的需求。</think>### 分步解答:如何将 Spring Cloud Gateway 的调用日志存入 PostgreSQL 数据库? #### 1. **添加依赖** 在 `pom.xml` 中引入 PostgreSQL 驱动和 Spring Data JPA 依赖: ```xml <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> ``` #### 2. **定义日志实体类** 创建实体类映射数据库表: ```java @Entity @Table(name = "gateway_logs") public class GatewayLog { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String path; // 请求路径 private String method; // HTTP方法 private int status; // 响应状态码 private long duration; // 请求处理时间(毫秒) private String requestHeaders; // 请求头(JSON序列化) private String responseHeaders;// 响应头(JSON序列化) private LocalDateTime timestamp; // 请求时间 // Getters and Setters } ``` #### 3. **创建 Repository 接口** 定义 JPA 操作接口: ```java public interface GatewayLogRepository extends JpaRepository<GatewayLog, Long> { } ``` #### 4. **实现全局过滤器** 通过 `GlobalFilter` 记录请求/响应日志并存入数据库: ```java @Component public class LoggingFilter implements GlobalFilter { @Autowired private GatewayLogRepository logRepository; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { long startTime = System.currentTimeMillis(); ServerHttpRequest request = exchange.getRequest(); // 记录请求信息 GatewayLog log = new GatewayLog(); log.setPath(request.getPath().toString()); log.setMethod(request.getMethodValue()); log.setRequestHeaders(serializeHeaders(request.getHeaders())); log.setTimestamp(LocalDateTime.now()); return chain.filter(exchange).then(Mono.fromRunnable(() -> { // 记录响应信息 ServerHttpResponse response = exchange.getResponse(); log.setStatus(response.getStatusCode().value()); log.setDuration(System.currentTimeMillis() - startTime); log.setResponseHeaders(serializeHeaders(response.getHeaders())); // 异步保存日志(避免阻塞) CompletableFuture.runAsync(() -> logRepository.save(log)); })); } private String serializeHeaders(HttpHeaders headers) { return new JSONObject(headers.toSingleValueMap()).toString(); } } ``` #### 5. **配置数据源** 在 `application.yml` 中添加 PostgreSQL 配置: ```yaml spring: datasource: url: jdbc:postgresql://localhost:5432/gateway_logs username: postgres password: your_password jpa: hibernate: ddl-auto: update properties: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect ``` #### 6. **验证日志存储** 通过 Postman 发送请求后,查询 PostgreSQL 数据库: ```sql SELECT * FROM gateway_logs; ``` ### 关键优化点 - **异步处理**:使用 `CompletableFuture.runAsync()` 避免日志写入阻塞网关线程[^3] - **数据压缩**:对于大型请求头/响应体可添加压缩逻辑 - **错误处理**:添加 `try-catch` 块防止日志记录失败影响主流程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心系代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值