feat: 更新依赖项并优化组件结构
- 在 package.json 和 package-lock.json 中新增 @sentry/react-native、react-native-device-info 和 react-native-purchases 依赖 - 更新统计页面,替换 CircularRing 组件为 FitnessRingsCard,增强健身数据展示 - 在布局文件中引入 ToastProvider,优化用户通知体验 - 新增 SuccessToast 组件,提供全局成功提示功能 - 更新健康数据获取逻辑,支持健身圆环数据的提取 - 优化多个组件的样式和交互,提升用户体验
This commit is contained in:
113
utils/sentry.utils.ts
Normal file
113
utils/sentry.utils.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import * as Sentry from '@sentry/react-native';
|
||||
|
||||
export const captureException = (error: Error) => {
|
||||
Sentry.captureException(error);
|
||||
};
|
||||
|
||||
export const captureMessage = (message: string) => {
|
||||
Sentry.captureMessage(message);
|
||||
};
|
||||
|
||||
// 智能处理大型对象的日志记录,避免截断
|
||||
export const captureMessageWithContext = (
|
||||
message: string,
|
||||
context?: Record<string, any>,
|
||||
level: 'debug' | 'info' | 'warning' | 'error' = 'info'
|
||||
) => {
|
||||
try {
|
||||
// 如果有上下文数据,优先使用 addBreadcrumb 或 setContext
|
||||
if (context) {
|
||||
// 检查 JSON 字符串长度
|
||||
const contextString = JSON.stringify(context);
|
||||
|
||||
if (contextString.length > 7000) { // 留 1000+ 字符给消息本身
|
||||
// 如果上下文数据太大,将其作为 context 附加到事件
|
||||
Sentry.withScope(scope => {
|
||||
scope.setContext('large_data', context);
|
||||
Sentry.captureMessage(`${message} (大型上下文数据已附加到事件上下文)`, level);
|
||||
});
|
||||
} else {
|
||||
// 数据较小时,直接包含在消息中
|
||||
Sentry.captureMessage(`${message}: ${contextString}`, level);
|
||||
}
|
||||
} else {
|
||||
Sentry.captureMessage(message, level);
|
||||
}
|
||||
} catch (error) {
|
||||
// 如果 JSON.stringify 失败,回退到基本消息
|
||||
console.error('序列化上下文数据失败:', error);
|
||||
Sentry.captureMessage(`${message} (上下文数据序列化失败)`, level);
|
||||
}
|
||||
};
|
||||
|
||||
// 专门用于记录购买相关的日志,带有结构化数据
|
||||
export const capturePurchaseEvent = (
|
||||
eventType: 'init' | 'success' | 'error' | 'restore',
|
||||
message: string,
|
||||
data?: any
|
||||
) => {
|
||||
const tags = {
|
||||
event_type: 'purchase',
|
||||
purchase_action: eventType,
|
||||
};
|
||||
|
||||
Sentry.withScope(scope => {
|
||||
// 设置标签
|
||||
Object.entries(tags).forEach(([key, value]) => {
|
||||
scope.setTag(key, value);
|
||||
});
|
||||
|
||||
// 如果有数据,设置为上下文
|
||||
if (data) {
|
||||
scope.setContext('purchase_data', data);
|
||||
}
|
||||
|
||||
// 根据事件类型设置适当的级别
|
||||
const level = eventType === 'error' ? 'error' : 'info';
|
||||
Sentry.captureMessage(message, level);
|
||||
});
|
||||
};
|
||||
|
||||
// 记录用户操作日志
|
||||
export const captureUserAction = (
|
||||
action: string,
|
||||
details?: Record<string, any>
|
||||
) => {
|
||||
Sentry.addBreadcrumb({
|
||||
message: `用户操作: ${action}`,
|
||||
category: 'user_action',
|
||||
data: details,
|
||||
level: 'info',
|
||||
});
|
||||
};
|
||||
|
||||
// 记录 API 调用日志
|
||||
export const captureApiCall = (
|
||||
endpoint: string,
|
||||
method: string,
|
||||
success: boolean,
|
||||
responseData?: any,
|
||||
error?: Error
|
||||
) => {
|
||||
const breadcrumb = {
|
||||
message: `API ${method} ${endpoint}`,
|
||||
category: 'http',
|
||||
data: {
|
||||
method,
|
||||
endpoint,
|
||||
success,
|
||||
} as any,
|
||||
level: success ? 'info' : 'error' as any,
|
||||
};
|
||||
|
||||
if (success && responseData) {
|
||||
// 对于成功的响应,只记录关键信息避免数据过大
|
||||
breadcrumb.data.response_keys = Object.keys(responseData);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
breadcrumb.data.error = error.message;
|
||||
}
|
||||
|
||||
Sentry.addBreadcrumb(breadcrumb);
|
||||
};
|
||||
Reference in New Issue
Block a user