开发者集成指南¶
本文档为开发者提供 JAiRouter 分布式追踪系统的集成指南和 API 参考。
核心 API¶
TracingService¶
追踪服务的核心接口,提供 Span 管理和追踪上下文操作。
主要方法¶
@Component
public class TracingService {
/**
* 创建根 Span
* @param operation 操作名称
* @return Span 对象
*/
public Span createRootSpan(String operation);
/**
* 创建子 Span
* @param operation 操作名称
* @return Span 对象
*/
public Span createChildSpan(String operation);
/**
* 在当前上下文中执行操作
* @param operation 操作名称
* @param function 执行函数
* @return 执行结果
*/
public <T> T withSpan(String operation, Function<Span, T> function);
/**
* 添加标签到当前 Span
* @param key 标签键
* @param value 标签值
*/
public void addTag(String key, String value);
/**
* 记录事件到当前 Span
* @param event 事件名称
*/
public void addEvent(String event);
/**
* 记录事件到当前 Span(带属性)
* @param event 事件名称
* @param attributes 事件属性
*/
public void addEvent(String event, Map<String, Object> attributes);
/**
* 记录异常到当前 Span
* @param throwable 异常对象
*/
public void recordException(Throwable throwable);
}
TracingContext¶
追踪上下文管理器,用于获取和操作当前线程的追踪信息。
public class TracingContext {
/**
* 获取当前上下文
* @return TracingContext 对象
*/
public static Optional<TracingContext> current();
/**
* 获取当前 Trace ID
* @return Trace ID
*/
public static String getCurrentTraceId();
/**
* 获取当前 Span ID
* @return Span ID
*/
public static String getCurrentSpanId();
/**
* 添加属性到当前上下文
* @param key 属性键
* @param value 属性值
*/
public void addAttribute(String key, Object value);
/**
* 获取属性值
* @param key 属性键
* @return 属性值
*/
public Object getAttribute(String key);
}
自定义追踪组件¶
实现自定义采样策略¶
@Component
public class CustomSamplingStrategy implements SamplingStrategy {
@Override
public boolean shouldSample(SamplingContext context) {
// 自定义采样逻辑
String userId = context.getAttribute("userId");
String operation = context.getOperation();
// VIP 用户 100% 采样
if (isVipUser(userId)) {
return true;
}
// 关键操作 50% 采样
if (isCriticalOperation(operation)) {
return Math.random() < 0.5;
}
// 默认 10% 采样
return Math.random() < 0.1;
}
@Override
public String getName() {
return "custom";
}
}
创建自定义导出器¶
@Component
public class CustomExporter implements SpanExporter {
private final HttpClient httpClient;
public CustomExporter(HttpClient httpClient) {
this.httpClient = httpClient;
}
@Override
public CompletableResultCode export(Collection<SpanData> spans) {
try {
// 自定义导出逻辑
List<CustomSpan> customSpans = spans.stream()
.map(this::convertToCustomSpan)
.collect(Collectors.toList());
// 发送到自定义后端
HttpResponse response = httpClient.post("/traces")
.body(customSpans)
.execute();
return response.isSuccess() ?
CompletableResultCode.ofSuccess() :
CompletableResultCode.ofFailure();
} catch (Exception e) {
log.error("导出追踪数据失败", e);
return CompletableResultCode.ofFailure();
}
}
@Override
public CompletableResultCode flush() {
// 刷新逻辑
return CompletableResultCode.ofSuccess();
}
@Override
public CompletableResultCode shutdown() {
// 关闭逻辑
return CompletableResultCode.ofSuccess();
}
private CustomSpan convertToCustomSpan(SpanData spanData) {
// 转换逻辑
return new CustomSpan();
}
}
注解支持¶
@TraceSpan 注解¶
用于自动创建 Span 的方法级注解。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TraceSpan {
/**
* Span 名称
*/
String name() default "";
/**
* 标签键值对
*/
String[] tags() default {};
/**
* 是否记录异常
*/
boolean recordException() default true;
}
使用示例:
@Service
public class UserService {
@TraceSpan(name = "user-authentication", tags = {"operation", "login"})
public User authenticate(String username, String password) {
// 认证逻辑
return userRepository.findByUsername(username);
}
@TraceSpan(name = "user-profile-update")
public void updateUserProfile(UserProfile profile) {
// 更新用户资料
userProfileRepository.save(profile);
}
}
@TraceAsync 注解¶
用于异步方法的追踪注解。
@RestController
public class AsyncController {
@Autowired
private AsyncService asyncService;
@TraceAsync("data-processing")
@PostMapping("/api/process")
public CompletableFuture<ProcessResult> processData(@RequestBody DataRequest request) {
return asyncService.processData(request);
}
}
响应式编程集成¶
Mono/Flux 追踪支持¶
@Component
public class ReactiveTracingService {
public <T> Mono<T> traceMono(String operation, Mono<T> mono) {
return Mono.defer(() -> {
Span span = tracingService.createChildSpan(operation);
return mono
.doOnSuccess(result -> {
span.addTag("result", "success");
span.end();
})
.doOnError(error -> {
span.recordException(error);
span.addTag("result", "error");
span.end();
});
});
}
public <T> Flux<T> traceFlux(String operation, Flux<T> flux) {
return Flux.defer(() -> {
Span span = tracingService.createChildSpan(operation);
AtomicLong count = new AtomicLong(0);
return flux
.doOnNext(item -> count.incrementAndGet())
.doOnComplete(() -> {
span.addTag("item.count", String.valueOf(count.get()));
span.addTag("result", "success");
span.end();
})
.doOnError(error -> {
span.recordException(error);
span.addTag("result", "error");
span.end();
});
});
}
}
使用示例:
@Service
public class DataService {
@Autowired
private ReactiveTracingService reactiveTracingService;
public Mono<DataResult> fetchData(String id) {
return reactiveTracingService.traceMono("fetch-data",
dataRepository.findById(id)
.map(this::transformData));
}
public Flux<DataItem> streamData() {
return reactiveTracingService.traceFlux("stream-data",
dataRepository.findAll()
.filter(this::isValidItem));
}
}
扩展和插件¶
创建自定义追踪拦截器¶
@Component
public class CustomTracingInterceptor implements TracingInterceptor {
@Override
public void preHandle(TracingContext context, Span span) {
// 请求前处理
span.addTag("custom.interceptor", "pre-handle");
// 添加自定义属性
String userAgent = getCurrentUserAgent();
if (userAgent != null) {
span.addTag("http.user_agent", userAgent);
}
}
@Override
public void postHandle(TracingContext context, Span span, Object result) {
// 响应后处理
if (result instanceof ResponseEntity) {
ResponseEntity<?> response = (ResponseEntity<?>) result;
span.addTag("http.status_code", String.valueOf(response.getStatusCodeValue()));
}
}
@Override
public void afterCompletion(TracingContext context, Span span, Exception ex) {
// 完成后处理
if (ex != null) {
span.recordException(ex);
}
span.end();
}
}
自定义指标收集器¶
@Component
public class CustomMetricsCollector {
private final MeterRegistry meterRegistry;
private final Counter customCounter;
private final Timer customTimer;
public CustomMetricsCollector(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.customCounter = Counter.builder("custom.tracing.operations")
.description("自定义追踪操作计数")
.register(meterRegistry);
this.customTimer = Timer.builder("custom.tracing.duration")
.description("自定义追踪操作耗时")
.register(meterRegistry);
}
public <T> T measureOperation(String operation, Supplier<T> supplier) {
customCounter.increment(1.0, "operation", operation);
return Timer.Sample.start(meterRegistry)
.stop(customTimer.tag("operation", operation));
}
}
测试支持¶
单元测试¶
@ExtendWith(MockitoExtension.class)
class TracingServiceTest {
@Mock
private SpanExporter spanExporter;
@InjectMocks
private TracingService tracingService;
@Test
void testCreateRootSpan() {
// Given
String operation = "test-operation";
// When
Span span = tracingService.createRootSpan(operation);
// Then
assertThat(span).isNotNull();
assertThat(span.getName()).isEqualTo(operation);
}
@Test
void testAddTag() {
// Given
Span span = tracingService.createRootSpan("test");
// When
tracingService.addTag("test.key", "test.value");
// Then
// 验证标签已添加到 Span
}
}
集成测试¶
@SpringBootTest
@AutoConfigureTestDatabase
class TracingIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private TracingService tracingService;
@Test
void testTracingIntegration() {
// Given
HttpHeaders headers = new HttpHeaders();
headers.set("X-Trace-Debug", "true");
HttpEntity<String> entity = new HttpEntity<>("{}", headers);
// When
ResponseEntity<String> response = restTemplate.exchange(
"/api/test", HttpMethod.POST, entity, String.class);
// Then
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
// 验证追踪数据已生成
verify(tracingService).createRootSpan(anyString());
}
}
最佳实践¶
1. Span 命名规范¶
// ✅ 好的命名
tracingService.createSpan("user-authentication");
tracingService.createSpan("database-query");
tracingService.createSpan("external-api-call");
// ❌ 避免的命名
tracingService.createSpan("op1");
tracingService.createSpan("doSomething");
2. 标签使用规范¶
// ✅ 有意义的标签
span.addTag("http.method", "POST");
span.addTag("user.id", userId);
span.addTag("business.operation", "payment");
// ❌ 避免的标签
span.addTag("tag1", "value");
span.addTag("data", largeObject.toString()); // 过大的值
3. 异常处理¶
// ✅ 正确的异常记录
try {
performOperation();
} catch (BusinessException e) {
span.recordException(e);
span.addTag("error.type", "business");
throw e;
}
// ❌ 避免记录敏感信息
try {
performOperation();
} catch (Exception e) {
span.addTag("error.details", e.getMessage()); // 可能包含敏感信息
throw e;
}
4. 性能考虑¶
// ✅ 高效的追踪
@TraceSpan("critical-operation")
public void criticalOperation() {
// 关键业务逻辑
}
// ❌ 避免在高频路径中过度追踪
@TraceSpan("high-frequency-op") // 可能影响性能
public void highFrequencyOperation() {
// 高频调用的方法
}