FIRIAMClearcutLogger.m 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. * Copyright 2018 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <TargetConditionals.h>
  17. #if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION
  18. #import "FirebaseCore/Extension/FirebaseCoreInternal.h"
  19. #import "FirebaseInAppMessaging/Sources/Analytics/FIRIAMClearcutLogStorage.h"
  20. #import "FirebaseInAppMessaging/Sources/FIRCore+InAppMessaging.h"
  21. #import "FirebaseInAppMessaging/Sources/Private/Analytics/FIRIAMClearcutLogger.h"
  22. #import "FirebaseInAppMessaging/Sources/Private/Analytics/FIRIAMClearcutUploader.h"
  23. @interface FIRIAMClearcutLogger ()
  24. // these two writable for assisting unit testing need
  25. @property(readwrite, nonatomic) FIRIAMClearcutHttpRequestSender *requestSender;
  26. @property(readwrite, nonatomic) id<FIRIAMTimeFetcher> timeFetcher;
  27. @property(readonly, nonatomic) FIRIAMClientInfoFetcher *clientInfoFetcher;
  28. @property(readonly, nonatomic) FIRIAMClearcutUploader *ctUploader;
  29. @property(readonly, copy, nonatomic) NSString *fbProjectNumber;
  30. @property(readonly, copy, nonatomic) NSString *fbAppId;
  31. @end
  32. @implementation FIRIAMClearcutLogger {
  33. // Firebase installations ID.
  34. NSString *_FID;
  35. }
  36. - (instancetype)initWithFBProjectNumber:(NSString *)fbProjectNumber
  37. fbAppId:(NSString *)fbAppId
  38. clientInfoFetcher:(FIRIAMClientInfoFetcher *)clientInfoFetcher
  39. usingTimeFetcher:(id<FIRIAMTimeFetcher>)timeFetcher
  40. usingUploader:(FIRIAMClearcutUploader *)uploader {
  41. if (self = [super init]) {
  42. _fbProjectNumber = fbProjectNumber;
  43. _fbAppId = fbAppId;
  44. _clientInfoFetcher = clientInfoFetcher;
  45. _timeFetcher = timeFetcher;
  46. _ctUploader = uploader;
  47. }
  48. return self;
  49. }
  50. + (void)updateSourceExtensionDictWithAnalyticsEventEnumType:(FIRIAMAnalyticsLogEventType)eventType
  51. forDict:(NSMutableDictionary *)dict {
  52. switch (eventType) {
  53. case FIRIAMAnalyticsEventMessageImpression:
  54. dict[@"event_type"] = @"IMPRESSION_EVENT_TYPE";
  55. break;
  56. case FIRIAMAnalyticsEventActionURLFollow:
  57. dict[@"event_type"] = @"CLICK_EVENT_TYPE";
  58. break;
  59. case FIRIAMAnalyticsEventMessageDismissAuto:
  60. dict[@"dismiss_type"] = @"AUTO";
  61. break;
  62. case FIRIAMAnalyticsEventMessageDismissClick:
  63. dict[@"dismiss_type"] = @"CLICK";
  64. break;
  65. case FIRIAMAnalyticsEventMessageDismissSwipe:
  66. dict[@"dismiss_type"] = @"SWIPE";
  67. break;
  68. case FIRIAMAnalyticsEventImageFetchError:
  69. dict[@"render_error_reason"] = @"IMAGE_FETCH_ERROR";
  70. break;
  71. case FIRIAMAnalyticsEventImageFormatUnsupported:
  72. dict[@"render_error_reason"] = @"IMAGE_UNSUPPORTED_FORMAT";
  73. break;
  74. case FIRIAMAnalyticsEventFetchAPIClientError:
  75. dict[@"fetch_error_reason"] = @"CLIENT_ERROR";
  76. break;
  77. case FIRIAMAnalyticsEventFetchAPIServerError:
  78. dict[@"fetch_error_reason"] = @"SERVER_ERROR";
  79. break;
  80. case FIRIAMAnalyticsEventFetchAPINetworkError:
  81. dict[@"fetch_error_reason"] = @"NETWORK_ERROR";
  82. break;
  83. case FIRIAMAnalyticsEventTestMessageImpression:
  84. dict[@"event_type"] = @"TEST_MESSAGE_IMPRESSION_EVENT_TYPE";
  85. break;
  86. case FIRIAMAnalyticsEventTestMessageClick:
  87. dict[@"event_type"] = @"TEST_MESSAGE_CLICK_EVENT_TYPE";
  88. break;
  89. case FIRIAMAnalyticsLogEventUnknown:
  90. break;
  91. }
  92. }
  93. // constructing CampaignAnalytics proto defined in campaign_analytics.proto and serialize it into
  94. // a string.
  95. // @return nil if error happened
  96. - (NSString *)constructSourceExtensionJsonForClearcutWithEventType:
  97. (FIRIAMAnalyticsLogEventType)eventType
  98. forCampaignID:(NSString *)campaignID
  99. eventTimeInMs:(NSNumber *)eventTimeInMs
  100. installationID:(NSString *)installationID {
  101. NSMutableDictionary *campaignAnalyticsDict = [[NSMutableDictionary alloc] init];
  102. campaignAnalyticsDict[@"project_number"] = self.fbProjectNumber;
  103. campaignAnalyticsDict[@"campaign_id"] = campaignID;
  104. campaignAnalyticsDict[@"client_app"] =
  105. @{@"google_app_id" : self.fbAppId, @"firebase_instance_id" : installationID};
  106. campaignAnalyticsDict[@"client_timestamp_millis"] = eventTimeInMs;
  107. [self.class updateSourceExtensionDictWithAnalyticsEventEnumType:eventType
  108. forDict:campaignAnalyticsDict];
  109. campaignAnalyticsDict[@"fiam_sdk_version"] = [self.clientInfoFetcher getIAMSDKVersion];
  110. // turn campaignAnalyticsDict into a json string
  111. NSError *error;
  112. NSData *jsonData = [NSJSONSerialization
  113. dataWithJSONObject:campaignAnalyticsDict // Here you can pass array or dictionary
  114. options:0 // Pass 0 if you don't care about the readability of the generated
  115. // string
  116. error:&error];
  117. if (jsonData) {
  118. NSString *jsonString;
  119. jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
  120. FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM210006",
  121. @"Source extension json string produced as %@", jsonString);
  122. return jsonString;
  123. } else {
  124. FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM210007",
  125. @"Error in generating source extension json string: %@", error);
  126. return nil;
  127. }
  128. }
  129. - (void)logAnalyticsEventForType:(FIRIAMAnalyticsLogEventType)eventType
  130. forCampaignID:(NSString *)campaignID
  131. withEventTimeInMs:(nullable NSNumber *)eventTimeInMs
  132. FID:(NSString *)FID
  133. completion:(void (^)(BOOL success))completion {
  134. NSTimeInterval nowInMs = [self.timeFetcher currentTimestampInSeconds] * 1000;
  135. if (eventTimeInMs == nil) {
  136. eventTimeInMs = @((long)nowInMs);
  137. }
  138. if (!FID) {
  139. FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM210009",
  140. @"Instance ID is nil, event %ld for campaign ID %@ will not be sent",
  141. (long)eventType, campaignID);
  142. return;
  143. }
  144. NSString *sourceExtensionJsonString =
  145. [self constructSourceExtensionJsonForClearcutWithEventType:eventType
  146. forCampaignID:campaignID
  147. eventTimeInMs:eventTimeInMs
  148. installationID:FID];
  149. FIRIAMClearcutLogRecord *newRecord = [[FIRIAMClearcutLogRecord alloc]
  150. initWithExtensionJsonString:sourceExtensionJsonString
  151. eventTimestampInSeconds:eventTimeInMs.integerValue / 1000];
  152. [self.ctUploader addNewLogRecord:newRecord];
  153. FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM210003",
  154. @"One more clearcut log record created and sent to uploader with source extension %@",
  155. sourceExtensionJsonString);
  156. completion(YES);
  157. }
  158. - (void)logAnalyticsEventForType:(FIRIAMAnalyticsLogEventType)eventType
  159. forCampaignID:(NSString *)campaignID
  160. withCampaignName:(NSString *)campaignName
  161. eventTimeInMs:(nullable NSNumber *)eventTimeInMs
  162. completion:(void (^)(BOOL success))completion {
  163. if (!_FID) {
  164. [self.clientInfoFetcher
  165. fetchFirebaseInstallationDataWithProjectNumber:self.fbProjectNumber
  166. withCompletion:^(NSString *_Nullable FID,
  167. NSString *_Nullable FISToken,
  168. NSError *_Nullable error) {
  169. if (error) {
  170. FIRLogWarning(
  171. kFIRLoggerInAppMessaging, @"I-IAM210001",
  172. @"Failed to get iid value for clearcut logging %@",
  173. error);
  174. completion(NO);
  175. } else {
  176. // persist FID through the whole life-cycle
  177. self->_FID = FID;
  178. [self logAnalyticsEventForType:eventType
  179. forCampaignID:campaignID
  180. withEventTimeInMs:eventTimeInMs
  181. FID:FID
  182. completion:completion];
  183. }
  184. }];
  185. } else {
  186. FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM210004",
  187. @"Using remembered iid for event logging");
  188. [self logAnalyticsEventForType:eventType
  189. forCampaignID:campaignID
  190. withEventTimeInMs:eventTimeInMs
  191. FID:_FID
  192. completion:completion];
  193. }
  194. }
  195. @end
  196. #endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION