UNPKG

mixpanel-react-native

Version:

Official React Native Tracking Library for Mixpanel Analytics

509 lines (398 loc) 13.5 kB
# Workflow: Debugging Issues ## Overview This workflow provides a systematic approach to debugging issues in the mixpanel-react-native library, covering both native and JavaScript implementation modes, common failure scenarios, and diagnostic techniques. ## 🔍 Initial Diagnostics ### Step 1: Determine Implementation Mode ```javascript // Add this debug code to determine which mode is active const debugImplementationMode = () => { console.log('=== Mixpanel Debug Info ==='); console.log('Native module available:', !!NativeModules.MixpanelReactNative); console.log('Implementation type:', mixpanel.mixpanelImpl === MixpanelReactNative ? 'Native' : 'JavaScript'); console.log('Platform:', Platform.OS); console.log('=============================='); }; ``` ### Step 2: Enable Comprehensive Logging ```javascript // Enable logging for all tokens mixpanel.setLoggingEnabled(true); // Check current logging status console.log('Logging enabled:', mixpanel.config?.getLoggingEnabled?.(token)); // Verify logs are appearing with [Mixpanel] prefix // Expected output: [Mixpanel] Track 'Event Name' with properties {...} ``` ### Step 3: Check Basic Configuration ```javascript const debugConfiguration = async () => { console.log('=== Configuration Debug ==='); console.log('Token:', mixpanel.token); console.log('Track automatic events:', mixpanel.trackAutomaticEvents); console.log('Opted out:', await mixpanel.hasOptedOutTracking()); console.log('Distinct ID:', await mixpanel.getDistinctId()); console.log('Device ID:', await mixpanel.getDeviceId()); console.log('Super properties:', await mixpanel.getSuperProperties()); console.log('=============================='); }; ``` ## 🔧 Native Mode Debugging ### Common Native Issues #### Issue: "MixpanelReactNative is not available" ```bash # iOS Troubleshooting cd ios pod install --repo-update cd .. # Verify podfile contains: # pod 'MixpanelReactNative', :path => '../node_modules/mixpanel-react-native' # Clean and rebuild npx react-native run-ios --reset-cache ``` ```bash # Android Troubleshooting cd android ./gradlew clean ./gradlew build cd .. # Verify autolinking worked npx react-native config # Clean and rebuild npx react-native run-android --reset-cache ``` #### Issue: Native Method Calls Failing ```javascript // Test native bridge directly const testNativeBridge = async () => { try { // Test basic native method await NativeModules.MixpanelReactNative?.initialize?.( 'test-token', true, false, {}, 'https://api.mixpanel.com', false ); console.log('✅ Native bridge working'); } catch (error) { console.error('❌ Native bridge error:', error); console.log('Available methods:', Object.keys(NativeModules.MixpanelReactNative || {})); } }; ``` #### Issue: iOS-Specific Problems ```javascript // Check iOS-specific features const debugiOS = () => { if (Platform.OS === 'ios') { console.log('=== iOS Debug ==='); // Test iOS-specific methods try { mixpanel.setFlushOnBackground(true); console.log('✅ iOS setFlushOnBackground working'); } catch (error) { console.error('❌ iOS method error:', error); } console.log('=================='); } }; ``` #### Issue: Android-Specific Problems ```javascript // Check Android-specific behavior const debugAndroid = () => { if (Platform.OS === 'android') { console.log('=== Android Debug ==='); // Android doesn't support setFlushOnBackground console.log('Flush on background not supported on Android'); // Check instance synchronization console.log('Instance management: Thread-safe synchronized'); console.log('======================'); } }; ``` ## 🖥️ JavaScript Mode Debugging ### Common JavaScript Issues #### Issue: Events Not Being Tracked ```javascript const debugEventTracking = async () => { console.log('=== Event Tracking Debug ==='); // Check opt-out status first const optedOut = await mixpanel.hasOptedOutTracking(); console.log('Opted out:', optedOut); if (optedOut) { console.log('❌ User has opted out - events will not be tracked'); return; } // Test queue addition mixpanel.track('Debug Event', { debug: true, timestamp: Date.now() }); // Check if event was queued (in JavaScript mode) if (mixpanel.mixpanelImpl !== MixpanelReactNative) { console.log('✅ JavaScript mode - event should be queued'); // Note: Cannot directly access internal queue in production } console.log('============================='); }; ``` #### Issue: Queue Not Processing ```javascript const debugQueueProcessing = () => { console.log('=== Queue Processing Debug ==='); // Check flush interval const config = mixpanel.mixpanelImpl?.config; if (config) { console.log('Flush interval:', config.getFlushInterval?.(mixpanel.token)); console.log('Batch size:', config.getFlushBatchSize?.(mixpanel.token)); console.log('Server URL:', config.getServerURL?.(mixpanel.token)); } // Manual flush test console.log('Triggering manual flush...'); mixpanel.flush(); console.log('==============================='); }; ``` #### Issue: Storage Problems ```javascript const debugStorage = async () => { console.log('=== Storage Debug ==='); try { // Test AsyncStorage directly await AsyncStorage.setItem('mixpanel_test_key', 'test_value'); const value = await AsyncStorage.getItem('mixpanel_test_key'); console.log('✅ AsyncStorage working:', value === 'test_value'); await AsyncStorage.removeItem('mixpanel_test_key'); } catch (error) { console.error('❌ AsyncStorage error:', error); console.log('Falling back to in-memory storage'); } // Test Mixpanel storage try { const originalProps = await mixpanel.getSuperProperties(); await mixpanel.registerSuperProperties({ debug_test: true }); const newProps = await mixpanel.getSuperProperties(); console.log('✅ Mixpanel storage working:', newProps.debug_test === true); } catch (error) { console.error('❌ Mixpanel storage error:', error); } console.log('==================='); }; ``` ## 🌐 Network Debugging ### Network Request Issues ```javascript const debugNetwork = async () => { console.log('=== Network Debug ==='); // Test basic connectivity try { const response = await fetch('https://api.mixpanel.com/track/', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: 'data=' + encodeURIComponent(JSON.stringify([{ event: 'Debug Test', properties: { token: mixpanel.token, time: Date.now(), distinct_id: 'debug-user' } }])) }); console.log('Network response status:', response.status); const result = await response.json(); console.log('Network response body:', result); if (response.status === 200 && result === 1) { console.log('✅ Network connectivity working'); } else { console.log('❌ Network issue detected'); } } catch (error) { console.error('❌ Network error:', error); } console.log('==================='); }; ``` ### Server URL Issues ```javascript const debugServerURL = () => { console.log('=== Server URL Debug ==='); const config = mixpanel.mixpanelImpl?.config; if (config) { const serverURL = config.getServerURL?.(mixpanel.token); console.log('Current server URL:', serverURL); // Test different server URLs const validURLs = [ 'https://api.mixpanel.com', // Default 'https://api-eu.mixpanel.com', // EU ]; validURLs.forEach(url => { console.log(`Testing URL: ${url}`); try { mixpanel.setServerURL(url); console.log(`✅ ${url} set successfully`); } catch (error) { console.error(`❌ ${url} failed:`, error); } }); } console.log('========================'); }; ``` ## 🔄 Common Error Scenarios ### Scenario 1: Silent Failures ```javascript const debugSilentFailures = () => { console.log('=== Silent Failure Debug ==='); // Test with invalid data that might cause silent failures const testCases = [ { name: 'Circular reference', data: {} }, { name: 'Function property', data: { fn: () => {} } }, { name: 'Symbol property', data: { sym: Symbol('test') } }, { name: 'Large object', data: { large: 'x'.repeat(10000) } }, ]; // Create circular reference testCases[0].data.self = testCases[0].data; testCases.forEach(testCase => { console.log(`Testing: ${testCase.name}`); try { JSON.stringify(testCase.data); console.log(`✅ ${testCase.name} - serializable`); mixpanel.track(`Test ${testCase.name}`, testCase.data); console.log(`✅ ${testCase.name} - tracked successfully`); } catch (error) { console.error(`❌ ${testCase.name} - error:`, error.message); } }); console.log('============================'); }; ``` ### Scenario 2: Memory Leaks ```javascript const debugMemoryUsage = async () => { console.log('=== Memory Usage Debug ==='); const initialMemory = performance.memory?.usedJSHeapSize || 'Unknown'; console.log('Initial memory:', initialMemory); // Create multiple instances to test cleanup const instances = []; for (let i = 0; i < 10; i++) { const instance = new Mixpanel(`test-token-${i}`, true); await instance.init(); instances.push(instance); } const afterCreateMemory = performance.memory?.usedJSHeapSize || 'Unknown'; console.log('Memory after creating 10 instances:', afterCreateMemory); // Reset all instances for (const instance of instances) { await instance.reset(); } const afterResetMemory = performance.memory?.usedJSHeapSize || 'Unknown'; console.log('Memory after reset:', afterResetMemory); console.log('=========================='); }; ``` ### Scenario 3: Timing Issues ```javascript const debugTimingIssues = async () => { console.log('=== Timing Issues Debug ==='); // Test rapid initialization const startTime = Date.now(); const instance = new Mixpanel('timing-test-token', true); // Multiple rapid calls const promises = []; for (let i = 0; i < 5; i++) { promises.push(instance.init()); } try { await Promise.all(promises); const endTime = Date.now(); console.log(`✅ Multiple init calls completed in ${endTime - startTime}ms`); } catch (error) { console.error('❌ Timing issue detected:', error); } // Test rapid tracking for (let i = 0; i < 100; i++) { instance.track(`Rapid Event ${i}`, { index: i }); } console.log('✅ Rapid tracking completed'); console.log('=========================='); }; ``` ## 🛠️ Diagnostic Utilities ### Complete Health Check ```javascript const runCompleteHealthCheck = async () => { console.log('🔍 Starting Mixpanel Health Check...\n'); try { // 1. Implementation mode debugImplementationMode(); // 2. Configuration await debugConfiguration(); // 3. Storage await debugStorage(); // 4. Network await debugNetwork(); // 5. Event tracking await debugEventTracking(); // 6. Platform-specific if (Platform.OS === 'ios') { debugiOS(); } else if (Platform.OS === 'android') { debugAndroid(); } console.log('✅ Health check completed'); } catch (error) { console.error('❌ Health check failed:', error); } }; ``` ### Performance Monitor ```javascript const monitorPerformance = () => { const originalTrack = mixpanel.track.bind(mixpanel); let trackCount = 0; let totalTime = 0; mixpanel.track = (eventName, properties) => { const startTime = Date.now(); trackCount++; const result = originalTrack(eventName, properties); const endTime = Date.now(); const duration = endTime - startTime; totalTime += duration; console.log(`Track #${trackCount}: ${eventName} (${duration}ms)`); console.log(`Average time per track: ${(totalTime / trackCount).toFixed(2)}ms`); return result; }; console.log('Performance monitoring enabled'); }; ``` ## 📊 Issue Resolution Checklist ### Basic Issues - [ ] Verify implementation mode (native vs JavaScript) - [ ] Check logging is enabled - [ ] Confirm token is valid - [ ] Verify user hasn't opted out - [ ] Test basic connectivity ### Native Mode Issues - [ ] Run `pod install` (iOS) or gradle clean/build (Android) - [ ] Verify autolinking configuration - [ ] Check native module availability - [ ] Test native bridge directly - [ ] Verify platform-specific features ### JavaScript Mode Issues - [ ] Check AsyncStorage availability - [ ] Verify queue processing - [ ] Test manual flush - [ ] Check storage persistence - [ ] Monitor network requests ### Performance Issues - [ ] Monitor memory usage - [ ] Check for circular references - [ ] Verify batch sizes - [ ] Test under load - [ ] Check timing/race conditions ### Data Issues - [ ] Verify event structure - [ ] Check super properties - [ ] Test identity management - [ ] Validate serialization - [ ] Confirm server responses This debugging workflow helps systematically identify and resolve issues across both implementation modes and all major subsystems.