Solon v3.7.2

opentelemetry-solon-cloud-plugin [预览]

</> markdown
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>opentelemetry-solon-cloud-plugin</artifactId>
</dependency>

1、描述

(3.7.3-SNAPSHOT 后支持)分布式扩展插件。基于 opentelemetry 适配的 solon cloud 插件。可与支持 opentelemetry 规范的服务,一同提供链路跟踪支持。

2、配置示例

solon.app:
  name: "demoapp"
  group: "demo"

solon.cloud.opentelemetry:
  server: "http://localhost:4317"
  trace:
    enable: true                     #是否启用(默认:true)
    exclude: "/healthz,/_run/check/" #排除路径,多个以,号隔开

3、附带技能

支持 slf4j 日志框架的 MDC 变量(可以通过格式符获取,例:"%X{X-TraceId}"):

  • X-TraceId
  • X-SpanId

4、代码应用

  • 添加示例需要的依赖
<dependencies>
    <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-sdk</artifactId>
        <version>${opentelemetry.version}</version>
    </dependency>

    <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-exporter-otlp</artifactId>
        <version>${opentelemetry.version}</version>
    </dependency>
    
    <dependency>
        <groupId>io.opentelemetry.semconv</groupId>
        <artifactId>opentelemetry-semconv</artifactId>
        <version>${opentelemetry-semconv.version}</version>
    </dependency>
</dependencies>
  • 启用和配置跟踪器实现(仅供参考)
public class App {
    public static void main(String[] args) {
        Solon.start(App.class, args);
    }
}

@Configuration
public class DemoConfig {
    @Bean
    public Tracer tracer(OpenTelemetry openTelemetry) {
        return openTelemetry.getTracer(Solon.cfg().appName(), "1.0.0");
    }

    @Bean
    public OpenTelemetry openTelemetry(AppContext context) {
        CloudProps cloudProps = new CloudProps(context, "opentelemetry");

        // 1. 定义资源 (Resource),包含服务名称
        Resource serviceResource = Resource.getDefault()
                .toBuilder()
                .put(ServiceAttributes.SERVICE_NAME, Solon.cfg().appName())
                .put(ServiceAttributes.SERVICE_VERSION,"1.0.0")
                .build();

        // 2. 配置 Span Exporter (例如 OTLP/gRPC) //
        OtlpGrpcSpanExporter otlpExporter = OtlpGrpcSpanExporter.builder()
                // 默认连接到 http://localhost:4317 (OTLP Collector)
                .setEndpoint(cloudProps.getServer())
                .setTimeout(30, TimeUnit.SECONDS)
                .build();

        // 3. 配置 Span Processor (例如 BatchSpanProcessor)
        BatchSpanProcessor spanProcessor = BatchSpanProcessor.builder(otlpExporter)
                .setScheduleDelay(100, TimeUnit.MILLISECONDS)
                .build();

        // 4. 配置 Tracer Provider
        SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
                .setResource(serviceResource)
                .addSpanProcessor(spanProcessor)
                // 设置采样器 (Sampler.alwaysOn() 表示 100% 采样)
                .setSampler(Sampler.alwaysOn())
                .build();

        // 5. 构建 OpenTelemetry SDK 并注册为全局单例
        OpenTelemetrySdk openTelemetrySdk = OpenTelemetrySdk.builder()
                .setTracerProvider(tracerProvider)
                .buildAndRegisterGlobal();

        System.out.println("OpenTelemetry SDK initialized and set as global.");
        return openTelemetrySdk;
    }
}
  • 应用代码
// --  可以当它不存在得用
@Controller
public class TestController {
    @NamiClient
    UserService userService;
    
    @Inject
    OrderService orderService;

    @Mapping("/")
    public String hello(String name) {
        name = userService.getUser(name);

        return orderService.orderCreate(name, "1");
    }
}


import org.noear.solon.annotation.Component;
import org.noear.solon.cloud.telemetry.Spans;
import org.noear.solon.cloud.telemetry.annotation.Tracing;

//-- 通过注解增加业务链节点 ( @Tracing )
@Component
public class OrderService {
    @Tracing(name = "创建订单", tags = "订单=#{orderId}")
    public String orderCreate(String userName, String orderId) {
        //手动添加 tag
        Spans.active().setAttribute("用户", userName);

        return orderId;
    }
}

5、@Tracing 注意事项

  • 控制器或最终转为 Handler 的类可以不加(已由 Filter 全局处理了),加了会产生新的 Span

  • 修改当前 Span 的操作名

@Controller
public class TestController {

    @Mapping("/")
    public String hello(String name) {
        Spans.active().setOperationName("Hello");  //修改当前操作名
    
        return "Hello " + name;
    }
}
  • 添加在空接口上,一般会无效(比如:Mapper)。除非其底层有适配
  • 需加在代理的类上,不然拦截器不会生效。如:@Component 注解的类