diff --git a/.github/workflows/deploy-cocoapods.yml b/.github/workflows/deploy-cocoapods.yml index 4e5f327b..f3fbfd5a 100644 --- a/.github/workflows/deploy-cocoapods.yml +++ b/.github/workflows/deploy-cocoapods.yml @@ -8,7 +8,6 @@ jobs: build: name: Deploy to Cocoapods runs-on: macOS-latest - if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - name: Checkout source branch uses: actions/checkout@v4 diff --git a/.github/workflows/deploy-private-pod.yml b/.github/workflows/deploy-private-pod.yml index 05fee893..f78e23f5 100644 --- a/.github/workflows/deploy-private-pod.yml +++ b/.github/workflows/deploy-private-pod.yml @@ -13,18 +13,22 @@ jobs: runs-on: macOS-latest if: (startsWith(github.event.pull_request.head.ref, 'release/') || startsWith(github.event.pull_request.head.ref, 'hotfix-release/')) steps: - - name: Checkout + - name: 'Checkout' uses: actions/checkout@v4 with: ref: '${{ github.event.pull_request.head.ref }}' - - name: Install Cocoapods + - name: 'Install Cocoapods' run: gem install cocoapods + + - name: 'Convert podspec to podspec.json' + run: | + pod ipc spec Rudder.podspec > Rudder.podspec.json - - name: Add Private Spec Repo to CocoaPods installation + - name: 'Add Private Spec Repo to CocoaPods installation' run: | - pod repo add Rudder https://${{secrets.PAT_USERNAME}}:${{secrets.PAT}}@github.com/rudderlabs/Specs.git + pod repo add rudderlabs https://${{secrets.PAT_USERNAME}}:${{secrets.PAT}}@github.com/rudderlabs/Specs.git - - name: Add Podspec to repo + - name: 'Add Podspec to repo' run: | - pod repo push Rudder Rudder.podspec + pod repo push rudderlabs Rudder.podspec.json diff --git a/.github/workflows/draft-new-beta-release.yml b/.github/workflows/draft-new-beta-release.yml index f58115a9..bbe91b24 100644 --- a/.github/workflows/draft-new-beta-release.yml +++ b/.github/workflows/draft-new-beta-release.yml @@ -82,18 +82,22 @@ jobs: run: | git push - - name: Checkout + - name: 'Checkout' uses: actions/checkout@v4 with: ref: '${{ steps.create-release.outputs.branch_name }}' - - name: Install Cocoapods + - name: 'Install Cocoapods' run: gem install cocoapods - - name: Add Private Spec Repo to CocoaPods installation + - name: 'Convert podspec to podspec.json' run: | - pod repo add Rudder https://${{secrets.PAT_USERNAME}}:${{secrets.PAT}}@github.com/rudderlabs/Specs.git + pod ipc spec Rudder.podspec > Rudder.podspec.json - - name: Add Podspec to repo + - name: 'Add Private Spec Repo to CocoaPods installation' run: | - pod repo push Rudder Rudder.podspec + pod repo add rudderlabs https://${{secrets.PAT_USERNAME}}:${{secrets.PAT}}@github.com/rudderlabs/Specs.git + + - name: 'Add Podspec to repo' + run: | + pod repo push rudderlabs Rudder.podspec.json diff --git a/.github/workflows/slack-notify.yml b/.github/workflows/slack-notify.yml index 3049addb..40d90e8e 100644 --- a/.github/workflows/slack-notify.yml +++ b/.github/workflows/slack-notify.yml @@ -8,7 +8,6 @@ jobs: deploy-tag: name: Notify Slack runs-on: ubuntu-latest - if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - name: Send message to Slack channel id: slack diff --git a/CHANGELOG.md b/CHANGELOG.md index fbe1ea65..92c42e29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.23.0](https://github.com/rudderlabs/rudder-sdk-ios/compare/v1.22.0...v1.23.0) (2023-10-09) + + +### Features + +* metrics for DMT and DBEncryption ([#404](https://github.com/rudderlabs/rudder-sdk-ios/issues/404)) ([e863f72](https://github.com/rudderlabs/rudder-sdk-ios/commit/e863f72f9f53e4600d1de074bbb9591c2337153a)) + + +### Bug Fixes + +* fixed issues related to DBEncryption in RSDBPersistentManager and enhanced error handling ([#403](https://github.com/rudderlabs/rudder-sdk-ios/issues/403)) ([2e9c2cf](https://github.com/rudderlabs/rudder-sdk-ios/commit/2e9c2cf0bbac631bfa960adc778c044b3368d709)) + ## [1.22.0](https://github.com/rudderlabs/rudder-sdk-ios/compare/v1.20.0...v1.22.0) (2023-09-28) diff --git a/README.md b/README.md index dd080996..ba95f421 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@
@@ -39,7 +39,7 @@ The iOS SDK is available through [**CocoaPods**](https://cocoapods.org), [**Cart To install the SDK, simply add the following line to your Podfile: ```xcode -pod 'Rudder', '1.22.0' +pod 'Rudder', '1.23.0' ``` ### Carthage @@ -47,7 +47,7 @@ pod 'Rudder', '1.22.0' For Carthage support, add the following line to your `Cartfile`: ```xcode -github "rudderlabs/rudder-sdk-ios" "v1.22.0" +github "rudderlabs/rudder-sdk-ios" "v1.23.0" ``` > Remember to include the following code in all `.m` and `.h` files where you want to refer to or use the RudderStack SDK classes, as shown: @@ -71,7 +71,7 @@ You can also add the RudderStack iOS SDK via Swift Package Mangaer, via one of t * Enter the package repository (`git@github.com:rudderlabs/rudder-sdk-ios.git`) in the search bar. -* In **Dependency Rule**, select **Up to Next Major Version** and enter `1.22.0` as the value, as shown: +* In **Dependency Rule**, select **Up to Next Major Version** and enter `1.23.0` as the value, as shown: ![Setting dependency](https://user-images.githubusercontent.com/59817155/145574696-8c849749-13e0-40d5-aacb-3fccb5c8e67d.png) @@ -99,7 +99,7 @@ let package = Package( ], dependencies: [ // Dependencies declare other packages that this package depends on. - .package(url: "git@github.com:rudderlabs/rudder-sdk-ios.git", from: "1.22.0") + .package(url: "git@github.com:rudderlabs/rudder-sdk-ios.git", from: "1.23.0") ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/Rudder.podspec b/Rudder.podspec index 68fac6b0..a0c44e6c 100644 --- a/Rudder.podspec +++ b/Rudder.podspec @@ -12,7 +12,7 @@ Pod::Spec.new do |s| s.homepage = "https://github.com/rudderlabs/rudder-sdk-ios" s.license = { :type => "Apache", :file => "LICENSE" } - s.author = { "RudderStack" => "arnab@rudderlabs.com" } + s.author = { "RudderStack" => "sdk@rudderstack.com" } s.source = { :git => "https://github.com/rudderlabs/rudder-sdk-ios.git", :tag => "v#{s.version}" } s.ios.deployment_target = '12.0' diff --git a/Sources/Classes/Headers/Public/RSMetricsReporter.h b/Sources/Classes/Headers/Public/RSMetricsReporter.h index c7000856..52916c5c 100644 --- a/Sources/Classes/Headers/Public/RSMetricsReporter.h +++ b/Sources/Classes/Headers/Public/RSMetricsReporter.h @@ -32,6 +32,11 @@ extern NSString *const SDKMETRICS_SC_ATTEMPT_ABORT; extern NSString *const SDKMETRICS_CM_ATTEMPT_SUCCESS; extern NSString *const SDKMETRICS_CM_ATTEMPT_RETRY; extern NSString *const SDKMETRICS_CM_ATTEMPT_ABORT; +extern NSString *const SDKMETRICS_DMT_SUBMITTED; +extern NSString *const SDKMETRICS_DMT_SUCCESS; +extern NSString *const SDKMETRICS_DMT_DISCARD; +extern NSString *const SDKMETRICS_DMT_RETRY; +extern NSString *const SDKMETRICS_DB_ENCRYPT; extern NSString *const SDKMETRICS_TYPE; extern NSString *const SDKMETRICS_OPT_OUT; @@ -50,6 +55,12 @@ extern NSString *const SDKMETRICS_SOURCE_DISABLED; extern NSString *const SDKMETRICS_WRITEKEY_INVALID; extern NSString *const SDKMETRICS_INTEGRATION; extern NSString *const SDKMETRICS_REQUEST_TIMEOUT; +extern NSString *const SDKMETRICS_CREATED; +extern NSString *const SDKMETRICS_MIGRATE_TO_ENCRYPT; +extern NSString *const SDKMETRICS_MIGRATE_TO_DECRYPT; +extern NSString *const SDKMETRICS_RESOURCE_NOT_FOUND; +extern NSString *const SDKMETRICS_BAD_REQUEST; +extern NSString *const SDKMETRICS_MAX_RETRIES_EXHAUSTED; @end diff --git a/Sources/Classes/Headers/RSVersion.h b/Sources/Classes/Headers/RSVersion.h index daa9cebd..0bbd1018 100644 --- a/Sources/Classes/Headers/RSVersion.h +++ b/Sources/Classes/Headers/RSVersion.h @@ -8,6 +8,6 @@ #ifndef RSVersion_h #define RSVersion_h -NSString *const SDK_VERSION = @"1.22.0"; +NSString *const SDK_VERSION = @"1.23.0"; #endif /* RSVersion_h */ diff --git a/Sources/Classes/RSDBPersistentManager.m b/Sources/Classes/RSDBPersistentManager.m index 5fc27b13..5010164c 100644 --- a/Sources/Classes/RSDBPersistentManager.m +++ b/Sources/Classes/RSDBPersistentManager.m @@ -24,6 +24,7 @@ NSString* _Nonnull const COL_DM_PROCESSED = @"dm_processed"; NSString* _Nonnull const ENCRYPTED_DB_NAME = @"rl_persistence_encrypted.sqlite"; NSString* _Nonnull const UNENCRYPTED_DB_NAME = @"rl_persistence.sqlite"; +NSString* _Nonnull const SQLCIPHER_TEST_DB_NAME = @"rl_sqlcipher_test_db.sqlite"; @implementation RSDBPersistentManager { NSLock* lock; @@ -34,9 +35,13 @@ @implementation RSDBPersistentManager { - (instancetype)initWithDBEncryption:(RSDBEncryption * __nullable)dbEncryption { self = [super init]; if (self) { - self->lock = [[NSLock alloc] init]; self->database = [[self getDatabaseProvider:dbEncryption] getDatabase]; + + self->lock = [[NSLock alloc] init]; + [self->lock lock]; [self createDB:dbEncryption]; + [self->lock unlock]; + isReturnClauseSupported = [self doesReturnClauseExists]; if(isReturnClauseSupported) { [RSLogger logVerbose:@"RSDBPersistentManager: init: SQLiteVersion is >=3.35.0, hence return clause can be used"]; @@ -51,16 +56,22 @@ - (instancetype)initWithDBEncryption:(RSDBEncryption * __nullable)dbEncryption { if (dbEncryption == nil) { return [RSDefaultDatabaseProvider new]; } else { + [RSMetricsReporter report:SDKMETRICS_DB_ENCRYPT forMetricType:COUNT withProperties:@{SDKMETRICS_TYPE: SDKMETRICS_CREATED} andValue:1]; return dbEncryption.databaseProvider; } } - (void)createDB:(RSDBEncryption * __nullable)dbEncryption { - [self->lock lock]; BOOL isEncryptedDBExists = [RSUtils isFileExists:ENCRYPTED_DB_NAME]; BOOL isUnencryptedDBExists = [RSUtils isFileExists:UNENCRYPTED_DB_NAME]; BOOL isEncryptionNeeded = [self isEncryptionNeeded:dbEncryption]; - + + if (isEncryptionNeeded && ![self isSQLCipherAvailable]) { + [RSLogger logError:@"RSDBPersistentManager: createDB: Cannot encrypt the Database as SQLCipher wasn't linked correctly"]; + isEncryptionNeeded = NO; + } + + // when both encrypted and unencrypted db doesn't exists if (!isEncryptedDBExists && !isUnencryptedDBExists) { // fresh Install if (isEncryptionNeeded) { @@ -71,86 +82,50 @@ - (void)createDB:(RSDBEncryption * __nullable)dbEncryption { [self openUnencryptedDB]; } } else if (isEncryptedDBExists) { - if (isEncryptionNeeded) { - // open encrypted database with key - int code = [self openEncryptedDB:dbEncryption.key]; - if (code == SQLITE_NOTADB) { - // when key is wrong - // delete encrypted database; then open new encrypted database - // all previous events will be deleted - [RSLogger logError:@"RSDBPersistentManager: createDB: Wrong key is provided. Deleting encrypted DB and creating a new unencrypted DB"]; - [self closeDB]; - [RSUtils removeFile:ENCRYPTED_DB_NAME]; - [self openEncryptedDB:dbEncryption.key]; - } - } else { - if (dbEncryption == nil || dbEncryption.key == nil) { - // no key is provided - // delete encrypted database; then open unencrypted database - // all previous events will be deleted - [RSLogger logError:@"RSDBPersistentManager: createDB: No key is provided. Deleting encrypted DB and creating a new unencrypted DB"]; - [RSUtils removeFile:ENCRYPTED_DB_NAME]; - [self openUnencryptedDB]; - } else { - int code = [self openEncryptedDB:dbEncryption.key]; - switch (code) { - // when key is correct - // decyprt database; then open unencrypted database - case SQLITE_OK: { - code = [self decryptDB:dbEncryption.key]; - if (code == SQLITE_OK) { - [self closeDB]; - [RSUtils removeFile:ENCRYPTED_DB_NAME]; - [self openUnencryptedDB]; - } else { - [RSLogger logError:[NSString stringWithFormat:@"RSDBPersistentManager: createDB: Failed to decrypt, error code: %d", code]]; - } - } - break; - // when key is wrong - // delete encrypted database; then open unencrypted database - // all previous events will be deleted - case SQLITE_NOTADB: { - [RSLogger logError:@"RSDBPersistentManager: createDB: Wrong key is provided. Deleting encrypted DB and creating a new unencrypted DB"]; - [self closeDB]; - [RSUtils removeFile:ENCRYPTED_DB_NAME]; - [self openUnencryptedDB]; - } - break; - default: - [RSLogger logError:[NSString stringWithFormat:@"RSDBPersistentManager: createDB: Failed to decrypt, error code: %d", code]]; - break; - } - } - } + // when only encrypted db exists + [self handleWhenEncryptedDBExists:dbEncryption isEncryptionNeeded:isEncryptionNeeded]; } else { - if (isEncryptionNeeded) { - // encyprt database; then open encrypted database - [self openUnencryptedDB]; - int code = [self encryptDB:dbEncryption.key]; - if (code == SQLITE_OK) { - [self closeDB]; - [RSUtils removeFile:UNENCRYPTED_DB_NAME]; - [self openEncryptedDB:dbEncryption.key]; - } else { - [RSLogger logError:[NSString stringWithFormat:@"RSDBPersistentManager: createDB: Failed to encrypt, error code: %d", code]]; - } - } else { - // open unencrypted database - [self openUnencryptedDB]; - } + // when only unencrypted db exists + [self handleWhenUnencryptedDBExists:dbEncryption isEncryptionNeeded:isEncryptionNeeded]; } - [self->lock unlock]; } - (BOOL)isEncryptionNeeded:(RSDBEncryption * __nullable)dbEncryption { if (dbEncryption == nil) return NO; - if (dbEncryption.enable && [dbEncryption.key length] > 0) + if (dbEncryption.enable && [self doesEncryptionKeyExists:dbEncryption]) return YES; return NO; } +- (BOOL)doesEncryptionKeyExists:(RSDBEncryption * __nullable)dbEncryption { + if (dbEncryption == nil || dbEncryption.key == nil || [dbEncryption.key length] == 0) + return NO; + return YES; +} + +- (BOOL) isSQLCipherAvailable { + BOOL isSQLCipherAvailable = NO; + @try { + void *stmt = nil; + if ([database open_v2:[[self getSQLCipherTestDBPath] UTF8String] flags:SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX zVfs:NULL] == SQLITE_OK && [database prepare_v2:"PRAGMA cipher_version;" nBytes:-1 ppStmt:&stmt pzTail:NULL] == SQLITE_OK) { + if ([database step:stmt] == SQLITE_ROW) { + const unsigned char *ver = [database column_text:stmt i:0]; + if(ver != NULL) { + isSQLCipherAvailable = YES; + } + } + [database finalize:stmt]; + } + [self closeDB]; + } + @catch (NSException *exception) { + [RSLogger logError:[NSString stringWithFormat:@"RSDBPersistentManager: isSQLCipherAvailable: Failed to check if SQLCipher is available, reason: %@", exception.reason]]; + } + [RSUtils removeFile:SQLCIPHER_TEST_DB_NAME]; + return isSQLCipherAvailable; +} + - (void)openUnencryptedDB { int executeCode = [database open_v2:[[self getUnencryptedDBPath] UTF8String] flags:SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX zVfs:NULL]; if (executeCode == SQLITE_OK) { @@ -176,6 +151,105 @@ - (int)openEncryptedDB:(NSString *)encryptionKey { return executeCode; } +- (void)handleWhenEncryptedDBExists:(RSDBEncryption * _Nullable)dbEncryption isEncryptionNeeded:(BOOL)isEncryptionNeeded { + if (isEncryptionNeeded) { + // open encrypted database with key + int code = [self openEncryptedDB:dbEncryption.key]; + if (code == SQLITE_NOTADB) { + // when key is wrong + // delete encrypted database; then open new encrypted database + // all previous events will be deleted + [RSLogger logError:@"RSDBPersistentManager: createDB: Wrong key is provided. Deleting previous encrypted DB and creating a new encrypted DB"]; + [self closeDB]; + [RSUtils removeFile:ENCRYPTED_DB_NAME]; + [self openEncryptedDB:dbEncryption.key]; + } + return; + } + + // when encryption is not needed and no key is provided + // delete encrypted database; then open unencrypted database + // all previous events will be deleted + if (![self doesEncryptionKeyExists:dbEncryption]) { + [RSLogger logError:@"RSDBPersistentManager: createDB: No key is provided. Deleting encrypted DB and creating a new unencrypted DB"]; + [RSUtils removeFile:ENCRYPTED_DB_NAME]; + [self openUnencryptedDB]; + return; + } + + // when encryption is not needed and a key is provided + int code = [self openEncryptedDB:dbEncryption.key]; + switch (code) { + // when key is correct + // decyprt database; then open unencrypted database + case SQLITE_OK: { + code = [self decryptDB:dbEncryption.key]; + if (code == SQLITE_OK) { + [self deleteEncryptedAndOpenUnEncryptedDB]; + } else { + // when decryption of encrypted database failed + // delete encrypted database; then open unencrypted database + // all previous events will be deleted + [RSLogger logError:[NSString stringWithFormat:@"RSDBPersistentManager: createDB: Failed to decrypt the existing encrypted db, creating a new unencrypted db, error code: %d", code]]; + [self deleteEncryptedAndOpenUnEncryptedDB]; + } + } + break; + + // when key is wrong + // delete encrypted database; then open unencrypted database + // all previous events will be deleted + case SQLITE_NOTADB: { + [RSLogger logError:@"RSDBPersistentManager: createDB: Wrong key is provided. Deleting encrypted DB and creating a new unencrypted DB"]; + [self deleteEncryptedAndOpenUnEncryptedDB]; + } + break; + + default: + // when failed to open encrypted database due to any reason + // delete encrypted database; then open unencrypted database + // all previous events will be deleted + [RSLogger logError:[NSString stringWithFormat:@"RSDBPersistentManager: createDB: Failed to open the existing encrypted DB, creating a new unencrypted db, error code: %d", code]]; + [self deleteEncryptedAndOpenUnEncryptedDB]; + break; + } + +} + +- (void)handleWhenUnencryptedDBExists:(RSDBEncryption * _Nullable)dbEncryption isEncryptionNeeded:(BOOL)isEncryptionNeeded { + if (isEncryptionNeeded) { + // encrypt database; then open encrypted database + [self openUnencryptedDB]; + int code = [self encryptDB:dbEncryption.key]; + if (code == SQLITE_OK) { + [self deleteUnEncryptedAndOpenEncryptedDB:dbEncryption]; + } else { + // when encryption failed + // delete unencrypted database; then create new encrypted database + // all previous events will be deleted + [RSLogger logError:[NSString stringWithFormat:@"RSDBPersistentManager: createDB: Failed to encrypt the existing unecnrypted db, creating a new encrypted db, error code: %d", code]]; + [self deleteUnEncryptedAndOpenEncryptedDB:dbEncryption]; + } + } else { + // open unencrypted database + [self openUnencryptedDB]; + } +} + + +- (void)deleteEncryptedAndOpenUnEncryptedDB { + [self closeDB]; + [RSUtils removeFile:ENCRYPTED_DB_NAME]; + [self openUnencryptedDB]; +} + +- (void)deleteUnEncryptedAndOpenEncryptedDB:(RSDBEncryption * _Nullable)dbEncryption { + [self closeDB]; + [RSUtils removeFile:UNENCRYPTED_DB_NAME]; + [self openEncryptedDB:dbEncryption.key]; +} + + - (int)encryptDB:(NSString *)key { const char* attachDBSQL = [[NSString stringWithFormat:@"ATTACH DATABASE '%@' AS rl_persistence_encrypted KEY '%@';", [self getEncryptedDBPath], key] UTF8String]; @@ -218,6 +292,10 @@ - (int)decryptDB:(NSString *)key { return code; } +- (NSString *)getSQLCipherTestDBPath { + return [RSUtils getFilePath:SQLCIPHER_TEST_DB_NAME]; +} + - (NSString *)getEncryptedDBPath { return [RSUtils getFilePath:ENCRYPTED_DB_NAME]; } diff --git a/Sources/Classes/RSDeviceModeManager.m b/Sources/Classes/RSDeviceModeManager.m index 6492f20b..ac7dffca 100644 --- a/Sources/Classes/RSDeviceModeManager.m +++ b/Sources/Classes/RSDeviceModeManager.m @@ -252,6 +252,7 @@ -(void) dumpTransformedEvents:(NSArray*) transformedPayloads toDestinationId:(NS } RSMessage* transformedMessage = [[RSMessage alloc] initWithDict:transformedPayload[@"event"]]; [self dumpEvent:transformedMessage toDestinations:@[destinationName] withLogTag:@"dumpTransformedEvents"]; + [RSMetricsReporter report: SDKMETRICS_DMT_SUCCESS forMetricType:COUNT withProperties:@{SDKMETRICS_TYPE: transformedMessage.type} andValue:1]; continue; } NSNumber* orderNo = [NSNumber numberWithInt:[transformedPayload[@"orderNo"] intValue]]; diff --git a/Sources/Classes/RSDeviceModeTransformationManager.m b/Sources/Classes/RSDeviceModeTransformationManager.m index 51d4edfd..221bea95 100644 --- a/Sources/Classes/RSDeviceModeTransformationManager.m +++ b/Sources/Classes/RSDeviceModeTransformationManager.m @@ -7,6 +7,7 @@ // #import "RSDeviceModeTransformationManager.h" +#import "RSMetricsReporter.h" int const DMT_BATCH_SIZE = 12; int const MAX_RETRIES = 2; // Maximum number of retries @@ -60,6 +61,7 @@ - (void) transformationProcessor { NSString* responsePayload = response.responsePayload; if (response.state == WRONG_WRITE_KEY) { [RSLogger logDebug:@"RSDeviceModeTransformationManager: TransformationProcessor: Wrong WriteKey. Aborting the TransformationProcessor."]; + [RSMetricsReporter report:SDKMETRICS_DMT_DISCARD forMetricType:COUNT withProperties:@{SDKMETRICS_TYPE: SDKMETRICS_WRITEKEY_INVALID} andValue:1]; break; } else if (response.state == INVALID_URL) { [RSLogger logDebug:@"RSDeviceModeTransformationManager: TransformationProcessor: Invalid Data Plane URL. Aborting the TransformationProcessor"]; @@ -69,6 +71,7 @@ - (void) transformationProcessor { break; } else if (response.state == BAD_REQUEST) { [RSLogger logWarn:@"RSDeviceModeTransformationManager: TransformationProcessor: Bad Request, dumping back the original events to the factories"]; + [RSMetricsReporter report:SDKMETRICS_DMT_DISCARD forMetricType:COUNT withProperties:@{SDKMETRICS_TYPE: SDKMETRICS_BAD_REQUEST} andValue:1]; [strongSelf->deviceModeManager dumpOriginalEventsOnTransformationError:request.batch]; [strongSelf completeDeviceModeEventProcessing:dbMessage]; } @@ -78,13 +81,16 @@ - (void) transformationProcessor { retryCount = 0; deviceModeSleepCount = 0; [RSLogger logWarn:[NSString stringWithFormat:@"RSDeviceModeTransformationManager: TransformationProcessor: Failed to transform events even after %d retries, hence dumping back the original events to the factories", MAX_RETRIES]]; + [RSMetricsReporter report:SDKMETRICS_DMT_DISCARD forMetricType:COUNT withProperties:@{SDKMETRICS_TYPE: SDKMETRICS_MAX_RETRIES_EXHAUSTED} andValue:1]; [strongSelf->deviceModeManager dumpOriginalEventsOnTransformationError:request.batch]; [strongSelf completeDeviceModeEventProcessing:dbMessage]; } else { [RSLogger logDebug:[NSString stringWithFormat:@"RSDeviceModeTransformationManager: TransformationProcessor: Network Error, Retrying again in %.2f s", (NSTimeInterval)delay/1000]]; + [RSMetricsReporter report:SDKMETRICS_DMT_RETRY forMetricType:COUNT withProperties:nil andValue:1]; usleep((useconds_t)delay* 1000); } } else if (response.state == RESOURCE_NOT_FOUND) { // So when the customer is not eligible for Device Mode Transformations, we get RESOURCE_NOT_FOUND, and in this case we will dump the original methods itself to the factories. + [RSMetricsReporter report:SDKMETRICS_DMT_DISCARD forMetricType:COUNT withProperties:@{SDKMETRICS_TYPE: SDKMETRICS_RESOURCE_NOT_FOUND} andValue:1]; deviceModeSleepCount = 0; [strongSelf->deviceModeManager dumpOriginalEventsOnTransformationsFeatureDisabled:request.batch]; [strongSelf completeDeviceModeEventProcessing:dbMessage]; @@ -139,6 +145,7 @@ - (RSTransformationRequest *) __getDeviceModeTransformationRequest:(RSDBMessage transformationEvent.destinationIds = destinationIds; transformationEvent.orderNo = [NSNumber numberWithInt:[messageIds[i] intValue]]; [request.batch addObject:transformationEvent]; + [RSMetricsReporter report:SDKMETRICS_DMT_SUBMITTED forMetricType:COUNT withProperties:@{SDKMETRICS_TYPE: message.type} andValue:1]; } } return request; diff --git a/Sources/Classes/RSMetricsReporter.m b/Sources/Classes/RSMetricsReporter.m index 64a0507b..045e76f3 100644 --- a/Sources/Classes/RSMetricsReporter.m +++ b/Sources/Classes/RSMetricsReporter.m @@ -85,6 +85,11 @@ + (void)report:(NSString *)metricName forMetricType:(METRIC_TYPE)metricType with NSString *const SDKMETRICS_CM_ATTEMPT_SUCCESS = @"cm_attempt_success"; NSString *const SDKMETRICS_CM_ATTEMPT_RETRY = @"cm_attempt_retry"; NSString *const SDKMETRICS_CM_ATTEMPT_ABORT = @"cm_attempt_abort"; +NSString *const SDKMETRICS_DMT_SUBMITTED = @"dmt_submitted"; +NSString *const SDKMETRICS_DMT_SUCCESS = @"dmt_success"; +NSString *const SDKMETRICS_DMT_DISCARD = @"dmt_discard"; +NSString *const SDKMETRICS_DMT_RETRY = @"dmt_retry"; +NSString *const SDKMETRICS_DB_ENCRYPT = @"db_encrypt"; NSString *const SDKMETRICS_TYPE = @"type"; NSString *const SDKMETRICS_OPT_OUT = @"opt_out"; @@ -103,3 +108,9 @@ + (void)report:(NSString *)metricName forMetricType:(METRIC_TYPE)metricType with NSString *const SDKMETRICS_WRITEKEY_INVALID = @"writekey_invalid"; NSString *const SDKMETRICS_INTEGRATION = @"integration"; NSString *const SDKMETRICS_REQUEST_TIMEOUT = @"request_timeout"; +NSString *const SDKMETRICS_CREATED = @"created"; +NSString *const SDKMETRICS_MIGRATE_TO_ENCRYPT = @"migrate_to_encrypt"; +NSString *const SDKMETRICS_MIGRATE_TO_DECRYPT = @"migrate_to_decrypt"; +NSString *const SDKMETRICS_RESOURCE_NOT_FOUND = @"resource_not_found"; +NSString *const SDKMETRICS_BAD_REQUEST = @"bad_request"; +NSString *const SDKMETRICS_MAX_RETRIES_EXHAUSTED = @"max_retries_exhausted"; diff --git a/package.json b/package.json index 5977e2ce..5ff9be3a 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,4 @@ { - "version": "1.22.0", + "version": "1.23.0", "description": "Rudder is a platform for collecting, storing and routing customer event data to dozens of tools" } diff --git a/sonar-project.properties b/sonar-project.properties index 48e692d4..1c880d96 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -6,7 +6,7 @@ sonar.qualitygate.wait=false sonar.projectKey=rudderlabs_rudder-sdk-ios sonar.organization=rudderlabs sonar.projectName=RudderStack iOS SDK -sonar.projectVersion=1.22.0 +sonar.projectVersion=1.23.0 # C/C++/Objective-C related details # sonar.cfamily.compile-commands=compile_commands.json