diff --git a/android/build.gradle b/android/build.gradle
index df5b447..03427ea 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -75,10 +75,16 @@ android {
dependencies {
implementation 'androidx.multidex:multidex:2.0.0'
implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
- implementation group: 'org.slf4j', name: 'slf4j-android', version: '1.7.25'
+
+ //"logback-android" required for programmatic control of global sl4j log level.
+ // - default log configuration in /assets/logback.xml
+ // - [ref] https://github.com/tony19/logback-android
+ implementation 'com.github.tony19:logback-android:3.0.0'
+ implementation 'org.slf4j:slf4j-api:2.0.7'
+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.10"
implementation "com.optimizely.ab:android-sdk:4.0.0-beta2"
- implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
+ implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.4'
implementation ('com.google.guava:guava:19.0') {
exclude group:'com.google.guava', module:'listenablefuture'
}
diff --git a/android/src/main/assets/logback.xml b/android/src/main/assets/logback.xml
new file mode 100644
index 0000000..8e6e0d6
--- /dev/null
+++ b/android/src/main/assets/logback.xml
@@ -0,0 +1,18 @@
+
+
+
+ Optimizely
+
+
+ %msg
+
+
+
+
+
+
+
diff --git a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/OptimizelyFlutterClient.java b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/OptimizelyFlutterClient.java
index 8d0ca28..82e3384 100644
--- a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/OptimizelyFlutterClient.java
+++ b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/OptimizelyFlutterClient.java
@@ -97,6 +97,8 @@ protected void initializeOptimizely(@NonNull ArgumentsParser argumentsParser, @N
maxQueueSize = argumentsParser.getEventMaxQueueSize();
}
+ Utils.setDefaultLogLevel(argumentsParser.getDefaultLogLevel());
+
DefaultEventHandler eventHandler = DefaultEventHandler.getInstance(context);
eventHandler.setDispatchInterval(-1L);
NotificationCenter notificationCenter = new NotificationCenter();
diff --git a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/ArgumentsParser.java b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/ArgumentsParser.java
index 605b0aa..88087c7 100644
--- a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/ArgumentsParser.java
+++ b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/ArgumentsParser.java
@@ -72,6 +72,10 @@ public List getDecideOptions() {
return Utils.getDecideOptions((List) arguments.get(Constants.RequestParameterKey.DECIDE_OPTIONS));
}
+ public String getDefaultLogLevel() {
+ return (String) arguments.get(Constants.RequestParameterKey.DEFAULT_LOG_LEVEL);
+ }
+
public String getFlagKey() {
return (String) arguments.get(Constants.RequestParameterKey.FLAG_KEY);
}
diff --git a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Constants.java b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Constants.java
index 2f200db..453b1d6 100644
--- a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Constants.java
+++ b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Constants.java
@@ -67,6 +67,7 @@ public static class RequestParameterKey {
public static final String ATTRIBUTES = "attributes";
public static final String DECIDE_KEYS = "keys";
public static final String DECIDE_OPTIONS = "optimizelyDecideOption";
+ public static final String DEFAULT_LOG_LEVEL = "defaultLogLevel";
public static final String EVENT_BATCH_SIZE = "eventBatchSize";
public static final String EVENT_TIME_INTERVAL = "eventTimeInterval";
public static final String EVENT_MAX_QUEUE_SIZE = "eventMaxQueueSize";
@@ -153,4 +154,11 @@ public static class SegmentOption {
public static final String IGNORE_CACHE = "ignoreCache";
public static final String RESET_CACHE = "resetCache";
}
+
+ public static class LogLevel {
+ public static final String ERROR = "error";
+ public static final String WARNING = "warning";
+ public static final String INFO = "info";
+ public static final String DEBUG = "debug";
+ }
}
diff --git a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Utils.java b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Utils.java
index 76ec8c8..a4353b5 100644
--- a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Utils.java
+++ b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Utils.java
@@ -20,6 +20,7 @@
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import androidx.annotation.Nullable;
import static com.optimizely.ab.notification.DecisionNotification.FeatureVariableDecisionNotificationBuilder.SOURCE_INFO;
@@ -31,6 +32,9 @@
import com.optimizely.ab.notification.UpdateConfigNotification;
import com.optimizely.ab.odp.ODPSegmentOption;
import com.optimizely.ab.optimizelydecision.OptimizelyDecideOption;
+import org.slf4j.LoggerFactory;
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
public class Utils {
@@ -104,4 +108,33 @@ public static Class getNotificationListenerType(String notificationType) {
}
return listenerClass;
}
+
+ // SLF4J log level control:
+ // - logback logger (ch.qos.logback) is the only option available that supports global log level control programmatically (not only via configuration file)
+ // - "logback-android" logger (com.github.tony19:logback-android) is integrated in build.gradle.
+ // - log-level control is not integrated into the native android-sdk core since this solution depends on logback logger.
+
+ public static void setDefaultLogLevel(@Nullable String logLevel) {
+ Level defaultLogLevel = Utils.mapLogLevel(logLevel);
+ Logger rootLogger = (Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
+ rootLogger.setLevel(defaultLogLevel);
+ }
+
+ public static Level mapLogLevel(@Nullable String logLevel) {
+ Level level = Level.INFO;
+
+ if (logLevel == null || logLevel.isEmpty()) {
+ return level;
+ }
+
+ switch (logLevel) {
+ case Constants.LogLevel.ERROR: level = Level.ERROR; break;
+ case Constants.LogLevel.WARNING: level = Level.WARN; break;
+ case Constants.LogLevel.INFO: level = Level.INFO; break;
+ case Constants.LogLevel.DEBUG: level = Level.DEBUG; break;
+ default: {}
+ }
+ return level;
+ }
+
}
diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle
index ceec9a6..89fc349 100644
--- a/example/android/app/build.gradle
+++ b/example/android/app/build.gradle
@@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
- compileSdkVersion flutter.compileSdkVersion
+ compileSdkVersion 32
ndkVersion flutter.ndkVersion
compileOptions {
@@ -40,7 +40,7 @@ android {
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion 21
- targetSdkVersion flutter.targetSdkVersion
+ targetSdkVersion 32
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
diff --git a/example/ios/Podfile b/example/ios/Podfile
index 9411102..313ea4a 100644
--- a/example/ios/Podfile
+++ b/example/ios/Podfile
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
-platform :ios, '10.0'
+platform :ios, '11.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
diff --git a/example/lib/main.dart b/example/lib/main.dart
index a717223..e7db8fa 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -32,6 +32,7 @@ class _MyAppState extends State {
datafilePeriodicDownloadInterval: 10 * 60,
eventOptions: const EventOptions(
batchSize: 1, timeInterval: 60, maxQueueSize: 10000),
+ defaultLogLevel: OptimizelyLogLevel.debug,
defaultDecideOptions: defaultOptions);
var response = await flutterSDK.initializeClient();
diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj
index 154f82d..9f89128 100644
--- a/example/macos/Runner.xcodeproj/project.pbxproj
+++ b/example/macos/Runner.xcodeproj/project.pbxproj
@@ -26,6 +26,7 @@
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
+ 90B9B075FD9D5B075E83BE96 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A8DB69DD1CEB9DE6D5A4070 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -52,9 +53,10 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 019D04A8C81D7599D2E638FA /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; };
- 33CC10ED2044A3C60003C045 /* optimizely_flutter_sdk_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "optimizely_flutter_sdk_example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 33CC10ED2044A3C60003C045 /* optimizely_flutter_sdk_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = optimizely_flutter_sdk_example.app; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; };
@@ -66,7 +68,10 @@
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; };
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; };
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; };
+ 5A8DB69DD1CEB9DE6D5A4070 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; };
+ 7EEA78DE428A25C4C9195EC6 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
+ 8D05B77804EBF39FD6D6D079 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; };
/* End PBXFileReference section */
@@ -75,6 +80,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 90B9B075FD9D5B075E83BE96 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -99,6 +105,7 @@
33CEB47122A05771004F2AC0 /* Flutter */,
33CC10EE2044A3C60003C045 /* Products */,
D73912EC22F37F3D000D13A0 /* Frameworks */,
+ F74646C1D5F338EF32BE10E1 /* Pods */,
);
sourceTree = "";
};
@@ -148,10 +155,22 @@
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 5A8DB69DD1CEB9DE6D5A4070 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "";
};
+ F74646C1D5F338EF32BE10E1 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ 7EEA78DE428A25C4C9195EC6 /* Pods-Runner.debug.xcconfig */,
+ 8D05B77804EBF39FD6D6D079 /* Pods-Runner.release.xcconfig */,
+ 019D04A8C81D7599D2E638FA /* Pods-Runner.profile.xcconfig */,
+ );
+ name = Pods;
+ path = Pods;
+ sourceTree = "";
+ };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -159,11 +178,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
+ 834CC0346DE4E8E368DFDFD4 /* [CP] Check Pods Manifest.lock */,
33CC10E92044A3C60003C045 /* Sources */,
33CC10EA2044A3C60003C045 /* Frameworks */,
33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */,
+ F96AA93D7120056FD027BD50 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -270,6 +291,45 @@
shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
};
+ 834CC0346DE4E8E368DFDFD4 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ F96AA93D7120056FD027BD50 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
diff --git a/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/example/macos/Runner.xcworkspace/contents.xcworkspacedata
index 1d526a1..21a3cc1 100644
--- a/example/macos/Runner.xcworkspace/contents.xcworkspacedata
+++ b/example/macos/Runner.xcworkspace/contents.xcworkspacedata
@@ -4,4 +4,7 @@
+
+
diff --git a/ios/Classes/HelperClasses/Constants.swift b/ios/Classes/HelperClasses/Constants.swift
index c674389..e5be618 100644
--- a/ios/Classes/HelperClasses/Constants.swift
+++ b/ios/Classes/HelperClasses/Constants.swift
@@ -90,6 +90,7 @@ struct RequestParameterKey {
static let eventTags = "eventTags"
static let reasons = "reasons"
static let decideOptions = "optimizelyDecideOption"
+ static let defaultLogLevel = "defaultLogLevel"
static let eventBatchSize = "eventBatchSize"
static let eventTimeInterval = "eventTimeInterval"
static let eventMaxQueueSize = "eventMaxQueueSize"
diff --git a/ios/Classes/HelperClasses/Utils.swift b/ios/Classes/HelperClasses/Utils.swift
index 82f858a..6cac144 100644
--- a/ios/Classes/HelperClasses/Utils.swift
+++ b/ios/Classes/HelperClasses/Utils.swift
@@ -202,4 +202,17 @@ public class Utils: NSObject {
return nil
}
}
+
+ static func getDefaultLogLevel(_ logLevel: String) -> OptimizelyLogLevel {
+ var defaultLogLevel: OptimizelyLogLevel
+ switch logLevel {
+ case "error": defaultLogLevel = OptimizelyLogLevel.error
+ case "warning": defaultLogLevel = OptimizelyLogLevel.warning
+ case "info": defaultLogLevel = OptimizelyLogLevel.info
+ case "debug": defaultLogLevel = OptimizelyLogLevel.debug
+ default: defaultLogLevel = OptimizelyLogLevel.info
+ }
+ return defaultLogLevel;
+ }
+
}
diff --git a/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift b/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift
index cdc1549..287b056 100644
--- a/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift
+++ b/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift
@@ -106,7 +106,12 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
decideOptions = options
}
let defaultDecideOptions = Utils.getDecideOptions(options: decideOptions)
-
+
+ var defaultLogLevel = OptimizelyLogLevel.info
+ if let logLevel = parameters[RequestParameterKey.defaultLogLevel] as? String {
+ defaultLogLevel = Utils.getDefaultLogLevel(logLevel)
+ }
+
// SDK Settings Default Values
var segmentsCacheSize: Int = 100
var segmentsCacheTimeoutInSecs: Int = 600
@@ -152,7 +157,14 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
optimizelyClientsTracker.removeValue(forKey: sdkKey)
// Creating new instance
- let optimizelyInstance = OptimizelyClient(sdkKey:sdkKey, eventDispatcher: eventDispatcher, datafileHandler: datafileHandler, periodicDownloadInterval: datafilePeriodicDownloadInterval, defaultDecideOptions: defaultDecideOptions, settings: optimizelySdkSettings)
+ let optimizelyInstance = OptimizelyClient(
+ sdkKey:sdkKey,
+ eventDispatcher: eventDispatcher,
+ datafileHandler: datafileHandler,
+ periodicDownloadInterval: datafilePeriodicDownloadInterval,
+ defaultLogLevel: defaultLogLevel,
+ defaultDecideOptions: defaultDecideOptions,
+ settings: optimizelySdkSettings)
optimizelyInstance.start{ [weak self] res in
switch res {
diff --git a/lib/optimizely_flutter_sdk.dart b/lib/optimizely_flutter_sdk.dart
index 775130f..51dc9af 100644
--- a/lib/optimizely_flutter_sdk.dart
+++ b/lib/optimizely_flutter_sdk.dart
@@ -27,6 +27,7 @@ import 'package:optimizely_flutter_sdk/src/data_objects/get_variation_response.d
import 'package:optimizely_flutter_sdk/src/data_objects/optimizely_config_response.dart';
import 'package:optimizely_flutter_sdk/src/optimizely_client_wrapper.dart';
import 'package:optimizely_flutter_sdk/src/user_context/optimizely_user_context.dart';
+import 'package:optimizely_flutter_sdk/src/data_objects/log_level.dart';
export 'package:optimizely_flutter_sdk/src/optimizely_client_wrapper.dart'
show ClientPlatform, ListenerType;
@@ -50,6 +51,8 @@ export 'package:optimizely_flutter_sdk/src/data_objects/sdk_settings.dart'
show SDKSettings;
export 'package:optimizely_flutter_sdk/src/data_objects/datafile_options.dart'
show DatafileHostOptions;
+export 'package:optimizely_flutter_sdk/src/data_objects/log_level.dart'
+ show OptimizelyLogLevel;
/// The main client class for the Optimizely Flutter SDK.
///
@@ -63,6 +66,7 @@ class OptimizelyFlutterSdk {
final int _datafilePeriodicDownloadInterval;
final Map _datafileHostOptions;
final Set _defaultDecideOptions;
+ final OptimizelyLogLevel _defaultLogLevel;
final SDKSettings _sdkSettings;
OptimizelyFlutterSdk(this._sdkKey,
{EventOptions eventOptions = const EventOptions(),
@@ -70,11 +74,13 @@ class OptimizelyFlutterSdk {
10 * 60, // Default time interval in seconds
Map datafileHostOptions = const {},
Set defaultDecideOptions = const {},
+ OptimizelyLogLevel defaultLogLevel = OptimizelyLogLevel.info,
SDKSettings sdkSettings = const SDKSettings()})
: _eventOptions = eventOptions,
_datafilePeriodicDownloadInterval = datafilePeriodicDownloadInterval,
_datafileHostOptions = datafileHostOptions,
_defaultDecideOptions = defaultDecideOptions,
+ _defaultLogLevel = defaultLogLevel,
_sdkSettings = sdkSettings;
/// Starts Optimizely SDK (Synchronous) with provided sdkKey.
@@ -85,6 +91,7 @@ class OptimizelyFlutterSdk {
_datafilePeriodicDownloadInterval,
_datafileHostOptions,
_defaultDecideOptions,
+ _defaultLogLevel,
_sdkSettings);
}
diff --git a/lib/src/data_objects/log_level.dart b/lib/src/data_objects/log_level.dart
new file mode 100644
index 0000000..c2eacd3
--- /dev/null
+++ b/lib/src/data_objects/log_level.dart
@@ -0,0 +1,22 @@
+/// **************************************************************************
+/// Copyright 2023, Optimizely, Inc. and contributors *
+/// *
+/// 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. *
+///**************************************************************************/
+
+enum OptimizelyLogLevel {
+ error,
+ warning,
+ info,
+ debug
+}
diff --git a/lib/src/optimizely_client_wrapper.dart b/lib/src/optimizely_client_wrapper.dart
index e26b74f..bb2c4c0 100644
--- a/lib/src/optimizely_client_wrapper.dart
+++ b/lib/src/optimizely_client_wrapper.dart
@@ -27,6 +27,8 @@ import 'package:optimizely_flutter_sdk/src/data_objects/optimizely_config_respon
import 'package:optimizely_flutter_sdk/src/utils/constants.dart';
import 'package:optimizely_flutter_sdk/src/utils/utils.dart';
+import 'data_objects/log_level.dart';
+
enum ListenerType { activate, track, decision, logEvent, projectConfigUpdate }
enum ClientPlatform { iOS, android }
@@ -61,14 +63,17 @@ class OptimizelyClientWrapper {
int datafilePeriodicDownloadInterval,
Map datafileHostOptions,
Set defaultDecideOptions,
+ OptimizelyLogLevel defaultLogLevel,
SDKSettings sdkSettings) async {
_channel.setMethodCallHandler(methodCallHandler);
final convertedOptions = Utils.convertDecideOptions(defaultDecideOptions);
+ final convertedLogLevel = Utils.convertLogLevel(defaultLogLevel);
Map requestDict = {
Constants.sdkKey: sdkKey,
Constants.datafilePeriodicDownloadInterval:
datafilePeriodicDownloadInterval,
Constants.optimizelyDecideOption: convertedOptions,
+ Constants.defaultLogLevel: convertedLogLevel,
Constants.eventBatchSize: eventOptions.batchSize,
Constants.eventTimeInterval: eventOptions.timeInterval,
Constants.eventMaxQueueSize: eventOptions.maxQueueSize,
diff --git a/lib/src/utils/constants.dart b/lib/src/utils/constants.dart
index f6a61d5..d5bc3ff 100644
--- a/lib/src/utils/constants.dart
+++ b/lib/src/utils/constants.dart
@@ -83,6 +83,7 @@ class Constants {
static const String optimizelyDecideOption = "optimizelyDecideOption";
static const String optimizelySegmentOption = "optimizelySegmentOption";
static const String optimizelySdkSettings = "optimizelySdkSettings";
+ static const String defaultLogLevel = "defaultLogLevel";
static const String payload = "payload";
static const String value = "value";
static const String type = "type";
diff --git a/lib/src/utils/utils.dart b/lib/src/utils/utils.dart
index da36841..782178e 100644
--- a/lib/src/utils/utils.dart
+++ b/lib/src/utils/utils.dart
@@ -18,6 +18,7 @@ import 'dart:io' show Platform;
import 'package:optimizely_flutter_sdk/src/user_context/optimizely_user_context.dart';
import 'package:optimizely_flutter_sdk/src/utils/constants.dart';
+import 'package:optimizely_flutter_sdk/src/data_objects/log_level.dart';
class Utils {
static Map decideOptions = {
@@ -94,4 +95,10 @@ class Utils {
Set options) {
return options.map((option) => Utils.segmentOptions[option]!).toList();
}
+
+ static String convertLogLevel(OptimizelyLogLevel logLevel) {
+ // OptimizelyLogLevel.error -> "error"
+ // OptimizelyLogLevel.debug -> "debug"
+ return logLevel.toString().split('.').last;
+ }
}
diff --git a/test/optimizely_flutter_sdk_test.dart b/test/optimizely_flutter_sdk_test.dart
index fa81adb..debf769 100644
--- a/test/optimizely_flutter_sdk_test.dart
+++ b/test/optimizely_flutter_sdk_test.dart
@@ -56,6 +56,7 @@ void main() {
DatafileHostOptions datafileHostOptions = const DatafileHostOptions("", "");
SDKSettings sdkSettings = const SDKSettings();
int datafilePeriodicDownloadInterval = 0;
+ String defaultLogLevel = "error";
const MethodChannel channel = MethodChannel("optimizely_flutter_sdk");
dynamic mockOptimizelyConfig;
@@ -83,6 +84,9 @@ void main() {
case Constants.initializeMethod:
expect(methodCall.arguments[Constants.sdkKey], isNotEmpty);
expect(methodCall.arguments[Constants.userContextId], isNull);
+
+ defaultLogLevel = methodCall.arguments[Constants.defaultLogLevel];
+
// To Check if eventOptions were received
eventOptions = EventOptions(
batchSize: methodCall.arguments[Constants.eventBatchSize],
@@ -542,6 +546,33 @@ void main() {
});
});
+ group("log level configuration", () {
+ test("with no defaultLogLevel, log level should be info level", () async {
+ var sdk = OptimizelyFlutterSdk(testSDKKey);
+
+ var response = await sdk.initializeClient();
+
+ expect(response.success, isTrue);
+ expect(defaultLogLevel, equals("info"));
+ });
+
+ test("with a valid defaultLogLevel parameter", () async {
+ var sdk = OptimizelyFlutterSdk(testSDKKey, defaultLogLevel: OptimizelyLogLevel.debug);
+
+ var response = await sdk.initializeClient();
+
+ expect(response.success, isTrue);
+ expect(defaultLogLevel, equals("debug"));
+ });
+
+ test("should convert OptimizelyLogLevel to string", () async {
+ expect(Utils.convertLogLevel(OptimizelyLogLevel.error), "error");
+ expect(Utils.convertLogLevel(OptimizelyLogLevel.warning), "warning");
+ expect(Utils.convertLogLevel(OptimizelyLogLevel.info), "info");
+ expect(Utils.convertLogLevel(OptimizelyLogLevel.debug), "debug");
+ });
+ });
+
group("close()", () {
test("should succeed", () async {
var sdk = OptimizelyFlutterSdk(testSDKKey);