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-common": ">=0.4.0",
"@xuqm/rn-im": ">=0.2.0", "@xuqm/rn-im": ">=0.2.0",
"@xuqm/rn-license": ">=0.3.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-push": ">=0.2.0",
"@xuqm/rn-update": ">=0.4.0", "@xuqm/rn-update": ">=0.4.0",
"@xuqm/rn-xwebview": ">=0.2.0" "@xuqm/rn-xwebview": ">=0.2.0"

查看文件

@ -1,11 +1,11 @@
'use strict' 'use strict'
/** /**
* withXuqmLog(metroConfig) * withBugCollect(metroConfig)
* 包裹 Metro 配置 Release 包时自动上传 SourceMap * 包裹 Metro 配置 Release 包时自动上传 SourceMap
* 当前为存根实现后续补全 SourceMap 上传逻辑 * 当前为存根实现后续补全 SourceMap 上传逻辑
*/ */
function withXuqmLog(metroConfig) { function withBugCollect(metroConfig) {
return { return {
...metroConfig, ...metroConfig,
serializer: { serializer: {
@ -20,9 +20,9 @@ function withXuqmLog(metroConfig) {
// 仅 Release 包上传 SourceMapdev 模式跳过) // 仅 Release 包上传 SourceMapdev 模式跳过)
if (!options.dev) { if (!options.dev) {
// TODO: 补全 SourceMap 上传逻辑 // TODO: 补全 SourceMap 上传逻辑
// 1. 读取 .xuqmconfig 或 xuqm.config.js 获取 logApiUrl // 1. 读取 .xuqmconfig 或 xuqm.config.js 获取 bugCollectApiUrl
// 2. 读取 sourceMapUrl 对应的 .map 文件 // 2. 读取 sourceMapUrl 对应的 .map 文件
// 3. 上传到 logApiUrl/log/v1/sourcemaps/upload // 3. 上传到 bugCollectApiUrl/log/v1/sourcemaps/upload
} }
return result 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", "version": "0.1.0",
"description": "XuqmGroup RN SDK — log collection, error tracking, funnel analysis", "description": "XuqmGroup RN SDK — log collection, error tracking, funnel analysis",
"license": "UNLICENSED", "license": "UNLICENSED",

查看文件

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

查看文件

@ -1,6 +1,6 @@
/** /**
* ErrorCapture hooks into the RN global error handler and unhandled promise * 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 // 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. * Advances any funnel whose next expected step matches eventName.
*/ */
track(eventName: string, _properties?: Record<string, unknown>): void { 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 * 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: * Usage:
* HttpInterceptor.start(XLog.captureError.bind(XLog)) * HttpInterceptor.start(BugCollect.captureError.bind(BugCollect))
*/ */
type OnError = (error: unknown, meta?: Record<string, unknown>) => void type OnError = (error: unknown, meta?: Record<string, unknown>) => void

查看文件

@ -1,7 +1,7 @@
import AsyncStorage from '@react-native-async-storage/async-storage' 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 BATCH_SIZE = 30
const FLUSH_INTERVAL_MS = 10_000 // 10 seconds const FLUSH_INTERVAL_MS = 10_000 // 10 seconds
const MAX_QUEUE_SIZE = 500 const MAX_QUEUE_SIZE = 500
@ -11,13 +11,13 @@ export class LogQueue {
private flushTimer: ReturnType<typeof setInterval> | null = null private flushTimer: ReturnType<typeof setInterval> | null = null
private retryCount = 0 private retryCount = 0
constructor(private cfg: { logApiUrl: string; appKey: string }) { constructor(private cfg: { bugCollectApiUrl: string; appKey: string }) {
this.flushTimer = setInterval(() => { this.flushTimer = setInterval(() => {
void this.flush() void this.flush()
}, FLUSH_INTERVAL_MS) }, FLUSH_INTERVAL_MS)
} }
async push(event: XLogEvent): Promise<void> { async push(event: BugCollectEvent): Promise<void> {
const queue = await this._read() const queue = await this._read()
if (queue.length >= MAX_QUEUE_SIZE) queue.shift() // drop oldest if (queue.length >= MAX_QUEUE_SIZE) queue.shift() // drop oldest
queue.push(event) 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 body = JSON.stringify({ events: data })
const res = await fetch(`${this.cfg.logApiUrl}${path}`, { const res = await fetch(`${this.cfg.bugCollectApiUrl}${path}`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -66,16 +66,16 @@ export class LogQueue {
body, body,
}) })
if (!res.ok) { 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) 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)) await AsyncStorage.setItem(QUEUE_KEY, JSON.stringify(queue))
} }
} }

查看文件

@ -29,4 +29,4 @@ export interface IssueEvent {
metadata?: Record<string, unknown> 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 let _handler: ApiErrorHandler | null = null
/** 注册全局 API 错误处理器(宿主在初始化时注入,通常将错误转发给 rn-log)。*/ /** 注册全局 API 错误处理器(宿主在初始化时注入,通常将错误转发给 rn-bugcollect)。*/
export function setGlobalApiErrorHandler(handler: ApiErrorHandler): void { export function setGlobalApiErrorHandler(handler: ApiErrorHandler): void {
_handler = handler _handler = handler
} }

查看文件

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

查看文件

@ -63,8 +63,8 @@ export const XuqmSDK = {
imEnabled: remote.imEnabled as boolean | undefined, imEnabled: remote.imEnabled as boolean | undefined,
pushEnabled: remote.pushEnabled as boolean | undefined, pushEnabled: remote.pushEnabled as boolean | undefined,
licenseEnabled: remote.licenseEnabled as boolean | undefined, licenseEnabled: remote.licenseEnabled as boolean | undefined,
logApiUrl: remote.logApiUrl as string | undefined, bugCollectApiUrl: remote.bugCollectApiUrl as string | undefined,
logEnabled: remote.logEnabled as boolean | undefined, bugCollectEnabled: remote.bugCollectEnabled as boolean | undefined,
}) })
configureHttp({ configureHttp({
baseUrl: (remote.apiUrl as string | undefined) ?? baseUrl, 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-common": ["packages/common/src"],
"@xuqm/rn-im": ["packages/im/src"], "@xuqm/rn-im": ["packages/im/src"],
"@xuqm/rn-license": ["packages/license/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-push": ["packages/push/src"],
"@xuqm/rn-update": ["packages/update/src"], "@xuqm/rn-update": ["packages/update/src"],
"@xuqm/rn-xwebview": ["packages/xwebview/src"] "@xuqm/rn-xwebview": ["packages/xwebview/src"]