diff --git a/CHANGELOG.md b/CHANGELOG.md index 354f53d30..fae23dd81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Added - Add network logs obfuscation support using the new `NetworkLogger.obfuscateLog` API ([#380](https://github.com/Instabug/Instabug-Flutter/pull/380)). +- Add network logs omission support using the new `NetworkLogger.omitLog` API ([#382](https://github.com/Instabug/Instabug-Flutter/pull/382)). ### Changed diff --git a/lib/src/modules/network_logger.dart b/lib/src/modules/network_logger.dart index 7220fd785..83a88538c 100644 --- a/lib/src/modules/network_logger.dart +++ b/lib/src/modules/network_logger.dart @@ -43,7 +43,33 @@ class NetworkLogger { _manager.setObfuscateLogCallback(callback); } + /// Registers a callback to selectively omit network log data. + /// + /// Use this method to set a callback function that determines whether + /// specific network log data should be excluded before recording it. + /// + /// The [callback] function takes a [NetworkData] object as its argument and + /// should return a boolean value indicating whether the data should be omitted + /// (`true`) or included (`false`). + /// + /// Example: + /// + /// ```dart + /// NetworkLogger.omitLog((data) { + /// // Implement logic to decide whether to omit the data. + /// // For example, ignore requests to a specific URL: + /// return data.url.startsWith('https://example.com'); + /// }); + /// ``` + static void omitLog(OmitLogCallback callback) { + _manager.setOmitLogCallback(callback); + } + Future networkLog(NetworkData data) async { + final omit = await _manager.omitLog(data); + + if (omit) return; + final obfuscated = await _manager.obfuscateLog(data); await _host.networkLog(obfuscated.toJson()); diff --git a/lib/src/utils/network_manager.dart b/lib/src/utils/network_manager.dart index e212fb0ed..7aaf8f563 100644 --- a/lib/src/utils/network_manager.dart +++ b/lib/src/utils/network_manager.dart @@ -3,17 +3,24 @@ import 'dart:async'; import 'package:instabug_flutter/instabug_flutter.dart'; typedef ObfuscateLogCallback = FutureOr Function(NetworkData data); +typedef OmitLogCallback = FutureOr Function(NetworkData data); /// Mockable [NetworkManager] responsible for processing network logs /// before they are sent to the native SDKs. class NetworkManager { ObfuscateLogCallback? _obfuscateLogCallback; + OmitLogCallback? _omitLogCallback; // ignore: use_setters_to_change_properties void setObfuscateLogCallback(ObfuscateLogCallback callback) { _obfuscateLogCallback = callback; } + // ignore: use_setters_to_change_properties + void setOmitLogCallback(OmitLogCallback callback) { + _omitLogCallback = callback; + } + FutureOr obfuscateLog(NetworkData data) { if (_obfuscateLogCallback == null) { return data; @@ -21,4 +28,12 @@ class NetworkManager { return _obfuscateLogCallback!(data); } + + FutureOr omitLog(NetworkData data) { + if (_omitLogCallback == null) { + return false; + } + + return _omitLogCallback!(data); + } } diff --git a/test/network_logger_test.dart b/test/network_logger_test.dart index 6b6c8d6e9..e5a04e236 100644 --- a/test/network_logger_test.dart +++ b/test/network_logger_test.dart @@ -51,6 +51,7 @@ void main() { test('[networkLog] should call 1 host method on iOS', () async { when(mBuildInfo.isAndroid).thenReturn(false); when(mManager.obfuscateLog(data)).thenReturn(data); + when(mManager.omitLog(data)).thenReturn(false); await logger.networkLog(data); @@ -66,6 +67,7 @@ void main() { test('[networkLog] should call 2 host methods on Android', () async { when(mBuildInfo.isAndroid).thenReturn(true); when(mManager.obfuscateLog(data)).thenReturn(data); + when(mManager.omitLog(data)).thenReturn(false); await logger.networkLog(data); @@ -83,6 +85,7 @@ void main() { when(mBuildInfo.isAndroid).thenReturn(true); when(mManager.obfuscateLog(data)).thenReturn(obfuscated); + when(mManager.omitLog(data)).thenReturn(false); await logger.networkLog(data); @@ -99,6 +102,28 @@ void main() { ).called(1); }); + test('[networkLog] should not log data if it should be omitted', () async { + const omit = true; + + when(mBuildInfo.isAndroid).thenReturn(true); + when(mManager.obfuscateLog(data)).thenReturn(data); + when(mManager.omitLog(data)).thenReturn(omit); + + await logger.networkLog(data); + + verify( + mManager.omitLog(data), + ).called(1); + + verifyNever( + mInstabugHost.networkLog(data.toJson()), + ); + + verifyNever( + mApmHost.networkLogAndroid(data.toJson()), + ); + }); + test('[obfuscateLog] should set obfuscation callback on manager', () async { FutureOr callback(NetworkData data) => data; @@ -108,4 +133,14 @@ void main() { mManager.setObfuscateLogCallback(callback), ).called(1); }); + + test('[omitLog] should set omission callback on manager', () async { + FutureOr callback(NetworkData data) => true; + + NetworkLogger.omitLog(callback); + + verify( + mManager.setOmitLogCallback(callback), + ).called(1); + }); } diff --git a/test/network_manager_test.dart b/test/network_manager_test.dart index e47fa222b..31776c7ea 100644 --- a/test/network_manager_test.dart +++ b/test/network_manager_test.dart @@ -47,4 +47,33 @@ void main() { expect(result, equals(obfuscated)); }); + + test('[omitLog] should return false when no omit log callback', () async { + const expected = false; + + final result = await manager.omitLog(data); + + expect(result, equals(expected)); + }); + + test( + '[omitLog] should use omit callback when [setOmitLogCallback] has set a callback', + () async { + const omit = true; + final completer = Completer(); + FutureOr callback(NetworkData data) { + completer.complete(data); + return omit; + } + + manager.setOmitLogCallback(callback); + + final result = await manager.omitLog(data); + + expect(completer.isCompleted, isTrue); + + expect(await completer.future, data); + + expect(result, equals(omit)); + }); }