FIRIAMClearcutLogger.m 9.2 KB

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