feat: 集成符号化服务 - 实现 triggerSymbolicationAsync
- 注入 SourcemapService 到 LogService - 实现 triggerSymbolicationAsync 调用符号化服务 - 支持 RN/Android/iOS/Flutter 堆栈符号化 - 新增 symbolicator.url 配置 Co-Authored-By: Claude <noreply@anthropic.com>
这个提交包含在:
父节点
064e3e3223
当前提交
a8ad342336
@ -31,19 +31,25 @@ public class LogService {
|
||||
private final LogIssueUserRepository issueUserRepository;
|
||||
private final LogEventRepository eventRepository;
|
||||
private final WebhookService webhookService;
|
||||
private final SourcemapService sourcemapService;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@org.springframework.beans.factory.annotation.Value("${symbolicator.url:http://xuqm-symbolicator:3000}")
|
||||
private String symbolicatorUrl;
|
||||
|
||||
public LogService(LogIssueRepository issueRepository,
|
||||
LogIssueEventRepository issueEventRepository,
|
||||
LogIssueUserRepository issueUserRepository,
|
||||
LogEventRepository eventRepository,
|
||||
WebhookService webhookService,
|
||||
SourcemapService sourcemapService,
|
||||
ObjectMapper objectMapper) {
|
||||
this.issueRepository = issueRepository;
|
||||
this.issueEventRepository = issueEventRepository;
|
||||
this.issueUserRepository = issueUserRepository;
|
||||
this.eventRepository = eventRepository;
|
||||
this.webhookService = webhookService;
|
||||
this.sourcemapService = sourcemapService;
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@ -149,6 +155,79 @@ public class LogService {
|
||||
@Async
|
||||
void triggerSymbolicationAsync(Long issueId, String appKey, String platform, String release) {
|
||||
log.debug("Symbolication triggered issueId={} appKey={} platform={} release={}", issueId, appKey, platform, release);
|
||||
|
||||
// 查找 sourcemap 文件
|
||||
String storageKey = sourcemapService.findSourceMap(appKey, platform, release, "index");
|
||||
if (storageKey == null) {
|
||||
log.debug("No sourcemap found for appKey={} platform={} release={}", appKey, platform, release);
|
||||
return;
|
||||
}
|
||||
|
||||
// 查找事件
|
||||
LogIssueEventEntity event = issueEventRepository.findById(issueId).orElse(null);
|
||||
if (event == null || event.getStack() == null || event.getStack().isBlank()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 读取 sourcemap 内容
|
||||
String sourcemapContent = sourcemapService.readSourceMapContent(storageKey);
|
||||
if (sourcemapContent == null) {
|
||||
log.warn("Failed to read sourcemap content for storageKey={}", storageKey);
|
||||
return;
|
||||
}
|
||||
|
||||
// 确定平台类型
|
||||
String symbolicatePlatform = mapPlatform(platform);
|
||||
|
||||
// 调用符号化服务
|
||||
String symbolicated = callSymbolicator(symbolicatePlatform, event.getStack(), sourcemapContent);
|
||||
if (symbolicated != null && !symbolicated.equals(event.getStack())) {
|
||||
event.setStackSymbolicated(symbolicated);
|
||||
issueEventRepository.save(event);
|
||||
log.info("Symbolicated issueId={} platform={}", issueId, platform);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Symbolication failed for issueId={}: {}", issueId, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private String mapPlatform(String platform) {
|
||||
if (platform == null) return "rn";
|
||||
return switch (platform.toLowerCase()) {
|
||||
case "android" -> "android";
|
||||
case "ios" -> "ios";
|
||||
case "flutter" -> "flutter";
|
||||
default -> "rn"; // RN/Electron/Vue3 都使用 JS sourcemap
|
||||
};
|
||||
}
|
||||
|
||||
private String callSymbolicator(String platform, String stacktrace, String sourcemapContent) {
|
||||
try {
|
||||
org.springframework.web.client.RestTemplate restTemplate = new org.springframework.web.client.RestTemplate();
|
||||
java.util.Map<String, Object> request = java.util.Map.of(
|
||||
"platform", platform,
|
||||
"stacktrace", stacktrace,
|
||||
"sourcemap", sourcemapContent
|
||||
);
|
||||
|
||||
org.springframework.http.HttpHeaders headers = new org.springframework.http.HttpHeaders();
|
||||
headers.setContentType(org.springframework.http.MediaType.APPLICATION_JSON);
|
||||
org.springframework.http.HttpEntity<java.util.Map<String, Object>> entity = new org.springframework.http.HttpEntity<>(request, headers);
|
||||
|
||||
java.util.Map response = restTemplate.postForObject(
|
||||
symbolicatorUrl + "/api/symbolicate",
|
||||
entity,
|
||||
java.util.Map.class
|
||||
);
|
||||
|
||||
if (response != null && Boolean.TRUE.equals(response.get("success"))) {
|
||||
return (String) response.get("symbolicated");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Symbolicator service call failed: {}", e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户