FIRIAMClearcutLogger.m 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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. NSString *_iid;
  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. instanceID:(NSString *)instanceID {
  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" : instanceID};
  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. IID:(NSString *)iid
  131. completion:(void (^)(BOOL success))completion {
  132. NSTimeInterval nowInMs = [self.timeFetcher currentTimestampInSeconds] * 1000;
  133. if (eventTimeInMs == nil) {
  134. eventTimeInMs = @((long)nowInMs);
  135. }
  136. if (!iid) {
  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. instanceID:iid];
  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 (!_iid) {
  162. [self.clientInfoFetcher
  163. fetchFirebaseIIDDataWithProjectNumber:self.fbProjectNumber
  164. withCompletion:^(NSString *_Nullable iid, NSString *_Nullable token,
  165. NSError *_Nullable error) {
  166. if (error) {
  167. FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM210001",
  168. @"Failed to get iid value for clearcut logging %@",
  169. error);
  170. completion(NO);
  171. } else {
  172. // persist iid through the whole life-cycle
  173. self->_iid = iid;
  174. [self logAnalyticsEventForType:eventType
  175. forCampaignID:campaignID
  176. withEventTimeInMs:eventTimeInMs
  177. IID:iid
  178. completion:completion];
  179. }
  180. }];
  181. } else {
  182. FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM210004",
  183. @"Using remembered iid for event logging");
  184. [self logAnalyticsEventForType:eventType
  185. forCampaignID:campaignID
  186. withEventTimeInMs:eventTimeInMs
  187. IID:_iid
  188. completion:completion];
  189. }
  190. }
  191. @end