From 11d635fdd40d39f6e807bf349fceae4ae1c0aa22 Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Mon, 10 Apr 2023 23:34:48 +0530 Subject: [PATCH] added pageload tracking event --- .../ActionOpenPageHandler.swift | 6 ++- .../MVMCore/LoadHandling/MVMCoreLoadHandler.m | 1 + .../MVMCore/LoadHandling/MVMCoreLoadObject.h | 3 ++ .../MVMCoreLoadRequestOperation.h | 1 + .../MVMCoreLoadRequestOperation.m | 22 ++++++-- .../MVMCore/OtherHandlers/MVMCoreEvent.swift | 54 ++++++++++++++++++- MVMCore/MVMCore/Utility/MVMCoreErrorObject.h | 3 ++ 7 files changed, 85 insertions(+), 5 deletions(-) diff --git a/MVMCore/MVMCore/ActionHandling/ActionOpenPageHandler.swift b/MVMCore/MVMCore/ActionHandling/ActionOpenPageHandler.swift index 0267ea4..2a1c4e6 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionOpenPageHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionOpenPageHandler.swift @@ -43,6 +43,10 @@ open class ActionOpenPageHandler: MVMCoreJSONActionHandlerProtocol { /// Adds client parameters and makes calls performRequest() open func performRequestAddingClientParameters(with requestParameters: MVMCoreRequestParameters, model: ActionOpenPageModel, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws -> MVMCoreLoadRequestOperation? { + let coreLoadRequestOperation = MVMCoreLoadHandler.sharedGlobal()?.loadRequest(requestParameters, dataForPage: additionalData, delegateObject: delegateObject) + if let pageType = requestParameters.pageType, let identifier = coreLoadRequestOperation?.identifier { + MVMCoreLoggingHandler.shared()?.logCoreEvent(.pageStarted(pageType: pageType, requestUUID: identifier)) + } // Adds any client parameters to the request parameters. if let parametersToFetch = model.clientParameters, let fetchedParameters = try await ClientParameterHandler().getClientParameters( @@ -53,7 +57,7 @@ open class ActionOpenPageHandler: MVMCoreJSONActionHandlerProtocol { requestParameters.add(fetchedParameters) } try Task.checkCancellation() - return MVMCoreLoadHandler.sharedGlobal()?.loadRequest(requestParameters, dataForPage: additionalData, delegateObject: delegateObject) + return coreLoadRequestOperation } /// Ensures background requests do not have showing errors. diff --git a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m index a5f65c1..4430e4b 100644 --- a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m +++ b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m @@ -114,6 +114,7 @@ error.nativeDrivenErrorScreen = YES; error.silentError = NO; error.messageToDisplay = error.messageToDisplay ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess]; + error.identifier = loadObject.identifier; } return error; } diff --git a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadObject.h b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadObject.h index 1ee321d..13cf571 100644 --- a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadObject.h +++ b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadObject.h @@ -58,6 +58,9 @@ // The full response json @property (nullable, strong, nonatomic) NSDictionary *responseJSON; +//Unique Identifier for event tracking +@property (nonatomic, nonatomic, nonnull) NSString *identifier; + - (nullable instancetype)initWithPageJSON:(nullable NSDictionary *)pageJSON modulesJSON:(nullable NSDictionary *)modulesJSON requestParameters:(nullable MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegateObject:(nullable DelegateObject *)delegateObject; - (nullable instancetype)initWithRequestParameters:(nullable MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegateObject:(nullable DelegateObject *)delegateObject; diff --git a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.h b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.h index 0afd035..b441019 100644 --- a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.h +++ b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.h @@ -26,6 +26,7 @@ @property (nullable, nonatomic, readonly) NSString *finalLoadSource; @property (nonatomic) BOOL backgroundLoad; @property (nonatomic, getter=areDependenciesAdded) BOOL dependenciesAdded; +@property (nonnull, nonatomic, readonly) NSString *identifier; /// Legacy flag for if this operation will have an alert to show when finished. @property (nonatomic, readonly) BOOL alertToShow; diff --git a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m index ee714c3..18f9b2c 100644 --- a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m +++ b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m @@ -35,6 +35,7 @@ // For temporarily storing any alert to show until we determine it's delegate. @property (nonatomic, readwrite) BOOL alertToShow; @property (strong, nonatomic, nullable) MVMCoreErrorObject *errorForAlertToShow; +@property (nullable, nonatomic, readwrite) NSString *identifier; @end @@ -48,6 +49,7 @@ self.dataForPage = dataForPage; self.delegateObject = delegateObject; self.backgroundLoad = backgroundLoad; + self.identifier = [NSUUID UUID].UUIDString; } return self; } @@ -55,6 +57,7 @@ - (nullable instancetype)initWithLoadObject:(nullable MVMCoreLoadObject *)loadObject backgroundLoad:(BOOL)backgroundLoad { if (self = [self initWithRequestParameters:loadObject.requestParameters dataForPage:loadObject.dataForPage delegateObject:loadObject.delegateObject backgroundLoad:backgroundLoad]) { + loadObject.identifier = self.identifier; self.loadObject = loadObject; } return self; @@ -120,6 +123,7 @@ // No load requested, finish. MVMCoreLoadObject *loadObject = [[MVMCoreLoadObject alloc] initWithRequestParameters:nil dataForPage:self.dataForPage delegateObject:self.delegateObject]; + loadObject.identifier = self.identifier; loadObject.operation = self; [MVMCoreLoadRequestOperation loadFinished:loadObject loadedViewController:nil errorObject:nil]; } else if (self.loadObject) { @@ -155,9 +159,19 @@ [MVMCoreLoadRequestOperation handleLoadObject:loadObject error:nil]; } else { + if(loadObject.requestParameters.pageType) { + [[MVMCoreLoggingHandler sharedLoggingHandler] logPageLoadStartedFor:loadObject.requestParameters.pageType requestUUID:loadObject.identifier requestURL:@"requestURL"]; + } + // Send a new request to the server. [MVMCoreLoadRequestOperation sendRequest:requestForMissingData loadObject:loadObject completionHandler:^(NSDictionary * _Nullable json) { - + + NSString *serverProcessTime = [(NSDictionary *)json objectChainOfKeysOrIndexes:@[@"ResponseInfo", @"timeStamp"]] ?: @"0"; + + if(loadObject.requestParameters.pageType && serverProcessTime) { + [[MVMCoreLoggingHandler sharedLoggingHandler] logPageLoadCompleteFor:loadObject.requestParameters.pageType serverProcessingTime:serverProcessTime requestURL:@"requestURL" requestUUID:loadObject.identifier isFromCache:loadObject.pageDataFromCache]; + } + // Process the data retrieved from the server. [MVMCoreLoadRequestOperation processJSONFromServer:json loadObject:loadObject completionHandler:^(MVMCoreLoadObject * _Nonnull loadObject, MVMCoreErrorObject * _Nullable error) { @@ -226,7 +240,7 @@ if (pageFromCache) { loadObject.pageType = self.requestParameters.pageType; } - + loadObject.identifier = self.identifier; // Store if we loaded from the cache or not. loadObject.pageDataFromCache = (pageFromCache != nil); loadObject.moduleDataFromCache = (modulesFromCache != nil); @@ -292,10 +306,11 @@ // Error json not correct format. MVMCoreErrorObject *errorObject = [[MVMCoreLoadHandler sharedGlobal] errorForLoadObject:loadObject withTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeJSONNotDictionary domain:ErrorDomainSystem]; + errorObject.identifier = loadObject.identifier; [MVMCoreLoadRequestOperation loadAbortedWithError:errorObject loadObject:loadObject]; } } else { - + error.identifier = loadObject.identifier; // Error with the request/response [[MVMCoreLoadHandler sharedGlobal] attachLoadInformation:loadObject toError:error]; [MVMCoreLoadRequestOperation loadAbortedWithError:error loadObject:loadObject]; @@ -748,6 +763,7 @@ // Once displyed, we are finished. [MVMCoreActionUtility displayViewController:viewController forLoadObject:loadObject presentationDelegate:loadObject.operation completionHandler:^{ + NSLog(@"screen appear from displayViewController"); [MVMCoreLoadRequestOperation loadFinished:loadObject loadedViewController:viewController errorObject:error]; }]; } diff --git a/MVMCore/MVMCore/OtherHandlers/MVMCoreEvent.swift b/MVMCore/MVMCore/OtherHandlers/MVMCoreEvent.swift index 73d8ecc..5adb3fa 100644 --- a/MVMCore/MVMCore/OtherHandlers/MVMCoreEvent.swift +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreEvent.swift @@ -82,9 +82,42 @@ public enum MVMCoreEvent { actionId: String ) + case pageStarted( + pageType: String, + requestUUID: String + ) + + case pageLoadStarted( + pageType: String, + requestUUID: String, + requestURL: String + ) + + case pageLoadComplete( + pageType: String, + requestUUID: String, + serverProcessingTime: String, + requestURL: String, + isFromCache: Bool + ) + + case pageProcessingComplete( + pageType: String, + requestUUID: String, + webUrl: String? + ) + + case pageRenderComplete( + pageType: String, + requestUUID: String, + templateName: String?, + controllerName: String + ) + public enum EventType: String { case action case clientParameter + case pageLoad public var notification: Notification.Name { return Notification.Name(rawValue: rawValue) @@ -102,6 +135,7 @@ public enum MVMCoreEvent { case .clientParameterStartFetch: return .clientParameter case .clientParameterTimeout: return .clientParameter case .clientParameterFetchComplete: return .clientParameter + case .pageStarted, .pageLoadStarted, .pageLoadComplete, .pageProcessingComplete, .pageRenderComplete: return .pageLoad } } @@ -123,5 +157,23 @@ extension MVMCoreLoggingHandler { func logCoreEvent(_ event: MVMCoreEvent, at timestamp: Int64 = Date.unixMillisecondsNow()) { recordEvent(event.type.rawValue, attributes: ["timestamp": timestamp, "event": event]) } - +} + +@objc public extension MVMCoreLoggingHandler { + + @objc func logPageLoadStarted(for pageType: String, requestUUID: String, requestURL: String) { + logCoreEvent(.pageLoadStarted(pageType: pageType, requestUUID: requestUUID, requestURL: requestURL)) + } + + @objc func logPageLoadComplete(for pageType: String, serverProcessingTime: String, requestURL: String, requestUUID: String, isFromCache: Bool) { + logCoreEvent(.pageLoadComplete(pageType: pageType, requestUUID: requestUUID, serverProcessingTime: serverProcessingTime, requestURL: requestURL, isFromCache: isFromCache)) + } + + @objc func logPageProcessingComplete(for pageType: String, requestUUID: String, webUrl: String?) { + logCoreEvent(.pageProcessingComplete(pageType: pageType, requestUUID: requestUUID, webUrl: webUrl)) + } + + @objc func logPageRenderComplete(for pageType: String, requestUUID: String, templateName: String?, controllerName: String) { + logCoreEvent(.pageRenderComplete(pageType: pageType, requestUUID: requestUUID, templateName: templateName, controllerName: controllerName)) + } } diff --git a/MVMCore/MVMCore/Utility/MVMCoreErrorObject.h b/MVMCore/MVMCore/Utility/MVMCoreErrorObject.h index 465dc44..c717855 100644 --- a/MVMCore/MVMCore/Utility/MVMCoreErrorObject.h +++ b/MVMCore/MVMCore/Utility/MVMCoreErrorObject.h @@ -28,6 +28,9 @@ @property (nonatomic, assign) NSInteger httpStatusCode; @property (nullable, strong, nonatomic) NSDictionary *serverResponseInfo; +//Unique Identifier for event tracking +@property (nonatomic, nonatomic, nonnull) NSString *identifier; + // For the crash log. @property (nullable, strong, nonatomic) NSDictionary *crashLog;