feat(bugcollect): 更新 API 端点并改进数据结构
- 将 Android SDK 的 mapping 上传端点从 /log/v1/sourcemaps/upload 更改为 /bugcollect/v1/sourcemaps/upload - 将 RN SDK 的 API 端点从 /log/v1/ 统一更改为 /bugcollect/v1/ - 在 LogQueue.ts 的请求体中添加 sentAt 时间戳和 SDK 信息 - 重构 BugCollect.ts 中的事件结构,将 appVersion 重命名为 release,添加 environment 和 sdk 字段 - 将 JS 错误上报的类型从 js_error 改为 issue,并调整错误级别分类 - 为 warn 和 info 方法添加完整的 issue 事件结构 - 在 types.ts 中添加新的数据类型定义,包括 Level、Platform、SdkInfo、ExceptionInfo 等 - 为 IssueEvent 添加详细的异常信息结构,包括类型、值和堆栈跟踪 - 添加完整的错误收集 API v1 规范审阅报告文档 - 在数据库迁移脚本中为日志表添加新字段,包括级别、环境、设备信息、SDK 信息等
这个提交包含在:
父节点
639e9bcc26
当前提交
76099d897e
@ -22,7 +22,7 @@ function withBugCollect(metroConfig) {
|
||||
// TODO: 补全 SourceMap 上传逻辑
|
||||
// 1. 读取 .xuqmconfig 或 xuqm.config.js 获取 bugCollectApiUrl
|
||||
// 2. 读取 sourceMapUrl 对应的 .map 文件
|
||||
// 3. 上传到 bugCollectApiUrl/log/v1/sourcemaps/upload
|
||||
// 3. 上传到 bugCollectApiUrl/bugcollect/v1/sourcemaps/upload
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
@ -66,13 +66,15 @@ export const BugCollect = {
|
||||
const event: LogEvent = {
|
||||
type: 'event',
|
||||
name,
|
||||
properties: properties ? { ...properties, environment: _environment } : { environment: _environment },
|
||||
properties,
|
||||
timestamp: Date.now(),
|
||||
userId: getUserId() ?? undefined,
|
||||
sessionId: _sessionId,
|
||||
appKey: getConfig().appKey,
|
||||
platform: _getPlatform(),
|
||||
appVersion: _getAppVersion(),
|
||||
release: _getAppVersion(),
|
||||
environment: _environment,
|
||||
sdk: { name: 'bugcollect.rn', version: '0.2.0' },
|
||||
}
|
||||
_enqueue(event)
|
||||
FunnelTracker.track(name, properties)
|
||||
@ -83,17 +85,23 @@ export const BugCollect = {
|
||||
if (!isInitialized()) return
|
||||
const err = error instanceof Error ? error : new Error(String(error))
|
||||
const issue: IssueEvent = {
|
||||
type: 'js_error',
|
||||
message: err.message,
|
||||
stack: err.stack,
|
||||
fingerprint: computeFingerprint('js_error', err.message, err.stack),
|
||||
type: 'issue',
|
||||
level: 'error',
|
||||
platform: _getPlatform(),
|
||||
fingerprint: computeFingerprint('error', err.message, err.stack),
|
||||
timestamp: Date.now(),
|
||||
appKey: getConfig().appKey,
|
||||
release: _getAppVersion(),
|
||||
environment: _environment,
|
||||
exception: {
|
||||
type: err.name ?? 'Error',
|
||||
value: err.message,
|
||||
stacktrace: err.stack,
|
||||
},
|
||||
userId: getUserId() ?? undefined,
|
||||
sessionId: _sessionId,
|
||||
appKey: getConfig().appKey,
|
||||
platform: _getPlatform(),
|
||||
appVersion: _getAppVersion(),
|
||||
metadata: metadata ? { ...metadata, environment: _environment } : { environment: _environment },
|
||||
tags: metadata,
|
||||
sdk: { name: 'bugcollect.rn', version: '0.2.0' },
|
||||
}
|
||||
_enqueue(issue)
|
||||
},
|
||||
@ -101,13 +109,51 @@ export const BugCollect = {
|
||||
/** Log a warning (if log level allows). */
|
||||
warn(message: string, metadata?: Record<string, unknown>): void {
|
||||
if (_levelNum(_logLevel) > _levelNum('warn')) return
|
||||
BugCollect.captureError(new Error(message), { ...metadata, level: 'warn' })
|
||||
if (!isInitialized()) return
|
||||
const issue: IssueEvent = {
|
||||
type: 'issue',
|
||||
level: 'warning',
|
||||
platform: _getPlatform(),
|
||||
fingerprint: computeFingerprint('warning', message),
|
||||
timestamp: Date.now(),
|
||||
appKey: getConfig().appKey,
|
||||
release: _getAppVersion(),
|
||||
environment: _environment,
|
||||
exception: {
|
||||
type: 'Warning',
|
||||
value: message,
|
||||
},
|
||||
userId: getUserId() ?? undefined,
|
||||
sessionId: _sessionId,
|
||||
tags: metadata,
|
||||
sdk: { name: 'bugcollect.rn', version: '0.2.0' },
|
||||
}
|
||||
_enqueue(issue)
|
||||
},
|
||||
|
||||
/** Log an informational event (if log level allows). */
|
||||
info(message: string, metadata?: Record<string, unknown>): void {
|
||||
if (_levelNum(_logLevel) > _levelNum('info')) return
|
||||
BugCollect.event('__log_info', { message, ...metadata })
|
||||
if (!isInitialized()) return
|
||||
const issue: IssueEvent = {
|
||||
type: 'issue',
|
||||
level: 'info',
|
||||
platform: _getPlatform(),
|
||||
fingerprint: computeFingerprint('info', message),
|
||||
timestamp: Date.now(),
|
||||
appKey: getConfig().appKey,
|
||||
release: _getAppVersion(),
|
||||
environment: _environment,
|
||||
exception: {
|
||||
type: 'Info',
|
||||
value: message,
|
||||
},
|
||||
userId: getUserId() ?? undefined,
|
||||
sessionId: _sessionId,
|
||||
tags: metadata,
|
||||
sdk: { name: 'bugcollect.rn', version: '0.2.0' },
|
||||
}
|
||||
_enqueue(issue)
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@ -35,8 +35,8 @@ export class LogQueue {
|
||||
const events = batch.filter(e => e.type === 'event')
|
||||
|
||||
try {
|
||||
if (issues.length > 0) await this._post('/log/v1/issues/batch', issues)
|
||||
if (events.length > 0) await this._post('/log/v1/events/batch', events)
|
||||
if (issues.length > 0) await this._post('/bugcollect/v1/issues/batch', issues)
|
||||
if (events.length > 0) await this._post('/bugcollect/v1/events/batch', events)
|
||||
this.retryCount = 0
|
||||
} catch {
|
||||
this.retryCount++
|
||||
@ -56,7 +56,7 @@ export class LogQueue {
|
||||
}
|
||||
|
||||
private async _post(path: string, data: BugCollectEvent[]): Promise<void> {
|
||||
const body = JSON.stringify({ events: data })
|
||||
const body = JSON.stringify({ sentAt: new Date().toISOString(), sdk: { name: 'bugcollect.rn', version: '0.2.0' }, events: data })
|
||||
const res = await fetch(`${this.cfg.bugCollectApiUrl}${path}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
||||
@ -1,5 +1,30 @@
|
||||
export type LogLevel = 'debug' | 'info' | 'warn' | 'error'
|
||||
export type Environment = 'development' | 'staging' | 'production'
|
||||
export type Level = 'fatal' | 'error' | 'warning' | 'info' | 'debug'
|
||||
export type Platform = 'ios' | 'android' | 'harmonyos' | 'web' | 'react-native'
|
||||
|
||||
export interface SdkInfo {
|
||||
name: string
|
||||
version: string
|
||||
}
|
||||
|
||||
export interface ExceptionInfo {
|
||||
type: string
|
||||
value: string
|
||||
stacktrace?: string
|
||||
}
|
||||
|
||||
export interface UserInfo {
|
||||
id?: string
|
||||
}
|
||||
|
||||
export interface DeviceInfo {
|
||||
name?: string
|
||||
model?: string
|
||||
manufacturer?: string
|
||||
osName?: string
|
||||
osVersion?: string
|
||||
}
|
||||
|
||||
export interface LogEvent {
|
||||
type: 'event'
|
||||
@ -9,24 +34,37 @@ export interface LogEvent {
|
||||
userId?: string
|
||||
sessionId: string
|
||||
appKey: string
|
||||
platform: 'ios' | 'android'
|
||||
appVersion: string
|
||||
fingerprint?: string
|
||||
platform: Platform
|
||||
release: string
|
||||
environment?: Environment
|
||||
user?: UserInfo
|
||||
device?: DeviceInfo
|
||||
sdk?: SdkInfo
|
||||
}
|
||||
|
||||
export interface IssueEvent {
|
||||
type: 'js_error' | 'native_crash' | 'api_error' | 'warning'
|
||||
message: string
|
||||
stack?: string
|
||||
type: 'issue'
|
||||
level: Level
|
||||
platform: Platform
|
||||
fingerprint: string
|
||||
count?: number
|
||||
timestamp: number
|
||||
userId?: string
|
||||
sessionId: string
|
||||
appKey: string
|
||||
platform: 'ios' | 'android'
|
||||
appVersion: string
|
||||
metadata?: Record<string, unknown>
|
||||
release: string
|
||||
environment?: Environment
|
||||
exception?: ExceptionInfo
|
||||
userId?: string
|
||||
sessionId?: string
|
||||
user?: UserInfo
|
||||
device?: DeviceInfo
|
||||
tags?: Record<string, unknown>
|
||||
sdk?: SdkInfo
|
||||
}
|
||||
|
||||
export type BugCollectEvent = LogEvent | IssueEvent
|
||||
|
||||
/** Envelope sent in the POST body */
|
||||
export interface BugCollectEnvelope {
|
||||
sentAt?: string
|
||||
sdk?: SdkInfo
|
||||
events: BugCollectEvent[]
|
||||
}
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户