From 902da8cc4f08a58c1e26b1e34e387a320409d99d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 28 Aug 2019 12:31:38 +0200 Subject: [PATCH] rn: add native loggers These provide the ability to integrate the SDK with some other application loggers. At the time this was written we use Timber on Android and CocoaLumberjack on iOS. In addition to the integration capabilities, a LogBridge React Native module provides log transports for JavaScript code, thus centralizing all logs on the native loggers. --- android/sdk/build.gradle | 1 + .../org/jitsi/meet/sdk/AmplitudeModule.java | 3 +- .../org/jitsi/meet/sdk/AudioModeModule.java | 37 +++--- .../meet/sdk/BluetoothHeadsetMonitor.java | 15 +-- .../org/jitsi/meet/sdk/ConnectionService.java | 50 +++---- .../org/jitsi/meet/sdk/ExternalAPIModule.java | 8 +- .../org/jitsi/meet/sdk/JitsiMeetActivity.java | 9 +- .../JitsiMeetOngoingConferenceService.java | 15 ++- .../JitsiMeetUncaughtExceptionHandler.java | 4 +- .../org/jitsi/meet/sdk/JitsiMeetView.java | 11 +- .../org/jitsi/meet/sdk/LogBridgeModule.java | 73 +++++++++++ .../jitsi/meet/sdk/OngoingNotification.java | 7 +- .../meet/sdk/PictureInPictureModule.java | 5 +- .../jitsi/meet/sdk/RNConnectionService.java | 15 ++- .../meet/sdk/ReactInstanceManagerHolder.java | 2 + .../org/jitsi/meet/sdk/WiFiStatsModule.java | 10 +- .../meet/sdk/log/JitsiMeetBaseLogHandler.java | 49 +++++++ .../sdk/log/JitsiMeetDefaultLogHandler.java | 39 ++++++ .../jitsi/meet/sdk/log/JitsiMeetLogger.java | 94 ++++++++++++++ .../meet/sdk/net/NAT64AddrInfoModule.java | 8 +- ios/Podfile | 1 + ios/Podfile.lock | 10 +- ios/sdk/sdk.xcodeproj/project.pbxproj | 36 +++++- ios/sdk/src/AudioMode.m | 8 +- ios/sdk/src/JitsiMeet.h | 2 + ios/sdk/src/JitsiMeetBaseLogHandler+Private.h | 24 ++++ ios/sdk/src/JitsiMeetBaseLogHandler.h | 28 ++++ ios/sdk/src/JitsiMeetBaseLogHandler.m | 105 +++++++++++++++ ios/sdk/src/JitsiMeetLogger.h | 27 ++++ ios/sdk/src/JitsiMeetLogger.m | 40 ++++++ ios/sdk/src/LogBridge.m | 57 ++++++++ ios/sdk/src/LogUtils.h | 23 ++++ ios/sdk/src/analytics/AmplitudeModule.m | 6 +- ios/sdk/src/callkit/CallKit.m | 76 ++++------- package-lock.json | 122 ++++++++++++++++-- package.json | 1 + .../base/logging/LogTransport.native.js | 65 ++++++++++ .../features/base/logging/LogTransport.web.js | 0 react/features/base/logging/functions.js | 24 +++- react/features/base/logging/middleware.js | 6 - react/index.native.js | 6 + 41 files changed, 932 insertions(+), 190 deletions(-) create mode 100644 android/sdk/src/main/java/org/jitsi/meet/sdk/LogBridgeModule.java create mode 100644 android/sdk/src/main/java/org/jitsi/meet/sdk/log/JitsiMeetBaseLogHandler.java create mode 100644 android/sdk/src/main/java/org/jitsi/meet/sdk/log/JitsiMeetDefaultLogHandler.java create mode 100644 android/sdk/src/main/java/org/jitsi/meet/sdk/log/JitsiMeetLogger.java create mode 100644 ios/sdk/src/JitsiMeetBaseLogHandler+Private.h create mode 100644 ios/sdk/src/JitsiMeetBaseLogHandler.h create mode 100644 ios/sdk/src/JitsiMeetBaseLogHandler.m create mode 100644 ios/sdk/src/JitsiMeetLogger.h create mode 100644 ios/sdk/src/JitsiMeetLogger.m create mode 100644 ios/sdk/src/LogBridge.m create mode 100644 ios/sdk/src/LogUtils.h create mode 100644 react/features/base/logging/LogTransport.native.js create mode 100644 react/features/base/logging/LogTransport.web.js diff --git a/android/sdk/build.gradle b/android/sdk/build.gradle index d473292822..af5620f635 100644 --- a/android/sdk/build.gradle +++ b/android/sdk/build.gradle @@ -44,6 +44,7 @@ dependencies { implementation 'org.webkit:android-jsc:+' implementation 'com.dropbox.core:dropbox-core-sdk:3.0.8' + implementation 'com.jakewharton.timber:timber:4.7.1' if (!rootProject.ext.libreBuild) { implementation 'com.amplitude:android-sdk:2.14.1' diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/AmplitudeModule.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/AmplitudeModule.java index eb6cff7594..26877ae9ba 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/AmplitudeModule.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/AmplitudeModule.java @@ -24,6 +24,7 @@ import com.facebook.react.bridge.ReadableMap; import com.amplitude.api.Amplitude; import com.facebook.react.module.annotations.ReactModule; +import org.jitsi.meet.sdk.log.JitsiMeetLogger; import org.json.JSONException; import org.json.JSONObject; @@ -90,7 +91,7 @@ class AmplitudeModule JSONObject eventProps = new JSONObject(eventPropsString); Amplitude.getInstance(instanceName).logEvent(eventType, eventProps); } catch (JSONException e) { - e.printStackTrace(); + JitsiMeetLogger.e(e, "Error logging event"); } } diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/AudioModeModule.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/AudioModeModule.java index e440eeb9f9..c96c23a5d0 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/AudioModeModule.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/AudioModeModule.java @@ -25,7 +25,6 @@ import android.content.pm.PackageManager; import android.media.AudioDeviceInfo; import android.media.AudioManager; import android.os.Build; -import android.util.Log; import androidx.annotation.RequiresApi; import com.facebook.react.bridge.Arguments; @@ -37,6 +36,8 @@ import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; import com.facebook.react.module.annotations.ReactModule; +import org.jitsi.meet.sdk.log.JitsiMeetLogger; + import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -121,7 +122,7 @@ class AudioModeModule extends ReactContextBaseJavaModule case DEVICE_SPEAKER: return android.telecom.CallAudioState.ROUTE_SPEAKER; default: - Log.e(TAG, "Unsupported device name: " + audioDevice); + JitsiMeetLogger.e(TAG + " Unsupported device name: " + audioDevice); return android.telecom.CallAudioState.ROUTE_EARPIECE; } } @@ -218,7 +219,7 @@ class AudioModeModule extends ReactContextBaseJavaModule } availableDevices = devices; - Log.d(TAG, "Available audio devices: " + + JitsiMeetLogger.i(TAG + " Available audio devices: " + availableDevices.toString()); // Reset user selection @@ -360,7 +361,7 @@ class AudioModeModule extends ReactContextBaseJavaModule data.pushMap(deviceInfo); } ReactInstanceManagerHolder.emitEvent(DEVICE_CHANGE_EVENT, data); - Log.i(TAG, "Updating audio device list"); + JitsiMeetLogger.i(TAG + " Updating audio device list"); } }); } @@ -443,8 +444,7 @@ class AudioModeModule extends ReactContextBaseJavaModule if (audioDevicesChanged) { supportedRouteMask = newSupportedRoutes; availableDevices = routesToDeviceNames(supportedRouteMask); - Log.d(TAG, - "Available audio devices: " + JitsiMeetLogger.i(TAG + " Available audio devices: " + availableDevices.toString()); } @@ -478,7 +478,7 @@ class AudioModeModule extends ReactContextBaseJavaModule public void onAudioFocusChange(int focusChange) { switch (focusChange) { case AudioManager.AUDIOFOCUS_GAIN: { - Log.d(TAG, "Audio focus gained"); + JitsiMeetLogger.d(TAG + " Audio focus gained"); // Some other application potentially stole our audio focus // temporarily. Restore our mode. if (audioFocusLost) { @@ -490,7 +490,7 @@ class AudioModeModule extends ReactContextBaseJavaModule case AudioManager.AUDIOFOCUS_LOSS: case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: { - Log.d(TAG, "Audio focus lost"); + JitsiMeetLogger.d(TAG + " Audio focus lost"); audioFocusLost = true; break; } @@ -517,13 +517,13 @@ class AudioModeModule extends ReactContextBaseJavaModule @Override public void run() { if (!availableDevices.contains(device)) { - Log.d(TAG, "Audio device not available: " + device); + JitsiMeetLogger.w(TAG + " Audio device not available: " + device); userSelectedDevice = null; return; } if (mode != -1) { - Log.d(TAG, "User selected device set to: " + device); + JitsiMeetLogger.i(TAG + " User selected device set to: " + device); userSelectedDevice = device; updateAudioRoute(mode); } @@ -594,10 +594,7 @@ class AudioModeModule extends ReactContextBaseJavaModule success = updateAudioRoute(mode); } catch (Throwable e) { success = false; - Log.e( - TAG, - "Failed to update audio route for mode: " + mode, - e); + JitsiMeetLogger.e(e, TAG + " Failed to update audio route for mode: " + mode); } if (success) { AudioModeModule.this.mode = mode; @@ -633,14 +630,14 @@ class AudioModeModule extends ReactContextBaseJavaModule @Override public void onAudioDevicesAdded( AudioDeviceInfo[] addedDevices) { - Log.d(TAG, "Audio devices added"); + JitsiMeetLogger.d(TAG + " Audio devices added"); onAudioDeviceChange(); } @Override public void onAudioDevicesRemoved( AudioDeviceInfo[] removedDevices) { - Log.d(TAG, "Audio devices removed"); + JitsiMeetLogger.d(TAG + " Audio devices removed"); onAudioDeviceChange(); } }; @@ -659,7 +656,7 @@ class AudioModeModule extends ReactContextBaseJavaModule BroadcastReceiver wiredHeadsetReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - Log.d(TAG, "Wired headset added / removed"); + JitsiMeetLogger.d(TAG + " Wired headset added / removed"); onHeadsetDeviceChange(); } }; @@ -677,7 +674,7 @@ class AudioModeModule extends ReactContextBaseJavaModule * {@code false}, otherwise. */ private boolean updateAudioRoute(int mode) { - Log.d(TAG, "Update audio route for mode: " + mode); + JitsiMeetLogger.i(TAG + " Update audio route for mode: " + mode); if (mode == DEFAULT) { if (!useConnectionService()) { @@ -703,7 +700,7 @@ class AudioModeModule extends ReactContextBaseJavaModule AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN) == AudioManager.AUDIOFOCUS_REQUEST_FAILED) { - Log.d(TAG, "Audio focus request failed"); + JitsiMeetLogger.w(TAG + " Audio focus request failed"); return false; } } @@ -734,7 +731,7 @@ class AudioModeModule extends ReactContextBaseJavaModule } selectedDevice = audioDevice; - Log.d(TAG, "Selected audio device: " + audioDevice); + JitsiMeetLogger.i(TAG + " Selected audio device: " + audioDevice); if (useConnectionService()) { setAudioRoute(audioDevice); diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/BluetoothHeadsetMonitor.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/BluetoothHeadsetMonitor.java index 2d9e88a4ec..5ce151c14b 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/BluetoothHeadsetMonitor.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/BluetoothHeadsetMonitor.java @@ -24,7 +24,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.media.AudioManager; -import android.util.Log; + +import org.jitsi.meet.sdk.log.JitsiMeetLogger; /** * Helper class to detect and handle Bluetooth device changes. It monitors @@ -77,7 +78,7 @@ class BluetoothHeadsetMonitor { = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); if (!audioManager.isBluetoothScoAvailableOffCall()) { - Log.w(AudioModeModule.TAG, "Bluetooth SCO is not available"); + JitsiMeetLogger.w(AudioModeModule.TAG + " Bluetooth SCO is not available"); return; } @@ -93,7 +94,7 @@ class BluetoothHeadsetMonitor { BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter == null) { - Log.w(AudioModeModule.TAG, "Device doesn't support Bluetooth"); + JitsiMeetLogger.w(AudioModeModule.TAG + " Device doesn't support Bluetooth"); return false; } @@ -148,9 +149,7 @@ class BluetoothHeadsetMonitor { switch (state) { case BluetoothHeadset.STATE_CONNECTED: case BluetoothHeadset.STATE_DISCONNECTED: - Log.d( - AudioModeModule.TAG, - "BT headset connection state changed: " + state); + JitsiMeetLogger.d(AudioModeModule.TAG + " BT headset connection state changed: " + state); updateDevices(); break; } @@ -164,9 +163,7 @@ class BluetoothHeadsetMonitor { switch (state) { case AudioManager.SCO_AUDIO_STATE_CONNECTED: case AudioManager.SCO_AUDIO_STATE_DISCONNECTED: - Log.d( - AudioModeModule.TAG, - "BT SCO connection state changed: " + state); + JitsiMeetLogger.d(AudioModeModule.TAG + " BT SCO connection state changed: " + state); updateDevices(); break; } diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/ConnectionService.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/ConnectionService.java index 91d6e19b17..90b671b080 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/ConnectionService.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/ConnectionService.java @@ -13,13 +13,14 @@ import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telecom.VideoProfile; -import android.util.Log; import androidx.annotation.RequiresApi; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableNativeMap; +import org.jitsi.meet.sdk.log.JitsiMeetLogger; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -129,9 +130,7 @@ public class ConnectionService extends android.telecom.ConnectionService { if (connection != null) { connection.setActive(); } else { - Log.e(TAG, String.format( - "setConnectionActive - no connection for UUID: %s", - callUUID)); + JitsiMeetLogger.e("% setConnectionActive - no connection for UUID: %s", TAG, callUUID); } } @@ -162,7 +161,7 @@ public class ConnectionService extends android.telecom.ConnectionService { connection.setDisconnected(cause); connection.destroy(); } else { - Log.e(TAG, "endCall no connection for UUID: " + callUUID); + JitsiMeetLogger.e(TAG + " endCall no connection for UUID: " + callUUID); } } @@ -194,15 +193,14 @@ public class ConnectionService extends android.telecom.ConnectionService { boolean hasVideo = callState.getBoolean(ConnectionImpl.KEY_HAS_VIDEO); - Log.d(TAG, String.format( - "updateCall: %s hasVideo: %s", callUUID, hasVideo)); + JitsiMeetLogger.i(" %s updateCall: %s hasVideo: %s", TAG, callUUID, hasVideo); connection.setVideoState( hasVideo ? VideoProfile.STATE_BIDIRECTIONAL : VideoProfile.STATE_AUDIO_ONLY); } } else { - Log.e(TAG, "updateCall no connection for UUID: " + callUUID); + JitsiMeetLogger.e(TAG + " updateCall no connection for UUID: " + callUUID); } } @@ -238,13 +236,11 @@ public class ConnectionService extends android.telecom.ConnectionService { = unregisterStartCallPromise(connection.getCallUUID()); if (startCallPromise != null) { - Log.d(TAG, - "onCreateOutgoingConnection " + connection.getCallUUID()); + JitsiMeetLogger.d(TAG + " onCreateOutgoingConnection " + connection.getCallUUID()); startCallPromise.resolve(null); } else { - Log.e(TAG, String.format( - "onCreateOutgoingConnection: no start call Promise for %s", - connection.getCallUUID())); + JitsiMeetLogger.e( + TAG + " onCreateOutgoingConnection: no start call Promise for " + connection.getCallUUID()); } return connection; @@ -268,7 +264,7 @@ public class ConnectionService extends android.telecom.ConnectionService { PhoneAccountHandle theAccountHandle = request.getAccountHandle(); String callUUID = theAccountHandle.getId(); - Log.e(TAG, "onCreateOutgoingConnectionFailed " + callUUID); + JitsiMeetLogger.e(TAG + " onCreateOutgoingConnectionFailed " + callUUID); if (callUUID != null) { Promise startCallPromise = unregisterStartCallPromise(callUUID); @@ -278,12 +274,10 @@ public class ConnectionService extends android.telecom.ConnectionService { "CREATE_OUTGOING_CALL_FAILED", "The request has been denied by the system"); } else { - Log.e(TAG, String.format( - "startCallFailed - no start call Promise for UUID: %s", - callUUID)); + JitsiMeetLogger.e(TAG + " startCallFailed - no start call Promise for UUID: " + callUUID); } } else { - Log.e(TAG, "onCreateOutgoingConnectionFailed - no call UUID"); + JitsiMeetLogger.e(TAG + " onCreateOutgoingConnectionFailed - no call UUID"); } unregisterPhoneAccount(theAccountHandle); @@ -295,10 +289,10 @@ public class ConnectionService extends android.telecom.ConnectionService { if (phoneAccountHandle != null) { telecom.unregisterPhoneAccount(phoneAccountHandle); } else { - Log.e(TAG, "unregisterPhoneAccount - account handle is null"); + JitsiMeetLogger.e(TAG + " unregisterPhoneAccount - account handle is null"); } } else { - Log.e(TAG, "unregisterPhoneAccount - telecom is null"); + JitsiMeetLogger.e(TAG + "unregisterPhoneAccount - telecom is null"); } } @@ -357,7 +351,7 @@ public class ConnectionService extends android.telecom.ConnectionService { */ @Override public void onDisconnect() { - Log.d(TAG, "onDisconnect " + getCallUUID()); + JitsiMeetLogger.i(TAG + " onDisconnect " + getCallUUID()); WritableNativeMap data = new WritableNativeMap(); data.putString("callUUID", getCallUUID()); ReactInstanceManagerHolder.emitEvent( @@ -377,7 +371,7 @@ public class ConnectionService extends android.telecom.ConnectionService { */ @Override public void onAbort() { - Log.d(TAG, "onAbort " + getCallUUID()); + JitsiMeetLogger.i(TAG + " onAbort " + getCallUUID()); WritableNativeMap data = new WritableNativeMap(); data.putString("callUUID", getCallUUID()); ReactInstanceManagerHolder.emitEvent( @@ -395,9 +389,7 @@ public class ConnectionService extends android.telecom.ConnectionService { // What ?! Android will still call this method even if we do not add // the HOLD capability, so do the same thing as on abort. // TODO implement HOLD - Log.d(TAG, String.format( - "onHold %s - HOLD is not supported, aborting the call...", - getCallUUID())); + JitsiMeetLogger.w(TAG + " onHold %s - HOLD is not supported, aborting the call...", getCallUUID()); this.onAbort(); } @@ -410,7 +402,7 @@ public class ConnectionService extends android.telecom.ConnectionService { */ @Override public void onCallAudioStateChanged(CallAudioState state) { - Log.d(TAG, "onCallAudioStateChanged: " + state); + JitsiMeetLogger.d(TAG + " onCallAudioStateChanged: " + state); AudioModeModule audioModeModule = ReactInstanceManagerHolder .getNativeModule(AudioModeModule.class); @@ -426,10 +418,8 @@ public class ConnectionService extends android.telecom.ConnectionService { */ @Override public void onStateChanged(int state) { - Log.d(TAG, - String.format("onStateChanged: %s %s", - Connection.stateToString(state), - getCallUUID())); + JitsiMeetLogger.d( + "%s onStateChanged: %s %s", TAG, Connection.stateToString(state), getCallUUID()); if (state == STATE_DISCONNECTED) { removeConnection(this); diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/ExternalAPIModule.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/ExternalAPIModule.java index 4ac27de02b..46d5e91afa 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/ExternalAPIModule.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/ExternalAPIModule.java @@ -16,14 +16,14 @@ package org.jitsi.meet.sdk; -import android.util.Log; - import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.module.annotations.ReactModule; +import org.jitsi.meet.sdk.log.JitsiMeetLogger; + /** * Module implementing an API for sending events from JavaScript to native code. */ @@ -76,11 +76,11 @@ class ExternalAPIModule BaseReactView view = BaseReactView.findViewByExternalAPIScope(scope); if (view != null) { - Log.d(TAG, "Sending event: " + name + " with data: " + data); + JitsiMeetLogger.d(TAG + " Sending event: " + name + " with data: " + data); try { view.onExternalAPIEvent(name, data); } catch(Exception e) { - Log.e(TAG, "onExternalAPIEvent: error sending event", e); + JitsiMeetLogger.e(e, TAG + " onExternalAPIEvent: error sending event"); } } } diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java index e4d76ae49e..a0ac085b75 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java @@ -20,12 +20,13 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.util.Log; import androidx.annotation.Nullable; import androidx.fragment.app.FragmentActivity; import com.facebook.react.modules.core.PermissionListener; +import org.jitsi.meet.sdk.log.JitsiMeetLogger; + import java.util.Map; @@ -208,19 +209,19 @@ public class JitsiMeetActivity extends FragmentActivity @Override public void onConferenceJoined(Map data) { - Log.d(TAG, "Conference joined: " + data); + JitsiMeetLogger.i("Conference joined: " + data); // Launch the service for the ongoing notification. JitsiMeetOngoingConferenceService.launch(this); } @Override public void onConferenceTerminated(Map data) { - Log.d(TAG, "Conference terminated: " + data); + JitsiMeetLogger.i("Conference terminated: " + data); finish(); } @Override public void onConferenceWillJoin(Map data) { - Log.d(TAG, "Conference will join: " + data); + JitsiMeetLogger.i("Conference will join: " + data); } } diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetOngoingConferenceService.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetOngoingConferenceService.java index f3914d3483..9fdc17d288 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetOngoingConferenceService.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetOngoingConferenceService.java @@ -23,7 +23,8 @@ import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.IBinder; -import android.util.Log; + +import org.jitsi.meet.sdk.log.JitsiMeetLogger; /** @@ -55,7 +56,7 @@ public class JitsiMeetOngoingConferenceService extends Service componentName = context.startService(intent); } if (componentName == null) { - Log.w(TAG, "Ongoing conference service not started"); + JitsiMeetLogger.w(TAG + " Ongoing conference service not started"); } } @@ -90,20 +91,20 @@ public class JitsiMeetOngoingConferenceService extends Service Notification notification = OngoingNotification.buildOngoingConferenceNotification(); if (notification == null) { stopSelf(); - Log.w(TAG, "Couldn't start service, notification is null"); + JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null"); } else { startForeground(OngoingNotification.NOTIFICATION_ID, notification); - Log.i(TAG, "Service started"); + JitsiMeetLogger.i(TAG + " Service started"); } } else if (action.equals(Actions.HANGUP)) { - Log.i(TAG, "Hangup requested"); + JitsiMeetLogger.i(TAG + " Hangup requested"); // Abort all ongoing calls if (AudioModeModule.useConnectionService()) { ConnectionService.abortConnections(); } stopSelf(); } else { - Log.w(TAG, "Unknown action received: " + action); + JitsiMeetLogger.w(TAG + " Unknown action received: " + action); stopSelf(); } @@ -114,7 +115,7 @@ public class JitsiMeetOngoingConferenceService extends Service public void onCurrentConferenceChanged(String conferenceUrl) { if (conferenceUrl == null) { stopSelf(); - Log.i(TAG, "Service stopped"); + JitsiMeetLogger.i(TAG + "Service stopped"); } } } diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetUncaughtExceptionHandler.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetUncaughtExceptionHandler.java index 77cfc8f6db..bafc02e4b9 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetUncaughtExceptionHandler.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetUncaughtExceptionHandler.java @@ -17,7 +17,7 @@ package org.jitsi.meet.sdk; -import android.util.Log; +import org.jitsi.meet.sdk.log.JitsiMeetLogger; class JitsiMeetUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { private final Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler; @@ -37,7 +37,7 @@ class JitsiMeetUncaughtExceptionHandler implements Thread.UncaughtExceptionHandl @Override public void uncaughtException(Thread t, Throwable e) { - Log.e(this.getClass().getSimpleName(), "FATAL ERROR", e); + JitsiMeetLogger.e(e, this.getClass().getSimpleName() + " FATAL ERROR"); // Abort all ConnectionService ongoing calls if (AudioModeModule.useConnectionService()) { diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetView.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetView.java index fcb1ad31ea..08ee207267 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetView.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetView.java @@ -19,12 +19,13 @@ package org.jitsi.meet.sdk; import android.content.Context; import android.os.Bundle; -import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.facebook.react.bridge.ReadableMap; +import org.jitsi.meet.sdk.log.JitsiMeetLogger; + import java.lang.reflect.Method; import java.util.Map; @@ -39,12 +40,6 @@ public class JitsiMeetView extends BaseReactView private static final Map LISTENER_METHODS = ListenerUtils.mapListenerMethods(JitsiMeetViewListener.class); - /** - * The {@link Log} tag which identifies the source of the log messages of - * {@code JitsiMeetView}. - */ - private static final String TAG = JitsiMeetView.class.getSimpleName(); - /** * The URL of the current conference. */ @@ -137,7 +132,7 @@ public class JitsiMeetView extends BaseReactView try { pipModule.enterPictureInPicture(); } catch (RuntimeException re) { - Log.e(TAG, "failed to enter PiP mode", re); + JitsiMeetLogger.e(re, "Failed to enter PiP mode"); } } } diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/LogBridgeModule.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/LogBridgeModule.java new file mode 100644 index 0000000000..2b7d349d34 --- /dev/null +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/LogBridgeModule.java @@ -0,0 +1,73 @@ +/* + * Copyright @ 2019-present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jitsi.meet.sdk; + +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.module.annotations.ReactModule; + +import org.jitsi.meet.sdk.log.JitsiMeetLogger; + +import javax.annotation.Nonnull; + +/** + * Module implementing a "bridge" between the JS loggers and the native one. + */ +@ReactModule(name = LogBridgeModule.NAME) +class LogBridgeModule extends ReactContextBaseJavaModule { + public static final String NAME = "LogBridge"; + + public LogBridgeModule(@Nonnull ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public String getName() { + return NAME; + } + + @ReactMethod + public void trace(final String message) { + JitsiMeetLogger.v(message); + } + + @ReactMethod + public void debug(final String message) { + JitsiMeetLogger.d(message); + } + + @ReactMethod + public void info(final String message) { + JitsiMeetLogger.i(message); + } + + @ReactMethod + public void log(final String message) { + JitsiMeetLogger.i(message); + } + + @ReactMethod + public void warn(final String message) { + JitsiMeetLogger.w(message); + } + + @ReactMethod + public void error(final String message) { + JitsiMeetLogger.e(message); + } +} diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/OngoingNotification.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/OngoingNotification.java index e6660ff1c4..03b3c2a75b 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/OngoingNotification.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/OngoingNotification.java @@ -24,7 +24,8 @@ import android.content.Context; import android.content.Intent; import android.os.Build; import androidx.core.app.NotificationCompat; -import android.util.Log; + +import org.jitsi.meet.sdk.log.JitsiMeetLogger; import java.util.Random; @@ -50,7 +51,7 @@ class OngoingNotification { Context context = ReactInstanceManagerHolder.getCurrentActivity(); if (context == null) { - Log.w(TAG, "Cannot create notification channel: no current context"); + JitsiMeetLogger.w(TAG + " Cannot create notification channel: no current context"); return; } @@ -75,7 +76,7 @@ class OngoingNotification { static Notification buildOngoingConferenceNotification() { Context context = ReactInstanceManagerHolder.getCurrentActivity(); if (context == null) { - Log.w(TAG, "Cannot create notification: no current context"); + JitsiMeetLogger.w(TAG + " Cannot create notification: no current context"); return null; } diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/PictureInPictureModule.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/PictureInPictureModule.java index c63249a7f6..2123334d54 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/PictureInPictureModule.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/PictureInPictureModule.java @@ -20,7 +20,6 @@ import android.annotation.TargetApi; import android.app.Activity; import android.app.PictureInPictureParams; import android.os.Build; -import android.util.Log; import android.util.Rational; import com.facebook.react.bridge.Promise; @@ -29,6 +28,8 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.module.annotations.ReactModule; +import org.jitsi.meet.sdk.log.JitsiMeetLogger; + @ReactModule(name = PictureInPictureModule.NAME) class PictureInPictureModule extends ReactContextBaseJavaModule { @@ -70,7 +71,7 @@ class PictureInPictureModule throw new IllegalStateException("No current Activity!"); } - Log.d(TAG, "Entering Picture-in-Picture"); + JitsiMeetLogger.i(TAG + " Entering Picture-in-Picture"); PictureInPictureParams.Builder builder = new PictureInPictureParams.Builder() diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/RNConnectionService.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/RNConnectionService.java index fe6fe8a98e..70dcf94b8b 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/RNConnectionService.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/RNConnectionService.java @@ -10,7 +10,6 @@ import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telecom.VideoProfile; -import android.util.Log; import androidx.annotation.RequiresApi; import com.facebook.react.bridge.Promise; @@ -20,6 +19,8 @@ import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.module.annotations.ReactModule; +import org.jitsi.meet.sdk.log.JitsiMeetLogger; + /** * The react-native side of Jitsi Meet's {@link ConnectionService}. Exposes * the Java Script API. @@ -74,11 +75,11 @@ class RNConnectionService String handle, boolean hasVideo, Promise promise) { - Log.d(TAG, - String.format("startCall UUID=%s, h=%s, v=%s", + JitsiMeetLogger.d("%d startCall UUID=%s, h=%s, v=%s", + TAG, callUUID, handle, - hasVideo)); + hasVideo); ReactApplicationContext ctx = getReactApplicationContext(); @@ -118,7 +119,7 @@ class RNConnectionService */ @ReactMethod public void reportCallFailed(String callUUID) { - Log.d(TAG, "reportCallFailed " + callUUID); + JitsiMeetLogger.d(TAG + " reportCallFailed " + callUUID); ConnectionService.setConnectionDisconnected( callUUID, new DisconnectCause(DisconnectCause.ERROR)); @@ -131,7 +132,7 @@ class RNConnectionService */ @ReactMethod public void endCall(String callUUID) { - Log.d(TAG, "endCall " + callUUID); + JitsiMeetLogger.d(TAG + " endCall " + callUUID); ConnectionService.setConnectionDisconnected( callUUID, new DisconnectCause(DisconnectCause.LOCAL)); @@ -144,7 +145,7 @@ class RNConnectionService */ @ReactMethod public void reportConnectedOutgoingCall(String callUUID) { - Log.d(TAG, "reportConnectedOutgoingCall " + callUUID); + JitsiMeetLogger.d(TAG + " reportConnectedOutgoingCall " + callUUID); ConnectionService.setConnectionActive(callUUID); } diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java index 42cfd5dae2..9c3e68b799 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java @@ -34,6 +34,7 @@ import com.facebook.soloader.SoLoader; import com.oney.WebRTCModule.RTCVideoViewManager; import com.oney.WebRTCModule.WebRTCModule; +import org.jitsi.meet.sdk.log.JitsiMeetLogger; import org.webrtc.SoftwareVideoDecoderFactory; import org.webrtc.SoftwareVideoEncoderFactory; import org.webrtc.VideoDecoderFactory; @@ -67,6 +68,7 @@ class ReactInstanceManagerHolder { new DropboxModule(reactContext), new ExternalAPIModule(reactContext), new LocaleDetector(reactContext), + new LogBridgeModule(reactContext), new PictureInPictureModule(reactContext), new ProximityModule(reactContext), new WiFiStatsModule(reactContext), diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/WiFiStatsModule.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/WiFiStatsModule.java index c17eb544f3..529a52eed1 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/WiFiStatsModule.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/WiFiStatsModule.java @@ -19,7 +19,6 @@ package org.jitsi.meet.sdk; import android.content.Context; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; -import android.util.Log; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; @@ -27,6 +26,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.module.annotations.ReactModule; +import org.jitsi.meet.sdk.log.JitsiMeetLogger; import org.json.JSONArray; import org.json.JSONObject; @@ -184,17 +184,15 @@ class WiFiStatsModule } } catch (SocketException e) { - Log.wtf(TAG, - "Unable to NetworkInterface.getNetworkInterfaces()" - ); + JitsiMeetLogger.e(e, TAG + " Unable to NetworkInterface.getNetworkInterfaces()"); } result.put("addresses", addresses); promise.resolve(result.toString()); - Log.d(TAG, "WiFi stats: " + result.toString()); + JitsiMeetLogger.d(TAG + " WiFi stats: " + result.toString()); } catch (Throwable e) { - Log.e(TAG, "Failed to obtain wifi stats", e); + JitsiMeetLogger.e(e, TAG + " Failed to obtain wifi stats"); promise.reject( new Exception("Failed to obtain wifi stats")); } diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/log/JitsiMeetBaseLogHandler.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/log/JitsiMeetBaseLogHandler.java new file mode 100644 index 0000000000..bd45f72e92 --- /dev/null +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/log/JitsiMeetBaseLogHandler.java @@ -0,0 +1,49 @@ +/* + * Copyright @ 2019-present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jitsi.meet.sdk.log; + +import android.util.Log; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.text.MessageFormat; + +import timber.log.Timber; + +/** + * Base class for all custom log handlers. Implementations must inherit from this class and + * implement a `doLog` method which does the actual logging, in addition with a `getTag` method + * with which to tag all logs coming into this logger. + * + * See {@link JitsiMeetDefaultLogHandler} for an example. + */ +public abstract class JitsiMeetBaseLogHandler extends Timber.Tree { + @Override + protected void log(int priority, @Nullable String tag, @NotNull String msg, @Nullable Throwable t) { + String errmsg = Log.getStackTraceString(t); + if (errmsg.isEmpty()) { + doLog(priority, getTag(), msg); + } else { + doLog(priority, getTag(), MessageFormat.format("{0}\n{1}", msg, errmsg)); + } + } + + protected abstract void doLog(int priority, @NotNull String tag, @NotNull String msg); + + protected abstract String getTag(); +} diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/log/JitsiMeetDefaultLogHandler.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/log/JitsiMeetDefaultLogHandler.java new file mode 100644 index 0000000000..dd3fd10db2 --- /dev/null +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/log/JitsiMeetDefaultLogHandler.java @@ -0,0 +1,39 @@ +/* + * Copyright @ 2019-present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jitsi.meet.sdk.log; + +import android.util.Log; + +import org.jetbrains.annotations.NotNull; + +/** + * Default implementation of a {@link JitsiMeetBaseLogHandler}. This is the main SDK logger, which + * logs using the Android util.Log module. + */ +public class JitsiMeetDefaultLogHandler extends JitsiMeetBaseLogHandler { + private static final String TAG = "JitsiMeetSDK"; + + @Override + protected void doLog(int priority, @NotNull String tag, @NotNull String msg) { + Log.println(priority, tag, msg); + } + + @Override + protected String getTag() { + return TAG; + } +} diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/log/JitsiMeetLogger.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/log/JitsiMeetLogger.java new file mode 100644 index 0000000000..178c92d22b --- /dev/null +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/log/JitsiMeetLogger.java @@ -0,0 +1,94 @@ +/* + * Copyright @ 2019-present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jitsi.meet.sdk.log; + +import timber.log.Timber; + +public class JitsiMeetLogger { + static { + addHandler(new JitsiMeetDefaultLogHandler()); + } + + public static void addHandler(JitsiMeetBaseLogHandler handler) { + Timber.plant(handler); + } + + public static void removeHandler(JitsiMeetBaseLogHandler handler) { + Timber.uproot(handler); + } + + public static void v(String message, Object... args) { + Timber.v(message, args); + } + + public static void v(Throwable t, String message, Object... args) { + Timber.v(t, message, args); + } + + public static void v(Throwable t) { + Timber.v(t); + } + + public static void d(String message, Object... args) { + Timber.d(message, args); + } + + public static void d(Throwable t, String message, Object... args) { + Timber.d(t, message, args); + } + + public static void d(Throwable t) { + Timber.d(t); + } + + public static void i(String message, Object... args) { + Timber.i(message, args); + } + + public static void i(Throwable t, String message, Object... args) { + Timber.i(t, message, args); + } + + public static void i(Throwable t) { + Timber.i(t); + } + + public static void w(String message, Object... args) { + Timber.w(message, args); + } + + public static void w(Throwable t, String message, Object... args) { + Timber.w(t, message, args); + } + + public static void w(Throwable t) { + Timber.w(t); + } + + public static void e(String message, Object... args) { + Timber.e(message, args); + } + + public static void e(Throwable t, String message, Object... args) { + Timber.e(t, message, args); + } + + public static void e(Throwable t) { + Timber.e(t); + } + +} diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/net/NAT64AddrInfoModule.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/net/NAT64AddrInfoModule.java index 0d0ed86b65..1db7b7bd54 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/net/NAT64AddrInfoModule.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/net/NAT64AddrInfoModule.java @@ -15,14 +15,14 @@ */ package org.jitsi.meet.sdk.net; -import android.util.Log; - import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.module.annotations.ReactModule; +import org.jitsi.meet.sdk.log.JitsiMeetLogger; + import java.net.UnknownHostException; /** @@ -97,7 +97,7 @@ public class NAT64AddrInfoModule try { info = NAT64AddrInfo.discover(host); } catch (UnknownHostException e) { - Log.e(TAG, "NAT64AddrInfo.discover: " + host, e); + JitsiMeetLogger.e(e, TAG + " NAT64AddrInfo.discover: " + host); } infoTimestamp = System.currentTimeMillis(); } @@ -107,7 +107,7 @@ public class NAT64AddrInfoModule try { result = info == null ? null : info.getIPv6Address(ipv4Address); } catch (IllegalArgumentException exc) { - Log.e(TAG, "Failed to get IPv6 address for: " + ipv4Address, exc); + JitsiMeetLogger.e(exc, TAG + " Failed to get IPv6 address for: " + ipv4Address); // We don't want to reject. It's not a big deal if there's no IPv6 // address resolved. diff --git a/ios/Podfile b/ios/Podfile index 80165ca162..e7b21ac991 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -61,6 +61,7 @@ target 'JitsiMeet' do # pod 'Amplitude-iOS', '~> 4.0.4' + pod 'CocoaLumberjack', '~>3.5.3' pod 'ObjectiveDropboxOfficial', '~> 3.9.4' use_native_modules! diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2e1010f291..3a6d86321e 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -3,6 +3,9 @@ PODS: - boost-for-react-native (1.63.0) - BVLinearGradient (2.5.6): - React + - CocoaLumberjack (3.5.3): + - CocoaLumberjack/Core (= 3.5.3) + - CocoaLumberjack/Core (3.5.3) - Crashlytics (3.12.0): - Fabric (~> 1.9.0) - DoubleConversion (1.1.6) @@ -187,6 +190,7 @@ PODS: DEPENDENCIES: - Amplitude-iOS (~> 4.0.4) - BVLinearGradient (from `../node_modules/react-native-linear-gradient`) + - CocoaLumberjack (~> 3.5.3) - Crashlytics (~> 3.12.0) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - Fabric (~> 1.9.0) @@ -205,7 +209,7 @@ DEPENDENCIES: - react-native-background-timer (from `../node_modules/react-native-background-timer`) - react-native-calendar-events (from `../node_modules/react-native-calendar-events`) - react-native-keep-awake (from `../node_modules/react-native-keep-awake`) - - react-native-netinfo (from `../node_modules/@react-native-community/netinfo`) + - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" - react-native-webrtc (from `../node_modules/react-native-webrtc`) - react-native-webview (from `../node_modules/react-native-webview`) - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) @@ -229,6 +233,7 @@ SPEC REPOS: https://github.com/cocoapods/specs.git: - Amplitude-iOS - boost-for-react-native + - CocoaLumberjack - Crashlytics - Fabric - Firebase @@ -317,6 +322,7 @@ SPEC CHECKSUMS: Amplitude-iOS: 2ad4d7270c99186236c1272a3a9425463b1ae1a7 boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872 + CocoaLumberjack: 2f44e60eb91c176d471fdba43b9e3eae6a721947 Crashlytics: 07fb167b1694128c1c9a5a5cc319b0e9c3ca0933 DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2 Fabric: f988e33c97f08930a413e08123064d2e5f68d655 @@ -365,6 +371,6 @@ SPEC CHECKSUMS: RNWatch: 09738b339eceb66e4d80a2371633ca5fb380fa42 yoga: 312528f5bbbba37b4dcea5ef00e8b4033fdd9411 -PODFILE CHECKSUM: 0907bfe60b5b5f11dbdc6b4e65d40a248d000513 +PODFILE CHECKSUM: 0e3406a4217cc348dcadad5b016e8d939d4aa61f COCOAPODS: 1.7.2 diff --git a/ios/sdk/sdk.xcodeproj/project.pbxproj b/ios/sdk/sdk.xcodeproj/project.pbxproj index a5001538e7..6524aef79a 100644 --- a/ios/sdk/sdk.xcodeproj/project.pbxproj +++ b/ios/sdk/sdk.xcodeproj/project.pbxproj @@ -26,8 +26,6 @@ 0BCA496C1EC4BBF900B793EE /* jitsi.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 0BCA496B1EC4BBF900B793EE /* jitsi.ttf */; }; 0BD906EA1EC0C00300C8C18E /* JitsiMeet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BD906E81EC0C00300C8C18E /* JitsiMeet.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0F65EECE1D95DA94561BB47E /* libPods-JitsiMeet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 03F2ADC957FF109849B7FCA1 /* libPods-JitsiMeet.a */; }; - C30F88D0CB0F4F5593216D24 /* liveStreamingOff.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C30F88D1CB0F4F5593216D24 /* liveStreamingOff.mp3 */; }; - C30F88D2CB0F4F5593216D24 /* liveStreamingOn.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C30F88D3CB0F4F5593216D24 /* liveStreamingOn.mp3 */; }; 6C31EDC820C06D490089C899 /* recordingOn.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 6C31EDC720C06D490089C899 /* recordingOn.mp3 */; }; 6C31EDCA20C06D530089C899 /* recordingOff.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 6C31EDC920C06D530089C899 /* recordingOff.mp3 */; }; 75635B0A20751D6D00F29C9F /* joined.wav in Resources */ = {isa = PBXBuildFile; fileRef = 75635B0820751D6D00F29C9F /* joined.wav */; }; @@ -36,6 +34,8 @@ A4414AE020B37F1A003546E6 /* rejected.wav in Resources */ = {isa = PBXBuildFile; fileRef = A4414ADF20B37F1A003546E6 /* rejected.wav */; }; A480429C21EE335600289B73 /* AmplitudeModule.m in Sources */ = {isa = PBXBuildFile; fileRef = A480429B21EE335600289B73 /* AmplitudeModule.m */; }; A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */ = {isa = PBXBuildFile; fileRef = A4A934E8212F3ADB001E9388 /* Dropbox.m */; }; + C30F88D0CB0F4F5593216D24 /* liveStreamingOff.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C30F88D1CB0F4F5593216D24 /* liveStreamingOff.mp3 */; }; + C30F88D2CB0F4F5593216D24 /* liveStreamingOn.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C30F88D3CB0F4F5593216D24 /* liveStreamingOn.mp3 */; }; C6245F5D2053091D0040BE68 /* image-resize@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6245F5B2053091D0040BE68 /* image-resize@2x.png */; }; C6245F5E2053091D0040BE68 /* image-resize@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6245F5C2053091D0040BE68 /* image-resize@3x.png */; }; C69EFA0C209A0F660027712B /* JMCallKitEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA09209A0F650027712B /* JMCallKitEmitter.swift */; }; @@ -43,8 +43,15 @@ C69EFA0E209A0F660027712B /* JMCallKitListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA0B209A0F660027712B /* JMCallKitListener.swift */; }; C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3425E204EF76800E062DD /* DragGestureController.swift */; }; C6CC49AF207412CF000DFA42 /* PiPViewCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */; }; + DE65AACA2317FFCD00290BEC /* LogUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DE65AAC92317FFCD00290BEC /* LogUtils.h */; }; + DE65AACC2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */; }; DE762DB422AFDE76000DEBD6 /* JitsiMeetUserInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DE762DB322AFDE76000DEBD6 /* JitsiMeetUserInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; DE762DB622AFDE8D000DEBD6 /* JitsiMeetUserInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DE762DB522AFDE8D000DEBD6 /* JitsiMeetUserInfo.m */; }; + DE81A2D42316AC4D00AE1940 /* JitsiMeetLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = DE81A2D22316AC4D00AE1940 /* JitsiMeetLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DE81A2D52316AC4D00AE1940 /* JitsiMeetLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = DE81A2D32316AC4D00AE1940 /* JitsiMeetLogger.m */; }; + DE81A2D92316AC7600AE1940 /* LogBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = DE81A2D72316AC7600AE1940 /* LogBridge.m */; }; + DE81A2DE2317ED5400AE1940 /* JitsiMeetBaseLogHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = DE81A2DC2317ED5400AE1940 /* JitsiMeetBaseLogHandler.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DE81A2DF2317ED5400AE1940 /* JitsiMeetBaseLogHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = DE81A2DD2317ED5400AE1940 /* JitsiMeetBaseLogHandler.m */; }; DEAD3226220C497000E93636 /* JitsiMeetConferenceOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = DEAD3224220C497000E93636 /* JitsiMeetConferenceOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; DEAD3227220C497000E93636 /* JitsiMeetConferenceOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = DEAD3225220C497000E93636 /* JitsiMeetConferenceOptions.m */; }; DEAFA779229EAD520033A7FA /* RNRootView.m in Sources */ = {isa = PBXBuildFile; fileRef = DEAFA778229EAD520033A7FA /* RNRootView.m */; }; @@ -77,8 +84,6 @@ 0BD906E51EC0C00300C8C18E /* JitsiMeet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JitsiMeet.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 0BD906E81EC0C00300C8C18E /* JitsiMeet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeet.h; sourceTree = ""; }; 0BD906E91EC0C00300C8C18E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C30F88D1CB0F4F5593216D24 /* liveStreamingOff.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = liveStreamingOff.mp3; path = ../../sounds/liveStreamingOff.mp3; sourceTree = ""; }; - C30F88D3CB0F4F5593216D24 /* liveStreamingOn.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = liveStreamingOn.mp3; path = ../../sounds/liveStreamingOn.mp3; sourceTree = ""; }; 6C31EDC720C06D490089C899 /* recordingOn.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = recordingOn.mp3; path = ../../sounds/recordingOn.mp3; sourceTree = ""; }; 6C31EDC920C06D530089C899 /* recordingOff.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = recordingOff.mp3; path = ../../sounds/recordingOff.mp3; sourceTree = ""; }; 75635B0820751D6D00F29C9F /* joined.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = joined.wav; path = ../../sounds/joined.wav; sourceTree = ""; }; @@ -90,6 +95,8 @@ A480429B21EE335600289B73 /* AmplitudeModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AmplitudeModule.m; path = src/analytics/AmplitudeModule.m; sourceTree = SOURCE_ROOT; }; A4A934E8212F3ADB001E9388 /* Dropbox.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Dropbox.m; sourceTree = ""; }; A4A934EB21349A06001E9388 /* Dropbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Dropbox.h; sourceTree = ""; }; + C30F88D1CB0F4F5593216D24 /* liveStreamingOff.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = liveStreamingOff.mp3; path = ../../sounds/liveStreamingOff.mp3; sourceTree = ""; }; + C30F88D3CB0F4F5593216D24 /* liveStreamingOn.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = liveStreamingOn.mp3; path = ../../sounds/liveStreamingOn.mp3; sourceTree = ""; }; C6245F5B2053091D0040BE68 /* image-resize@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "image-resize@2x.png"; path = "src/picture-in-picture/image-resize@2x.png"; sourceTree = ""; }; C6245F5C2053091D0040BE68 /* image-resize@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "image-resize@3x.png"; path = "src/picture-in-picture/image-resize@3x.png"; sourceTree = ""; }; C69EFA09209A0F650027712B /* JMCallKitEmitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JMCallKitEmitter.swift; sourceTree = ""; }; @@ -98,9 +105,16 @@ C6A3425E204EF76800E062DD /* DragGestureController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragGestureController.swift; sourceTree = ""; }; C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiPViewCoordinator.swift; sourceTree = ""; }; C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetView+Private.h"; sourceTree = ""; }; + DE65AAC92317FFCD00290BEC /* LogUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogUtils.h; sourceTree = ""; }; + DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetBaseLogHandler+Private.h"; sourceTree = ""; }; DE762DB322AFDE76000DEBD6 /* JitsiMeetUserInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeetUserInfo.h; sourceTree = ""; }; DE762DB522AFDE8D000DEBD6 /* JitsiMeetUserInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JitsiMeetUserInfo.m; sourceTree = ""; }; DE762DB722AFE166000DEBD6 /* JitsiMeetUserInfo+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetUserInfo+Private.h"; sourceTree = ""; }; + DE81A2D22316AC4D00AE1940 /* JitsiMeetLogger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeetLogger.h; sourceTree = ""; }; + DE81A2D32316AC4D00AE1940 /* JitsiMeetLogger.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JitsiMeetLogger.m; sourceTree = ""; }; + DE81A2D72316AC7600AE1940 /* LogBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LogBridge.m; sourceTree = ""; }; + DE81A2DC2317ED5400AE1940 /* JitsiMeetBaseLogHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeetBaseLogHandler.h; sourceTree = ""; }; + DE81A2DD2317ED5400AE1940 /* JitsiMeetBaseLogHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JitsiMeetBaseLogHandler.m; sourceTree = ""; }; DEAD3224220C497000E93636 /* JitsiMeetConferenceOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeetConferenceOptions.h; sourceTree = ""; }; DEAD3225220C497000E93636 /* JitsiMeetConferenceOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JitsiMeetConferenceOptions.m; sourceTree = ""; }; DEAD3228220C734300E93636 /* JitsiMeetConferenceOptions+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetConferenceOptions+Private.h"; sourceTree = ""; }; @@ -186,8 +200,15 @@ DE762DB322AFDE76000DEBD6 /* JitsiMeetUserInfo.h */, DE762DB722AFE166000DEBD6 /* JitsiMeetUserInfo+Private.h */, DE762DB522AFDE8D000DEBD6 /* JitsiMeetUserInfo.m */, + DE81A2D22316AC4D00AE1940 /* JitsiMeetLogger.h */, + DE81A2D32316AC4D00AE1940 /* JitsiMeetLogger.m */, + DE81A2DC2317ED5400AE1940 /* JitsiMeetBaseLogHandler.h */, + DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */, + DE81A2DD2317ED5400AE1940 /* JitsiMeetBaseLogHandler.m */, 0B412F161EDEC65D00B1A0A6 /* JitsiMeetView.h */, 0B412F171EDEC65D00B1A0A6 /* JitsiMeetView.m */, + DE81A2D72316AC7600AE1940 /* LogBridge.m */, + DE65AAC92317FFCD00290BEC /* LogUtils.h */, DEAFA777229EAD3B0033A7FA /* RNRootView.h */, DEAFA778229EAD520033A7FA /* RNRootView.m */, C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */, @@ -273,8 +294,12 @@ DE762DB422AFDE76000DEBD6 /* JitsiMeetUserInfo.h in Headers */, 0B412F181EDEC65D00B1A0A6 /* JitsiMeetView.h in Headers */, 0B93EF7E1EC9DDCD0030D24D /* RCTBridgeWrapper.h in Headers */, + DE81A2DE2317ED5400AE1940 /* JitsiMeetBaseLogHandler.h in Headers */, + DE65AACC2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h in Headers */, 0B412F221EDEF6EA00B1A0A6 /* JitsiMeetViewDelegate.h in Headers */, 0BD906EA1EC0C00300C8C18E /* JitsiMeet.h in Headers */, + DE81A2D42316AC4D00AE1940 /* JitsiMeetLogger.h in Headers */, + DE65AACA2317FFCD00290BEC /* LogUtils.h in Headers */, DEAD3226220C497000E93636 /* JitsiMeetConferenceOptions.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -496,7 +521,9 @@ buildActionMask = 2147483647; files = ( 0BB9AD7B1F5EC8F4001C08DB /* CallKit.m in Sources */, + DE81A2DF2317ED5400AE1940 /* JitsiMeetBaseLogHandler.m in Sources */, 0BB9AD7D1F60356D001C08DB /* AppInfo.m in Sources */, + DE81A2D92316AC7600AE1940 /* LogBridge.m in Sources */, DEAFA779229EAD520033A7FA /* RNRootView.m in Sources */, DE762DB622AFDE8D000DEBD6 /* JitsiMeetUserInfo.m in Sources */, DEAD3227220C497000E93636 /* JitsiMeetConferenceOptions.m in Sources */, @@ -513,6 +540,7 @@ C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */, A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */, C69EFA0D209A0F660027712B /* JMCallKitProxy.swift in Sources */, + DE81A2D52316AC4D00AE1940 /* JitsiMeetLogger.m in Sources */, C69EFA0E209A0F660027712B /* JMCallKitListener.swift in Sources */, 0B412F191EDEC65D00B1A0A6 /* JitsiMeetView.m in Sources */, DEFE535421FB1BF800011A3A /* JitsiMeet.m in Sources */, diff --git a/ios/sdk/src/AudioMode.m b/ios/sdk/src/AudioMode.m index a25cb54255..475b7741a4 100644 --- a/ios/sdk/src/AudioMode.m +++ b/ios/sdk/src/AudioMode.m @@ -20,6 +20,8 @@ #import #import +#import "LogUtils.h" + // Audio mode typedef enum { @@ -167,7 +169,7 @@ RCT_EXPORT_METHOD(setMode:(int)mode RCT_EXPORT_METHOD(setAudioDevice:(NSString *)device resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - NSLog(@"[AudioMode] Selected device: %@", device); + DDLogInfo(@"[AudioMode] Selected device: %@", device); RTCAudioSession *session = [RTCAudioSession sharedInstance]; [session lockForConfiguration]; @@ -260,7 +262,7 @@ RCT_EXPORT_METHOD(updateDeviceList) { // This is to play well with other components which could be integrated // into the final application. if (self->activeMode != kAudioModeDefault) { - NSLog(@"[AudioMode] Route changed, reapplying RTCAudioSession config"); + DDLogInfo(@"[AudioMode] Route changed, reapplying RTCAudioSession config"); RTCAudioSessionConfiguration *config = [self configForMode:self->activeMode]; [self setConfig:config error:nil]; if (self->forceSpeaker && !self->isSpeakerOn) { @@ -274,7 +276,7 @@ RCT_EXPORT_METHOD(updateDeviceList) { } - (void)audioSession:(RTCAudioSession *)audioSession didSetActive:(BOOL)active { - NSLog(@"[AudioMode] Audio session didSetActive:%d", active); + DDLogInfo(@"[AudioMode] Audio session didSetActive:%d", active); } #pragma mark - Helper methods diff --git a/ios/sdk/src/JitsiMeet.h b/ios/sdk/src/JitsiMeet.h index a339ba4614..b0123c6f4f 100644 --- a/ios/sdk/src/JitsiMeet.h +++ b/ios/sdk/src/JitsiMeet.h @@ -18,6 +18,8 @@ #import #import #import +#import +#import @interface JitsiMeet : NSObject diff --git a/ios/sdk/src/JitsiMeetBaseLogHandler+Private.h b/ios/sdk/src/JitsiMeetBaseLogHandler+Private.h new file mode 100644 index 0000000000..e16edaf25b --- /dev/null +++ b/ios/sdk/src/JitsiMeetBaseLogHandler+Private.h @@ -0,0 +1,24 @@ +/* + * Copyright @ 2019-present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "LogUtils.h" +#import "JitsiMeetBaseLogHandler.h" + +@interface JitsiMeetBaseLogHandler () + +@property (nonatomic, retain) id logger; + +@end diff --git a/ios/sdk/src/JitsiMeetBaseLogHandler.h b/ios/sdk/src/JitsiMeetBaseLogHandler.h new file mode 100644 index 0000000000..09ac8bff46 --- /dev/null +++ b/ios/sdk/src/JitsiMeetBaseLogHandler.h @@ -0,0 +1,28 @@ +/* + * Copyright @ 2019-present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@interface JitsiMeetBaseLogHandler : NSObject + +// These are "abstract". +- (void)logVerbose:(NSString *)msg; +- (void)logDebug:(NSString *)msg; +- (void)logInfo:(NSString *)msg; +- (void)logWarn:(NSString *)msg; +- (void)logError:(NSString *)msg; + +@end diff --git a/ios/sdk/src/JitsiMeetBaseLogHandler.m b/ios/sdk/src/JitsiMeetBaseLogHandler.m new file mode 100644 index 0000000000..526672bba9 --- /dev/null +++ b/ios/sdk/src/JitsiMeetBaseLogHandler.m @@ -0,0 +1,105 @@ +/* + * Copyright @ 2019-present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "JitsiMeetBaseLogHandler+Private.h" + +@interface PrivateLogger : DDAbstractLogger +@end + +@implementation PrivateLogger { + JitsiMeetBaseLogHandler *_delegate; +} + +- (instancetype)initWithDelegate:(JitsiMeetBaseLogHandler *)delegate { + if (self = [super init]) { + _delegate = delegate; + } + + return self; +} + +#pragma mark - DDAbstractLogger interface + +- (void)logMessage:(DDLogMessage *)logMessage { + NSString *logMsg = logMessage.message; + + if (_logFormatter) + logMsg = [_logFormatter formatLogMessage:logMessage]; + + if (logMsg && _delegate) { + switch (logMessage.flag) { + case DDLogFlagError: + [_delegate logError:logMsg]; + break; + case DDLogFlagWarning: + [_delegate logWarn:logMsg]; + break; + case DDLogFlagInfo: + [_delegate logInfo:logMsg]; + break; + case DDLogFlagDebug: + [_delegate logDebug:logMsg]; + break; + case DDLogFlagVerbose: + [_delegate logVerbose:logMsg]; + break; + } + } +} + +@end + + +@implementation JitsiMeetBaseLogHandler + +#pragma mark - Proxy logger not to expose the CocoaLumberjack headers + +- (instancetype)init { + if (self = [super init]) { + self.logger = [[PrivateLogger alloc] initWithDelegate:self]; + } + + return self; +} + +#pragma mark - Public API + +- (void)logVerbose:(NSString *)msg { + // Override me! + [self doesNotRecognizeSelector:_cmd]; +} + +- (void)logDebug:(NSString *)msg { + // Override me! + [self doesNotRecognizeSelector:_cmd]; +} + +- (void)logInfo:(NSString *)msg { + // Override me! + [self doesNotRecognizeSelector:_cmd]; +} + +- (void)logWarn:(NSString *)msg { + // Override me! + [self doesNotRecognizeSelector:_cmd]; +} + +- (void)logError:(NSString *)msg { + // Override me! + [self doesNotRecognizeSelector:_cmd]; +} + +@end diff --git a/ios/sdk/src/JitsiMeetLogger.h b/ios/sdk/src/JitsiMeetLogger.h new file mode 100644 index 0000000000..4b604e2289 --- /dev/null +++ b/ios/sdk/src/JitsiMeetLogger.h @@ -0,0 +1,27 @@ +/* + * Copyright @ 2019-present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "JitsiMeetBaseLogHandler.h" + + +@interface JitsiMeetLogger : NSObject + ++ (void)addHandler:(JitsiMeetBaseLogHandler *)handler; ++ (void)removeHandler:(JitsiMeetBaseLogHandler *)handler; + +@end diff --git a/ios/sdk/src/JitsiMeetLogger.m b/ios/sdk/src/JitsiMeetLogger.m new file mode 100644 index 0000000000..245af499e3 --- /dev/null +++ b/ios/sdk/src/JitsiMeetLogger.m @@ -0,0 +1,40 @@ +/* + * Copyright @ 2019-present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "LogUtils.h" +#import "JitsiMeetLogger.h" +#import "JitsiMeetBaseLogHandler+Private.h" + + +@implementation JitsiMeetLogger + +/** +* This gets called automagically when the program starts. +*/ +__attribute__((constructor)) +static void initializeLogger() { + [DDLog addLogger:[DDOSLogger sharedInstance]]; +} + ++ (void)addHandler:(JitsiMeetBaseLogHandler *)handler { + [DDLog addLogger:handler.logger]; +} + ++ (void)removeHandler:(JitsiMeetBaseLogHandler *)handler { + [DDLog removeLogger:handler.logger]; +} + +@end diff --git a/ios/sdk/src/LogBridge.m b/ios/sdk/src/LogBridge.m new file mode 100644 index 0000000000..42d13f7424 --- /dev/null +++ b/ios/sdk/src/LogBridge.m @@ -0,0 +1,57 @@ +/* + * Copyright @ 2019-present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "LogUtils.h" + + +@interface LogBridge : NSObject +@end + +@implementation LogBridge + +RCT_EXPORT_MODULE(); + ++ (BOOL)requiresMainQueueSetup { + return NO; +} + +RCT_EXPORT_METHOD(trace:(NSString *)msg) { + DDLogDebug(@"%@", msg); +} + +RCT_EXPORT_METHOD(debug:(NSString *)msg) { + DDLogDebug(@"%@", msg); +} + +RCT_EXPORT_METHOD(info:(NSString *)msg) { + DDLogInfo(@"%@", msg); +} + +RCT_EXPORT_METHOD(log:(NSString *)msg) { + DDLogInfo(@"%@", msg); +} + +RCT_EXPORT_METHOD(warn:(NSString *)msg) { + DDLogWarn(@"%@", msg); +} + +RCT_EXPORT_METHOD(error:(NSString *)msg) { + DDLogError(@"%@", msg); +} + +@end diff --git a/ios/sdk/src/LogUtils.h b/ios/sdk/src/LogUtils.h new file mode 100644 index 0000000000..d47b22679e --- /dev/null +++ b/ios/sdk/src/LogUtils.h @@ -0,0 +1,23 @@ +/* + * Copyright @ 2019-present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef JM_LOG_UTILS_H +#define JM_LOG_UTILS_H + +#import +static const DDLogLevel ddLogLevel = DDLogLevelVerbose; + +#endif diff --git a/ios/sdk/src/analytics/AmplitudeModule.m b/ios/sdk/src/analytics/AmplitudeModule.m index f5864728c6..5942457c5f 100644 --- a/ios/sdk/src/analytics/AmplitudeModule.m +++ b/ios/sdk/src/analytics/AmplitudeModule.m @@ -15,10 +15,12 @@ */ #import + #import "Amplitude.h" +#import "LogUtils.h" + @interface AmplitudeModule : NSObject - @end @implementation AmplitudeModule @@ -50,7 +52,7 @@ RCT_EXPORT_METHOD(logEvent:(NSString*)instanceName eventType:(NSString*)eventTyp options:NSJSONReadingMutableContainers error:&error]; if (eventProperties == nil) { - NSLog(@"[Amplitude handler] Error parsing event properties: %@", error); + DDLogError(@"[Amplitude] Error parsing event properties: %@", error); } else { [[Amplitude instanceWithName:instanceName] logEvent:eventType withEventProperties:eventProperties]; } diff --git a/ios/sdk/src/callkit/CallKit.m b/ios/sdk/src/callkit/CallKit.m index 79559ed80d..f1cd64fabf 100644 --- a/ios/sdk/src/callkit/CallKit.m +++ b/ios/sdk/src/callkit/CallKit.m @@ -30,6 +30,9 @@ #import +#import "LogUtils.h" + + // The events emitted/supported by RNCallKit: static NSString * const RNCallKitPerformAnswerCallAction = @"performAnswerCallAction"; @@ -69,9 +72,7 @@ RCT_EXPORT_MODULE(); RCT_EXPORT_METHOD(endCall:(NSString *)callUUID resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { -#ifdef DEBUG - NSLog(@"[RNCallKit][endCall] callUUID = %@", callUUID); -#endif + DDLogInfo(@"[RNCallKit][endCall] callUUID = %@", callUUID); NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID]; @@ -92,9 +93,7 @@ RCT_EXPORT_METHOD(setMuted:(NSString *)callUUID muted:(BOOL)muted resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { -#ifdef DEBUG - NSLog(@"[RNCallKit][setMuted] callUUID = %@", callUUID); -#endif + DDLogInfo(@"[RNCallKit][setMuted] callUUID = %@", callUUID); NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID]; @@ -111,11 +110,7 @@ RCT_EXPORT_METHOD(setMuted:(NSString *)callUUID } RCT_EXPORT_METHOD(setProviderConfiguration:(NSDictionary *)dictionary) { -#ifdef DEBUG - NSLog( - @"[RNCallKit][setProviderConfiguration:] dictionary = %@", - dictionary); -#endif + DDLogInfo(@"[RNCallKit][setProviderConfiguration:] dictionary = %@", dictionary); if (![JMCallKitProxy isProviderConfigured]) { [self configureProviderFromDictionary:dictionary]; @@ -131,9 +126,7 @@ RCT_EXPORT_METHOD(startCall:(NSString *)callUUID video:(BOOL)video resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { -#ifdef DEBUG - NSLog(@"[RNCallKit][startCall] callUUID = %@", callUUID); -#endif + DDLogInfo(@"[RNCallKit][startCall] callUUID = %@", callUUID); NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID]; @@ -197,12 +190,7 @@ RCT_EXPORT_METHOD(updateCall:(NSString *)callUUID options:(NSDictionary *)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { -#ifdef DEBUG - NSLog( - @"[RNCallKit][updateCall] callUUID = %@ options = %@", - callUUID, - options); -#endif + DDLogInfo(@"[RNCallKit][updateCall] callUUID = %@ options = %@", callUUID, options); NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID]; @@ -225,9 +213,7 @@ RCT_EXPORT_METHOD(updateCall:(NSString *)callUUID #pragma mark - Helper methods - (void)configureProviderFromDictionary:(NSDictionary* )dictionary { -#ifdef DEBUG - NSLog(@"[RNCallKit][providerConfigurationFromDictionary:]"); -#endif + DDLogInfo(@"[RNCallKit][providerConfigurationFromDictionary: %@]", dictionary); if (!dictionary) { dictionary = @{}; @@ -271,17 +257,12 @@ RCT_EXPORT_METHOD(updateCall:(NSString *)callUUID - (void)requestTransaction:(CXTransaction *)transaction resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { -#ifdef DEBUG - NSLog(@"[RNCallKit][requestTransaction] transaction = %@", transaction); -#endif + DDLogInfo(@"[RNCallKit][requestTransaction] transaction = %@", transaction); [JMCallKitProxy request:transaction completion:^(NSError * _Nullable error) { if (error) { - NSLog( - @"[RNCallKit][requestTransaction] Error requesting transaction (%@): (%@)", - transaction.actions, - error); + DDLogError(@"[RNCallKit][requestTransaction] Error requesting transaction (%@): (%@)", transaction.actions, error); reject(nil, @"Error processing CallKit transaction", error); } else { resolve(nil); @@ -293,18 +274,14 @@ RCT_EXPORT_METHOD(updateCall:(NSString *)callUUID // Called when the provider has been reset. We should terminate all calls. - (void)providerDidReset { -#ifdef DEBUG - NSLog(@"[RNCallKit][CXProviderDelegate][providerDidReset:]"); -#endif + DDLogInfo(@"[RNCallKit][CXProviderDelegate][providerDidReset:]"); [self sendEventWithName:RNCallKitProviderDidReset body:nil]; } // Answering incoming call - (void) performAnswerCallWithUUID:(NSUUID *)UUID { -#ifdef DEBUG - NSLog(@"[RNCallKit][CXProviderDelegate][provider:performAnswerCallAction:]"); -#endif + DDLogInfo(@"[RNCallKit][CXProviderDelegate][provider:performAnswerCallAction:]"); [self sendEventWithName:RNCallKitPerformAnswerCallAction body:@{ @"callUUID": UUID.UUIDString }]; @@ -312,9 +289,7 @@ RCT_EXPORT_METHOD(updateCall:(NSString *)callUUID // Call ended, user request - (void) performEndCallWithUUID:(NSUUID *)UUID { -#ifdef DEBUG - NSLog(@"[RNCallKit][CXProviderDelegate][provider:performEndCallAction:]"); -#endif + DDLogInfo(@"[RNCallKit][CXProviderDelegate][provider:performEndCallAction:]"); [self sendEventWithName:RNCallKitPerformEndCallAction body:@{ @"callUUID": UUID.UUIDString }]; @@ -323,9 +298,7 @@ RCT_EXPORT_METHOD(updateCall:(NSString *)callUUID // Handle audio mute from CallKit view - (void) performSetMutedCallWithUUID:(NSUUID *)UUID isMuted:(BOOL)isMuted { -#ifdef DEBUG - NSLog(@"[RNCallKit][CXProviderDelegate][provider:performSetMutedCallAction:]"); -#endif + DDLogInfo(@"[RNCallKit][CXProviderDelegate][provider:performSetMutedCallAction:]"); [self sendEventWithName:RNCallKitPerformSetMutedCallAction body:@{ @@ -337,31 +310,26 @@ RCT_EXPORT_METHOD(updateCall:(NSString *)callUUID // Starting outgoing call - (void) performStartCallWithUUID:(NSUUID *)UUID isVideo:(BOOL)isVideo { -#ifdef DEBUG - NSLog(@"[RNCallKit][CXProviderDelegate][provider:performStartCallAction:]"); -#endif + DDLogInfo(@"[RNCallKit][CXProviderDelegate][provider:performStartCallAction:]"); + [JMCallKitProxy reportOutgoingCallWith:UUID startedConnectingAt:nil]; } - (void) providerDidActivateAudioSessionWithSession:(AVAudioSession *)session { -#ifdef DEBUG - NSLog(@"[RNCallKit][CXProviderDelegate][provider:didActivateAudioSession:]"); -#endif + DDLogInfo(@"[RNCallKit][CXProviderDelegate][provider:didActivateAudioSession:]"); + [[RTCAudioSession sharedInstance] audioSessionDidActivate:session]; } - (void) providerDidDeactivateAudioSessionWithSession:(AVAudioSession *)session { -#ifdef DEBUG - NSLog(@"[RNCallKit][CXProviderDelegate][provider:didDeactivateAudioSession:]"); -#endif + DDLogInfo(@"[RNCallKit][CXProviderDelegate][provider:didDeactivateAudioSession:]"); + [[RTCAudioSession sharedInstance] audioSessionDidDeactivate:session]; } - (void) providerTimedOutPerformingActionWithAction:(CXAction *)action { -#ifdef DEBUG - NSLog(@"[RNCallKit][CXProviderDelegate][provider:timedOutPerformingAction:]"); -#endif + DDLogWarn(@"[RNCallKit][CXProviderDelegate][provider:timedOutPerformingAction:]"); } diff --git a/package-lock.json b/package-lock.json index c32144baed..5064fd512f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8100,8 +8100,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -8306,7 +8305,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", - "dev": true, "requires": { "function-bind": "^1.0.2" } @@ -8325,6 +8323,11 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -9305,6 +9308,11 @@ "kind-of": "^3.0.2" } }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -9357,8 +9365,7 @@ "is-date-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" }, "is-descriptor": { "version": "0.1.6", @@ -9401,6 +9408,11 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, + "is-generator-function": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz", + "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==" + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -9456,7 +9468,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, "requires": { "has": "^1.0.1" } @@ -12032,6 +12043,15 @@ "requires": { "safe-buffer": "~5.1.0" } + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dev": true, + "requires": { + "inherits": "2.0.3" + } } } }, @@ -12285,6 +12305,76 @@ "isobject": "^3.0.0" } }, + "object.entries": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", + "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + }, + "dependencies": { + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "requires": { + "has-symbols": "^1.0.0" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, "object.getownpropertydescriptors": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", @@ -17339,12 +17429,22 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, "util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "dev": true, + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.1.tgz", + "integrity": "sha512-MREAtYOp+GTt9/+kwf00IYoHZyjM8VU4aVrkzUlejyqaIjd2GztVl5V9hGXKlvBKE3gENn/FMfHE5v6hElXGcQ==", "requires": { - "inherits": "2.0.3" + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "object.entries": "^1.1.0", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + } } }, "util-deprecate": { diff --git a/package.json b/package.json index 5c5f433aa2..7bdd65e657 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "redux": "4.0.4", "redux-thunk": "2.2.0", "styled-components": "3.4.9", + "util": "0.12.1", "uuid": "3.1.0", "windows-iana": "^3.1.0", "xmldom": "0.1.27" diff --git a/react/features/base/logging/LogTransport.native.js b/react/features/base/logging/LogTransport.native.js new file mode 100644 index 0000000000..7ddb186fb9 --- /dev/null +++ b/react/features/base/logging/LogTransport.native.js @@ -0,0 +1,65 @@ +// @flow + +import { NativeModules } from 'react-native'; +import { format } from 'util'; + +// Some code adapted from https://github.com/houserater/react-native-lumberjack +// License: MIT + +const { LogBridge } = NativeModules; + +/** + * Returns the stack trace for a given @code {Error} object. + * + * @param {Errror} e - The rrror. + * @returns {string} - The stack trace. + */ +function stackToString(e) { + let ce; + let s = e.stack; + + if (typeof e.cause === 'function' && (ce = e.cause())) { + s += `\nCaused by: ${stackToString(ce)}`; + } + + return s; +} + +/** + * Constructs a log transport object for use with jitsi-meet-logger. + * + * @returns {Object} - The transport object. + */ +function buildTransport() { + return [ + 'trace', + 'debug', + 'info', + 'log', + 'warn', + 'error' + ].reduce((logger, logName) => { + logger[logName] = (...args: Array) => { + const nargs = args.map(arg => { + if (arg instanceof Error) { + const errorBody = { + message: arg.message, + code: arg.code, + stack: stackToString(arg) + }; + + return `Error(${arg.name})${JSON.stringify(errorBody)}`; + } + + return arg; + }); + const message = format(...nargs); + + LogBridge[logName](message); + }; + + return logger; + }, {}); +} + +export default buildTransport(); diff --git a/react/features/base/logging/LogTransport.web.js b/react/features/base/logging/LogTransport.web.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/react/features/base/logging/functions.js b/react/features/base/logging/functions.js index 266c84a321..54cd32019a 100644 --- a/react/features/base/logging/functions.js +++ b/react/features/base/logging/functions.js @@ -1,6 +1,9 @@ // @flow -import { getLogger as _getLogger } from 'jitsi-meet-logger'; +import _ from 'lodash'; +import Logger, { getLogger as _getLogger } from 'jitsi-meet-logger'; + +import LogTransport from './LogTransport'; /** * Options for building the logger. We disable the callee info on RN because it's @@ -20,3 +23,22 @@ export function getLogger(id: string) { return _getLogger(id, undefined, opts); } + +/** + * Initializes native logging. This operations must be done as early as possible. + */ +export const _initLogging = _.once(() => { + if (navigator.product !== 'ReactNative') { + return; + } + + // Lazy load it to avoid cycles in early web bootstrap code. + const { default: JitsiMeetJS } = require('../lib-jitsi-meet'); + + Logger.setGlobalOptions(DEFAULT_RN_OPTS); + JitsiMeetJS.setGlobalLogOptions(DEFAULT_RN_OPTS); + Logger.removeGlobalTransport(console); + JitsiMeetJS.removeGlobalLogTransport(console); + Logger.addGlobalTransport(LogTransport); + JitsiMeetJS.addGlobalLogTransport(LogTransport); +}); diff --git a/react/features/base/logging/middleware.js b/react/features/base/logging/middleware.js index 6fbf4e2fc4..6aad5e7fb3 100644 --- a/react/features/base/logging/middleware.js +++ b/react/features/base/logging/middleware.js @@ -163,12 +163,6 @@ function _initLogging({ dispatch, getState }, loggingConfig, isTestingEnabled) { logCollector.stop(); dispatch(setLogCollector(undefined)); } - - // Disable caller function info. - if (navigator.product === 'ReactNative') { - Logger.setGlobalOptions({ disableCallerInfo: true }); - JitsiMeetJS.setGlobalLogOptions({ disableCallerInfo: true }); - } } /** diff --git a/react/index.native.js b/react/index.native.js index 6bb34cef90..dec856ac36 100644 --- a/react/index.native.js +++ b/react/index.native.js @@ -16,6 +16,9 @@ import { AppRegistry } from 'react-native'; import { App } from './features/app'; import { IncomingCallApp } from './features/mobile/incoming-call'; +// It's crucial that the native loggers are created ASAP, not to lose any data. +import { _initLogging } from './features/base/logging/functions'; + declare var __DEV__; /** @@ -51,6 +54,9 @@ class Root extends PureComponent { } } +// Initialize logging. +_initLogging(); + // HORRIBLE HACK ALERT! React Native logs the initial props with `console.log`. Here we are quickly patching it // to avoid logging potentially sensitive information. if (!__DEV__) {