skywalking展示http请求和响应

2021-11-24 13:26:38 浏览数 (1)

使用skywalking跟踪请求的时候,是看不到http请求的参数的,这样不方便定位问题。本文通过自定义的方式(ActiveSpan.tag),实现了http请求和响应的输出,方便快速定位问题

效果图

可以在请求中看到自定义请求信息input和返回值output,方便快速定位问题

实现请求和响应的输出

  • 添加依赖
代码语言:javascript复制
<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-trace</artifactId>
    <version>8.7.0</version>
    <scope>provided</scope>
</dependency>
  • 使用ActiveSpan.tag输出到skywalking
代码语言:javascript复制
ActiveSpan.tag("input", sb.toString());
  • 实现http请求和返回值的的输出

因为HttpServletRequestHttpServletResponse中的body只能读取一次,如果在Filte中读取的话,应用本身就读取不到,所以需要使用ContentCachingRequestWrapperContentCachingResponseWrapper

代码语言:javascript复制
@Slf4j
@Component
public class ApmHttpInfo extends HttpFilter {
    private static final ImmutableSet<String> IGNORED_HEADERS;
    static {
        Set<String> ignoredHeaders = ImmutableSet.of(
                        "Content-Type",
                        "User-Agent",
                        "Accept",
                        "Cache-Control",
                        "Postman-Token",
                        "Host",
                        "Accept-Encoding",
                        "Connection",
                        "Content-Length")
                .stream()
                .map(String::toUpperCase)
                .collect(Collectors.toSet());
        IGNORED_HEADERS = ImmutableSet.copyOf(ignoredHeaders);
    }

    @Override
    public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);

        try {
            filterChain.doFilter(requestWrapper, responseWrapper);
        } finally {
            try {
                //构造请求信息: 比如 curl -X GET http://localhost:18080/getPerson?id=1 -H 'token: me-token' -d '{ "name": "hello" }'
                //构造请求的方法&URL&参数
                StringBuilder sb = new StringBuilder("curl")
                        .append(" -X ").append(request.getMethod())
                        .append(" ").append(request.getRequestURL().toString());
                if (StringUtils.hasLength(request.getQueryString())) {
                    sb.append("?").append(request.getQueryString());
                }

                //构造header
                Enumeration<String> headerNames = request.getHeaderNames();
                while (headerNames.hasMoreElements()) {
                    String headerName = headerNames.nextElement();
                    if (!IGNORED_HEADERS.contains(headerName.toUpperCase())) {
                        sb.append(" -H '").append(headerName).append(": ").append(request.getHeader(headerName)).append("'");
                    }
                }

                //获取body
                String body = new String(requestWrapper.getContentAsByteArray(), StandardCharsets.UTF_8);
                if (StringUtils.hasLength(body)) {
                    sb.append(" -d '").append(body).append("'");
                }
                //输出到input
                ActiveSpan.tag("input", sb.toString());

                //获取返回值body
                String responseBody = new String(responseWrapper.getContentAsByteArray(), StandardCharsets.UTF_8);
                //输出到output
                ActiveSpan.tag("output", responseBody);
            } catch (Exception e) {
                log.warn("fail to build http log", e);
            } finally {
                //这一行必须添加,否则就一直不返回
                responseWrapper.copyBodyToResponse();
            }
        }
    }
}

参考

  • skywalking搭建
  • Spring参数错误时输出Http内容

0 人点赞