refactor: @xuqm/rn-log → @xuqm/rn-bugcollect

- packages/log → packages/bugcollect
- XLog → BugCollect
- logApiUrl/logEnabled → bugCollectApiUrl/bugCollectEnabled
- withXuqmLog → withBugCollect
- typecheck 通过

Co-Authored-By: Claude <noreply@anthropic.com>
这个提交包含在:
XuqmGroup 2026-06-16 17:39:18 +08:00
父节点 a53438a3f0
当前提交 57579d2871
共有 19 个文件被更改,包括 44 次插入44 次删除

查看文件

@ -29,7 +29,7 @@
"@xuqm/rn-common": ">=0.4.0",
"@xuqm/rn-im": ">=0.2.0",
"@xuqm/rn-license": ">=0.3.0",
"@xuqm/rn-log": ">=0.1.0",
"@xuqm/rn-bugcollect": ">=0.1.0",
"@xuqm/rn-push": ">=0.2.0",
"@xuqm/rn-update": ">=0.4.0",
"@xuqm/rn-xwebview": ">=0.2.0"

查看文件

@ -1,11 +1,11 @@
'use strict'
/**
* withXuqmLog(metroConfig)
* withBugCollect(metroConfig)
* 包裹 Metro 配置 Release 包时自动上传 SourceMap
* 当前为存根实现后续补全 SourceMap 上传逻辑
*/
function withXuqmLog(metroConfig) {
function withBugCollect(metroConfig) {
return {
...metroConfig,
serializer: {
@ -20,9 +20,9 @@ function withXuqmLog(metroConfig) {
// 仅 Release 包上传 SourceMapdev 模式跳过)
if (!options.dev) {
// TODO: 补全 SourceMap 上传逻辑
// 1. 读取 .xuqmconfig 或 xuqm.config.js 获取 logApiUrl
// 1. 读取 .xuqmconfig 或 xuqm.config.js 获取 bugCollectApiUrl
// 2. 读取 sourceMapUrl 对应的 .map 文件
// 3. 上传到 logApiUrl/log/v1/sourcemaps/upload
// 3. 上传到 bugCollectApiUrl/log/v1/sourcemaps/upload
}
return result
@ -31,4 +31,4 @@ function withXuqmLog(metroConfig) {
}
}
module.exports = { withXuqmLog }
module.exports = { withBugCollect }

查看文件

@ -1,5 +1,5 @@
{
"name": "@xuqm/rn-log",
"name": "@xuqm/rn-bugcollect",
"version": "0.1.0",
"description": "XuqmGroup RN SDK — log collection, error tracking, funnel analysis",
"license": "UNLICENSED",

查看文件

@ -4,7 +4,7 @@ import { LogQueue } from './queue/LogQueue'
import { ErrorCapture } from './capture/ErrorCapture'
import { computeFingerprint } from './fingerprint'
import { FunnelTracker } from './funnel/FunnelTracker'
import type { LogLevel, Environment, IssueEvent, LogEvent, XLogEvent } from './types'
import type { LogLevel, Environment, IssueEvent, LogEvent, BugCollectEvent } from './types'
// ─── Internal state ───────────────────────────────────────────────────────────
@ -35,18 +35,18 @@ function _getAppVersion(): string {
return typeof v === 'string' ? v : String(v ?? '0.0.0')
}
function _enqueue(event: XLogEvent): void {
function _enqueue(event: BugCollectEvent): void {
if (!_queue) {
const cfg = getConfig()
if (!cfg.logApiUrl || !cfg.logEnabled) return
_queue = new LogQueue({ logApiUrl: cfg.logApiUrl, appKey: cfg.appKey })
if (!cfg.bugCollectApiUrl || !cfg.bugCollectEnabled) return
_queue = new LogQueue({ bugCollectApiUrl: cfg.bugCollectApiUrl, appKey: cfg.appKey })
}
void _queue.push(event)
}
// ─── XLog public API ──────────────────────────────────────────────────────────
// ─── BugCollect public API ────────────────────────────────────────────────────
export const XLog = {
export const BugCollect = {
/** Set the minimum log level. Events below this level are discarded. */
setLogLevel(level: LogLevel): void {
_logLevel = level
@ -101,13 +101,13 @@ export const XLog = {
/** Log a warning (if log level allows). */
warn(message: string, metadata?: Record<string, unknown>): void {
if (_levelNum(_logLevel) > _levelNum('warn')) return
XLog.captureError(new Error(message), { ...metadata, level: 'warn' })
BugCollect.captureError(new Error(message), { ...metadata, level: 'warn' })
},
/** Log an informational event (if log level allows). */
info(message: string, metadata?: Record<string, unknown>): void {
if (_levelNum(_logLevel) > _levelNum('info')) return
XLog.event('__log_info', { message, ...metadata })
BugCollect.event('__log_info', { message, ...metadata })
},
/**
@ -117,7 +117,7 @@ export const XLog = {
startCapture(): void {
if (_errorCaptureStarted) return
_errorCaptureStarted = true
ErrorCapture.start(XLog.captureError.bind(XLog))
ErrorCapture.start(BugCollect.captureError.bind(BugCollect))
},
/** Define a funnel for step-by-step conversion tracking. */

查看文件

@ -1,6 +1,6 @@
/**
* ErrorCapture hooks into the RN global error handler and unhandled promise
* rejections to automatically forward errors to XLog.captureError.
* rejections to automatically forward errors to BugCollect.captureError.
*/
// React Native exposes ErrorUtils on the global object

查看文件

@ -26,7 +26,7 @@ export const FunnelTracker = {
},
/**
* Called automatically by XLog.event for each event.
* Called automatically by BugCollect.event for each event.
* Advances any funnel whose next expected step matches eventName.
*/
track(eventName: string, _properties?: Record<string, unknown>): void {

查看文件

@ -0,0 +1,2 @@
export { BugCollect } from './BugCollect'
export type { LogLevel, Environment, LogEvent, IssueEvent, BugCollectEvent } from './types'

查看文件

@ -1,9 +1,9 @@
/**
* HttpInterceptor wraps the global fetch to automatically report
* HTTP error responses (4xx / 5xx) through XLog.captureError.
* HTTP error responses (4xx / 5xx) through BugCollect.captureError.
*
* Usage:
* HttpInterceptor.start(XLog.captureError.bind(XLog))
* HttpInterceptor.start(BugCollect.captureError.bind(BugCollect))
*/
type OnError = (error: unknown, meta?: Record<string, unknown>) => void

查看文件

@ -1,7 +1,7 @@
import AsyncStorage from '@react-native-async-storage/async-storage'
import type { XLogEvent } from '../types'
import type { BugCollectEvent } from '../types'
const QUEUE_KEY = '@xuqm_log:queue'
const QUEUE_KEY = '@xuqm_bugcollect:queue'
const BATCH_SIZE = 30
const FLUSH_INTERVAL_MS = 10_000 // 10 seconds
const MAX_QUEUE_SIZE = 500
@ -11,13 +11,13 @@ export class LogQueue {
private flushTimer: ReturnType<typeof setInterval> | null = null
private retryCount = 0
constructor(private cfg: { logApiUrl: string; appKey: string }) {
constructor(private cfg: { bugCollectApiUrl: string; appKey: string }) {
this.flushTimer = setInterval(() => {
void this.flush()
}, FLUSH_INTERVAL_MS)
}
async push(event: XLogEvent): Promise<void> {
async push(event: BugCollectEvent): Promise<void> {
const queue = await this._read()
if (queue.length >= MAX_QUEUE_SIZE) queue.shift() // drop oldest
queue.push(event)
@ -55,9 +55,9 @@ export class LogQueue {
}
}
private async _post(path: string, data: XLogEvent[]): Promise<void> {
private async _post(path: string, data: BugCollectEvent[]): Promise<void> {
const body = JSON.stringify({ events: data })
const res = await fetch(`${this.cfg.logApiUrl}${path}`, {
const res = await fetch(`${this.cfg.bugCollectApiUrl}${path}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@ -66,16 +66,16 @@ export class LogQueue {
body,
})
if (!res.ok) {
throw new Error(`[XuqmLog] Upload failed: ${res.status}`)
throw new Error(`[BugCollect] Upload failed: ${res.status}`)
}
}
private async _read(): Promise<XLogEvent[]> {
private async _read(): Promise<BugCollectEvent[]> {
const raw = await AsyncStorage.getItem(QUEUE_KEY)
return raw ? (JSON.parse(raw) as XLogEvent[]) : []
return raw ? (JSON.parse(raw) as BugCollectEvent[]) : []
}
private async _write(queue: XLogEvent[]): Promise<void> {
private async _write(queue: BugCollectEvent[]): Promise<void> {
await AsyncStorage.setItem(QUEUE_KEY, JSON.stringify(queue))
}
}

查看文件

@ -29,4 +29,4 @@ export interface IssueEvent {
metadata?: Record<string, unknown>
}
export type XLogEvent = LogEvent | IssueEvent
export type BugCollectEvent = LogEvent | IssueEvent

查看文件

@ -4,7 +4,7 @@ type ApiErrorHandler = (error: RequestError) => void
let _handler: ApiErrorHandler | null = null
/** 注册全局 API 错误处理器(宿主在初始化时注入,通常将错误转发给 rn-log)。*/
/** 注册全局 API 错误处理器(宿主在初始化时注入,通常将错误转发给 rn-bugcollect)。*/
export function setGlobalApiErrorHandler(handler: ApiErrorHandler): void {
_handler = handler
}

查看文件

@ -15,9 +15,9 @@ export interface XuqmConfig {
imEnabled: boolean
pushEnabled: boolean
licenseEnabled: boolean
// 日志服务rn-log 使用)
logApiUrl: string
logEnabled: boolean
// 崩溃采集服务rn-bugcollect 使用)
bugCollectApiUrl: string
bugCollectEnabled: boolean
}
export interface XuqmUserInfo {
@ -47,8 +47,8 @@ export interface XuqmRemoteConfig {
imEnabled?: boolean
pushEnabled?: boolean
licenseEnabled?: boolean
logApiUrl?: string
logEnabled?: boolean
bugCollectApiUrl?: string
bugCollectEnabled?: boolean
}
export function initConfigFromRemote(
@ -66,8 +66,8 @@ export function initConfigFromRemote(
imEnabled: remote.imEnabled ?? !!remote.imWsUrl,
pushEnabled: remote.pushEnabled ?? true,
licenseEnabled: remote.licenseEnabled ?? false,
logApiUrl: remote.logApiUrl ?? '',
logEnabled: remote.logEnabled ?? false,
bugCollectApiUrl: remote.bugCollectApiUrl ?? '',
bugCollectEnabled: remote.bugCollectEnabled ?? false,
}
}

查看文件

@ -63,8 +63,8 @@ export const XuqmSDK = {
imEnabled: remote.imEnabled as boolean | undefined,
pushEnabled: remote.pushEnabled as boolean | undefined,
licenseEnabled: remote.licenseEnabled as boolean | undefined,
logApiUrl: remote.logApiUrl as string | undefined,
logEnabled: remote.logEnabled as boolean | undefined,
bugCollectApiUrl: remote.bugCollectApiUrl as string | undefined,
bugCollectEnabled: remote.bugCollectEnabled as boolean | undefined,
})
configureHttp({
baseUrl: (remote.apiUrl as string | undefined) ?? baseUrl,

查看文件

@ -1,2 +0,0 @@
export { XLog } from './XLog'
export type { LogLevel, Environment, LogEvent, IssueEvent, XLogEvent } from './types'

查看文件

@ -12,7 +12,7 @@
"@xuqm/rn-common": ["packages/common/src"],
"@xuqm/rn-im": ["packages/im/src"],
"@xuqm/rn-license": ["packages/license/src"],
"@xuqm/rn-log": ["packages/log/src"],
"@xuqm/rn-bugcollect": ["packages/bugcollect/src"],
"@xuqm/rn-push": ["packages/push/src"],
"@xuqm/rn-update": ["packages/update/src"],
"@xuqm/rn-xwebview": ["packages/xwebview/src"]