,然后通过 extract
方法来解析 span context,然后将解析出来的 span context 设置为子 span 的父级 span,最后将 span context 存储在请求属性中,以便后续使用 。
这里的关键是在初始化 OpenTelemetry 的时候需要配置 ContextPropagators
,代码如下所示:
// 初始化 ContextPropagators,这里我们配置包含 W3C Trace Context 和 W3C BaggageContextPropagators propagators = ContextPropagators.create( TextMapPropagator.composite( W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance()));
这样我们才能去解析 TraceContext 和 Baggage 两种上下文传播机制 。而其中的 getter
就是用来从 HTTP 请求头中获取 span context 的方式 。
当然最后我们还需要在 WebMvcConfig
中注册该拦截器,代码如下所示:
// src/main/java/com/youdianzhishi/orderservice/config/WebMvcConfig.javapackage com.youdianzhishi.orderservice.config;// ......@Configuration@Order(4)public class WebMvcConfig implements WebMvcConfigurer { @Autowired private TokenInterceptor tokenInterceptor; @Autowired private OpenTelemetryInterceptor otelCtxInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(otelCtxInterceptor) .addPathPatterns("/api/orders/**"); registry.addInterceptor(tokenInterceptor) .addPathPatterns("/api/orders/**") // 指定拦截器应该应用的路径模式 .excludePathPatterns("/api/login", "/api/register"); // 指定应该排除的路径模式 }}
这样当我们在请求 /api/orders/**
下面的接口时,就可以从请求属性中获取父级的 span context 了 。
现在我们重新修改 getAllOrders
处理器,代码如下所示:
@GetMappingpublic ResponseEntity<List<OrderDto>> getAllOrders(HttpServletRequest request) { // 从请求属性中获取 Span Span span = (Span) request.getAttribute("currentSpan"); try { // 从拦截器中获取用户信息 User user = (User) request.getAttribute("user"); // 要根据 orderDate 倒序排列 List<Order> orders = orderRepository.findByUserIdOrderByOrderDateDesc(user.getId()); // 将Order转换为OrderDto List<OrderDto> orderDtos = orders.stream().map(order -> { try { return order.toOrderDto(webClient); } catch (Exception e) { throw new RuntimeException(e); } }).collect(Collectors.toList()); span.setAttribute("user_id", user.getId()); span.setAttribute("order_count", orders.size()); return new ResponseEntity<>(orderDtos, HttpStatus.OK); } catch (Exception e) { // 记录 Span 错误 span.recordException(e).setStatus(StatusCode.ERROR, e.getMessage()); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } finally { // 记录 Span 结束时间 span.end(); }}
推荐阅读
- 通过诗经楚辞取的公司名字
- 动量定理的应用 动量定理的应用视频讲解
- 深入浅出、玩转Java多线程
- 揭秘十个必知的 JavaScript 3D 库,打造顶级3D炫酷效果!
- 图灵测试已死!ChatGPT通过人类考试也不算,超强AI评估新秀「逻辑谜题」
- 王者荣耀的段位排行榜是通过Redis实现的?
- 我不再写Javascript了
- Java 单元测试及常用语句
- 构建高效的Java网络应用,体验秒级响应
- 谷歌推出 AlloyDB AI,帮助开发者创建生成式 AI 应用