使用skywalking跟踪请求的时候,是看不到http请求的参数的,这样不方便定位问题。本文通过自定义的方式(
ActiveSpan.tag
),实现了http请求和响应的输出,方便快速定位问题
效果图
可以在请求中看到自定义请求信息input和返回值output,方便快速定位问题
实现请求和响应的输出
- 添加依赖
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<version>8.7.0</version>
<scope>provided</scope>
</dependency>
- 使用
ActiveSpan.tag
输出到skywalking
ActiveSpan.tag("input", sb.toString());
- 实现http请求和返回值的的输出
代码语言:javascript复制因为
HttpServletRequest
和HttpServletResponse
中的body只能读取一次,如果在Filte中读取的话,应用本身就读取不到,所以需要使用ContentCachingRequestWrapper
和ContentCachingResponseWrapper
@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内容