如何在 X-Ray SegmentListener 中访问传入的 HTTP 请求?
How to access incoming HTTP requests in X-Ray SegmentListener?
问题
我使用 AWS X-Ray SDK for Java 为我的 Spring 启动微服务启用 X-Ray 跟踪。
通过以下代码片段,我可以附加自定义 SegmentListener
:
final AWSXRayRecorder recorder = AWSXRayRecorderBuilder
.standard()
.withPlugin(new EcsPlugin())
.withSegmentListener(new SLF4JSegmentListener())
.withSegmentListener(new MyHttpHeaderSegementListener())
.build();
AWSXRay.setGlobalRecorder(recorder);
在 MyHttpHeaderSegementListener
中,我尝试根据传入的 HTTP 请求注入 X-Ray 注释 header(来自前端):
public class MyHttpHeaderSegementListener implements SegmentListener {
// snippet source:
public static Optional<HttpServletRequest> getCurrentHttpRequest() {
return Optional.ofNullable(RequestContextHolder.getRequestAttributes())
.filter(ServletRequestAttributes.class::isInstance)
.map(ServletRequestAttributes.class::cast)
.map(ServletRequestAttributes::getRequest);
}
public MyHttpHeaderSegementListener() {}
@Override
public void onBeginSegment(final Segment segment) {
final var httpContext = MyHttpHeaderSegementListener.getCurrentHttpRequest();
httpContext.ifPresent(context -> segment.putAnnotation("Origin", context.getHeader("Origin")));
}
}
段侦听器按预期触发 onBeginSegment
段,但 MyHttpHeaderSegementListener.getCurrentHttpRequest()
总是 returns Optional.empty
。
问题
- 是否有可能检查传入的 HTTP 请求(因为它们
Controller
) 在 SegmentListener
? 内收到
aws-xray-sdk-java
甚至可能支持本地方式吗?
- 为什么从
RequestContextHolder
检索到的请求总是空的?
(有点off-topic 但是:4. 基于 HTTP header 设置注释甚至是一个好习惯吗
我对问题 2. 和 3. 没有答案,但我找到了问题 1. 的答案。
对于传入的请求,您需要 add a Spring Filter to configure AWS X-Ray。由于 过滤器可以访问 HTTP 请求 我只是将自己的过滤器包裹在 AWS 的 com.amazonaws.xray.javax.servlet.AWSXRayServletFilter
周围:
public class XRayServletFilter extends AWSXRayServletFilter {
public XRayServletFilter(String fixedSegmentName) {
super(fixedSegmentName);
}
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
this.addHttpRequestToContext(request);
super.doFilter(request, response, chain);
}
private void addHttpRequestToContext(final ServletRequest request){
final Optional<HttpServletRequest> httpServletRequest = HttpRequestUtils.castToHttpRequest(request);
if (httpServletRequest.isPresent()) {
final ServletRequestAttributes requestAttributes = new ServletRequestAttributes(httpServletRequest.get());
RequestContextHolder.setRequestAttributes(requestAttributes);
}
}
}
它使用我写的静态 class:
public final class HttpRequestUtils {
public static Optional<HttpServletRequest> getCurrentHttpRequest() {
return Optional.ofNullable(RequestContextHolder.getRequestAttributes())
.filter(ServletRequestAttributes.class::isInstance)
.map(ServletRequestAttributes.class::cast)
.map(ServletRequestAttributes::getRequest);
}
public static Optional<HttpServletRequest> castToHttpRequest(ServletRequest request) {
try {
return Optional.of((HttpServletRequest) request);
} catch (ClassCastException classCastException) {
return Optional.empty();
}
}
}
此自定义过滤器基本上设置 RequestContextHolder
中的 HTTP 请求。之后,您可以在您的分段侦听器中使用它:
public class MyHttpHeaderSegementListener implements SegmentListener {
public MyHttpHeaderSegementListener() {}
@Override
public void onBeginSegment(final Segment segment) {
final Optional<HttpServletRequest> request = HttpRequestUtils.getCurrentHttpRequest();
request.map(req -> req.getHeader("Origin")).ifPresent(origin -> segment.putAnnotation("client_origin", origin));;
}
}
问题
我使用 AWS X-Ray SDK for Java 为我的 Spring 启动微服务启用 X-Ray 跟踪。
通过以下代码片段,我可以附加自定义 SegmentListener
:
final AWSXRayRecorder recorder = AWSXRayRecorderBuilder
.standard()
.withPlugin(new EcsPlugin())
.withSegmentListener(new SLF4JSegmentListener())
.withSegmentListener(new MyHttpHeaderSegementListener())
.build();
AWSXRay.setGlobalRecorder(recorder);
在 MyHttpHeaderSegementListener
中,我尝试根据传入的 HTTP 请求注入 X-Ray 注释 header(来自前端):
public class MyHttpHeaderSegementListener implements SegmentListener {
// snippet source:
public static Optional<HttpServletRequest> getCurrentHttpRequest() {
return Optional.ofNullable(RequestContextHolder.getRequestAttributes())
.filter(ServletRequestAttributes.class::isInstance)
.map(ServletRequestAttributes.class::cast)
.map(ServletRequestAttributes::getRequest);
}
public MyHttpHeaderSegementListener() {}
@Override
public void onBeginSegment(final Segment segment) {
final var httpContext = MyHttpHeaderSegementListener.getCurrentHttpRequest();
httpContext.ifPresent(context -> segment.putAnnotation("Origin", context.getHeader("Origin")));
}
}
段侦听器按预期触发 onBeginSegment
段,但 MyHttpHeaderSegementListener.getCurrentHttpRequest()
总是 returns Optional.empty
。
问题
- 是否有可能检查传入的 HTTP 请求(因为它们
Controller
) 在SegmentListener
? 内收到
aws-xray-sdk-java
甚至可能支持本地方式吗?- 为什么从
RequestContextHolder
检索到的请求总是空的?
(有点off-topic 但是:4. 基于 HTTP header 设置注释甚至是一个好习惯吗
我对问题 2. 和 3. 没有答案,但我找到了问题 1. 的答案。
对于传入的请求,您需要 add a Spring Filter to configure AWS X-Ray。由于 过滤器可以访问 HTTP 请求 我只是将自己的过滤器包裹在 AWS 的 com.amazonaws.xray.javax.servlet.AWSXRayServletFilter
周围:
public class XRayServletFilter extends AWSXRayServletFilter {
public XRayServletFilter(String fixedSegmentName) {
super(fixedSegmentName);
}
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
this.addHttpRequestToContext(request);
super.doFilter(request, response, chain);
}
private void addHttpRequestToContext(final ServletRequest request){
final Optional<HttpServletRequest> httpServletRequest = HttpRequestUtils.castToHttpRequest(request);
if (httpServletRequest.isPresent()) {
final ServletRequestAttributes requestAttributes = new ServletRequestAttributes(httpServletRequest.get());
RequestContextHolder.setRequestAttributes(requestAttributes);
}
}
}
它使用我写的静态 class:
public final class HttpRequestUtils {
public static Optional<HttpServletRequest> getCurrentHttpRequest() {
return Optional.ofNullable(RequestContextHolder.getRequestAttributes())
.filter(ServletRequestAttributes.class::isInstance)
.map(ServletRequestAttributes.class::cast)
.map(ServletRequestAttributes::getRequest);
}
public static Optional<HttpServletRequest> castToHttpRequest(ServletRequest request) {
try {
return Optional.of((HttpServletRequest) request);
} catch (ClassCastException classCastException) {
return Optional.empty();
}
}
}
此自定义过滤器基本上设置 RequestContextHolder
中的 HTTP 请求。之后,您可以在您的分段侦听器中使用它:
public class MyHttpHeaderSegementListener implements SegmentListener {
public MyHttpHeaderSegementListener() {}
@Override
public void onBeginSegment(final Segment segment) {
final Optional<HttpServletRequest> request = HttpRequestUtils.getCurrentHttpRequest();
request.map(req -> req.getHeader("Origin")).ifPresent(origin -> segment.putAnnotation("client_origin", origin));;
}
}