Merge branch 'feature/pageLoadTracking' into 'develop'

Page load time event

### Summary
Added pageload tracking event

Co-authored-by: Krishna Kishore Bandaru <krishna.kishore.bandaru@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/256
This commit is contained in:
Hedden, Kyle Matthew 2023-05-03 18:08:18 +00:00
commit cdff607cf1
8 changed files with 96 additions and 6 deletions

View File

@ -43,6 +43,11 @@ 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 actionUUID = MVMCoreActionHandler.getUUID(additionalData: additionalData) ?? UUID().uuidString
requestParameters.identifier = actionUUID
if !requestParameters.backgroundRequest, let pageType = requestParameters.pageType {
MVMCoreLoggingHandler.shared()?.logCoreEvent(.pageStarted(pageType: pageType, requestUUID: actionUUID))
}
// Adds any client parameters to the request parameters.
if let parametersToFetch = model.clientParameters,
let fetchedParameters = try await ClientParameterHandler().getClientParameters(
@ -53,7 +58,9 @@ open class ActionOpenPageHandler: MVMCoreJSONActionHandlerProtocol {
requestParameters.add(fetchedParameters)
}
try Task.checkCancellation()
return MVMCoreLoadHandler.sharedGlobal()?.loadRequest(requestParameters, dataForPage: additionalData, delegateObject: delegateObject)
let coreLoadRequestOperation = MVMCoreLoadHandler.sharedGlobal()?.loadRequest(requestParameters, dataForPage: additionalData, delegateObject: delegateObject)
coreLoadRequestOperation?.identifier = actionUUID
return coreLoadRequestOperation
}
/// Ensures background requests do not have showing errors.

View File

@ -114,6 +114,7 @@
error.nativeDrivenErrorScreen = YES;
error.silentError = NO;
error.messageToDisplay = error.messageToDisplay ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess];
error.requestId = loadObject.identifier; //To track for errors due to invalid JSON or any errors thrown at viewcontroller level.
}
return error;
}
@ -388,6 +389,7 @@
return [self loadBackgroundRequest:requestParameters dataForPage:dataForPage delegateObject:delegateObject];
} else {
MVMCoreLoadRequestOperation *loadOperation = [[MVMCoreLoadRequestOperation alloc] initWithRequestParameters:requestParameters dataForPage:dataForPage delegateObject:delegateObject backgroundLoad:NO];
loadOperation.identifier = requestParameters.identifier;
[self.blockingLoadQueue addOperation:loadOperation];
return loadOperation;
}
@ -395,6 +397,7 @@
- (MVMCoreLoadRequestOperation *)loadBackgroundRequest:(nonnull MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegateObject:(nullable DelegateObject *)delegateObject {
MVMCoreLoadRequestOperation *loadOperation = [[MVMCoreLoadRequestOperation alloc] initWithRequestParameters:requestParameters dataForPage:dataForPage delegateObject:delegateObject backgroundLoad:YES];
loadOperation.identifier = requestParameters.identifier;
[self.backgroundLoadQueue addOperation:loadOperation];
return loadOperation;
}

View File

@ -58,6 +58,9 @@
// The full response json
@property (nullable, strong, nonatomic) NSDictionary *responseJSON;
//Unique Identifier for event tracking
@property (nullable, strong, nonatomic) 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;

View File

@ -55,6 +55,9 @@
if (errorObject.messageToDisplay) {
[responseInfo setObject:errorObject.messageToDisplay forKey:KeyUserMessage];
}
if (errorObject.requestId) {
self.identifier = errorObject.requestId;
}
self.responseInfoMap = responseInfo;
}
return self;

View File

@ -26,6 +26,7 @@
@property (nullable, nonatomic, readonly) NSString *finalLoadSource;
@property (nonatomic) BOOL backgroundLoad;
@property (nonatomic, getter=areDependenciesAdded) BOOL dependenciesAdded;
@property (nonnull, nonatomic, strong) NSString *identifier;
/// Legacy flag for if this operation will have an alert to show when finished.
@property (nonatomic, readonly) BOOL alertToShow;

View File

@ -55,6 +55,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;
@ -122,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) {
@ -153,13 +155,25 @@
MVMCoreRequestParameters *requestForMissingData = [MVMCoreLoadRequestOperation createRequestForDataWithLoadObject:loadObject];
if (!requestForMissingData) {
[[MVMCoreLoggingHandler sharedLoggingHandler] logPageLoadCompleteFor:loadObject.requestParameters.pageType serverProcessingTime:@"0" requestURL:loadObject.requestParameters.URL.absoluteString requestUUID:loadObject.identifier isFromCache:loadObject.pageDataFromCache];
// We have all the needed data, continue with the load.
[MVMCoreLoadRequestOperation handleLoadObject:loadObject error:nil];
} else {
if(!self.backgroundLoad && loadObject.requestParameters.pageType) {
[[MVMCoreLoggingHandler sharedLoggingHandler] logPageLoadStartedFor:loadObject.requestParameters.pageType requestUUID:loadObject.identifier requestURL:loadObject.requestParameters.URL.absoluteString];
}
// 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(!self.backgroundLoad && loadObject.requestParameters.pageType && serverProcessTime) {
[[MVMCoreLoggingHandler sharedLoggingHandler] logPageLoadCompleteFor:loadObject.requestParameters.pageType serverProcessingTime:serverProcessTime requestURL:loadObject.requestParameters.URL.absoluteString 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) {
@ -228,7 +242,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);
@ -297,7 +311,6 @@
[MVMCoreLoadRequestOperation loadAbortedWithError:errorObject loadObject:loadObject];
}
} else {
// Error with the request/response
[[MVMCoreLoadHandler sharedGlobal] attachLoadInformation:loadObject toError:error];
[MVMCoreLoadRequestOperation loadAbortedWithError:error loadObject:loadObject];

View File

@ -101,6 +101,9 @@ typedef NS_ENUM(NSInteger, MFLoadStyle) {
/// A flag for if it should be a background request or not.
@property (assign, nonatomic) BOOL backgroundRequest;
//Unique Identifier for event tracking
@property (nullable, strong, nonatomic) NSString *identifier;
// Creates an object with the given page type and extra parameters. Adds the extra parameters to the standard request parameters. Will add any modules needed by the page type by default.
- (nullable instancetype)initWithPageType:(nonnull NSString *)pageType extraParameters:(nullable NSDictionary *)extraParameters;

View File

@ -82,9 +82,43 @@ 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,
error: String?
)
public enum EventType: String {
case action
case clientParameter
case pageLoad
public var notification: Notification.Name {
return Notification.Name(rawValue: rawValue)
@ -102,6 +136,7 @@ public enum MVMCoreEvent {
case .clientParameterStartFetch: return .clientParameter
case .clientParameterTimeout: return .clientParameter
case .clientParameterFetchComplete: return .clientParameter
case .pageStarted, .pageLoadStarted, .pageLoadComplete, .pageProcessingComplete, .pageRenderComplete: return .pageLoad
}
}
@ -118,10 +153,32 @@ public enum MVMCoreEvent {
}
}
extension MVMCoreLoggingHandler {
public 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 pageStarted(for pageType: String, requestUUID: String) {
logCoreEvent(.pageStarted(pageType: pageType, requestUUID: requestUUID))
}
@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, error: String?) {
logCoreEvent(.pageRenderComplete(pageType: pageType, requestUUID: requestUUID, templateName: templateName, controllerName: controllerName, error: error))
}
}