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>
这个提交包含在:
父节点
a53438a3f0
当前提交
57579d2871
@ -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 包上传 SourceMap(dev 模式跳过)
|
||||
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"]
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户