FIRIAMClearcutLogger.m 9.2 KB

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