首页 > 解决方案 > 使用 @RepositoryRestResource 时记录请求/响应

问题描述

我正在使用来自. spring-data-rest-api由于 JAX-RS 控制器是自动生成的,因此我无法手动添加记录器来记录传入请求。是否存在会自动记录请求的注释?

我的代码:

@RepositoryRestResource(collectionResourceRel = "organizations", path = "organizations")
public interface OrganizationRepository extends JpaRepository<Organization, UUID> {
}

标签: jax-rsslf4jspring-data-rest

解决方案


由于我的应用程序是用 Quarkus 编写的,并且我无法从 访问拦截器spring-web,因此我创建了一个自定义注释并使用了过滤器。

@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Logged { }
@Logged
@Provider
public class RequestLoggingFilter implements ContainerRequestFilter {

    /**
     * @param requestContext used to extract information from the HTTP request such as the URI, headers and HTTP entity.
     */
    @Override
    public void filter(ContainerRequestContext requestContext) {
        String message = getEntityBody(requestContext);
        requestContext.setProperty("StartTime", System.currentTimeMillis());
        String url = requestContext.getUriInfo().getAbsolutePath().toString();
        StructuredDataUtils.logRequestAsJson(url, message);
    }

    /**
     * @param requestContext HTTP request containing the request body.
     * @return the request body of an HTTP request.
     */
    private String getEntityBody(ContainerRequestContext requestContext) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        InputStream in = requestContext.getEntityStream();

        String result = null;
        try {
            ReaderWriter.writeTo(in, out);

            byte[] requestEntity = out.toByteArray();
            if (requestEntity.length == 0) {
                result = "";
            } else {
                result = new String(requestEntity, "UTF-8");
            }
            requestContext.setEntityStream(new ByteArrayInputStream(requestEntity));

        } catch (IOException e) {
            result = e.getMessage();
        }

        if (result.contains("password")) {
            result = maskPassword(result);
        }
        return result;
    }

    /**
     * @param jsonString JSON string containing password field.
     * @return JSON string with password field hidden.
     */
    private String maskPassword(String jsonString) {
        return jsonString.replaceAll("(\\n?\\s*\"password\"\\s?:\\s?\")[^\\n\"]*(\",?\\n?)", "$1********$2");
    }
}
@Logged
@Provider
public class ResponseLoggingFilter implements ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext requestContext,
                       ContainerResponseContext responseContext) {
        String responseMessage = convertObjectToJson(responseContext.getEntity());
        String responseStatus = responseContext.getStatusInfo().toString();
        String responseTime = String.valueOf(System.currentTimeMillis() - (Long) requestContext.getProperty("StartTime"));
        String calledServiceName = "d2d-server"; // TODO: pass service name in @Logged() and set default
        StructuredDataUtils.setStructuredDataFields(responseMessage, calledServiceName, responseStatus, responseTime);
    }
}

然后我简单地标记一个方法@Logged来记录 HTTP req/resp。


推荐阅读