diff --git a/MVMCore/MVMCore.xcodeproj/project.pbxproj b/MVMCore/MVMCore.xcodeproj/project.pbxproj index c827f0f..5c113a1 100644 --- a/MVMCore/MVMCore.xcodeproj/project.pbxproj +++ b/MVMCore/MVMCore.xcodeproj/project.pbxproj @@ -42,6 +42,7 @@ 2723337B28BD534D004EAEE0 /* MVMCoreEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2723337A28BD534D004EAEE0 /* MVMCoreEvent.swift */; }; 2723337D28BD53C2004EAEE0 /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2723337C28BD53C2004EAEE0 /* Date+Extension.swift */; }; 5846ABF42B44BB9000FA6C76 /* Collection+Safe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5846ABF32B44BB9000FA6C76 /* Collection+Safe.swift */; }; + 5878F0B22BDAA63E00ADE23D /* ReadableDecodingErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5878F0B12BDAA63E00ADE23D /* ReadableDecodingErrors.swift */; }; 6042E8FC2B317B190031644B /* MVMCoreLoggingHandlerHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 6042E8FB2B3094680031644B /* MVMCoreLoggingHandlerHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; 605A9A2A2ABD712F00487E47 /* MVMCoreLoggingHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 605A9A292ABD712F00487E47 /* MVMCoreLoggingHandler.swift */; }; 6079EDCE2AD97AA5004B7A85 /* MVMCoreLoggingDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6079EDCD2AD97AA5004B7A85 /* MVMCoreLoggingDelegateProtocol.swift */; }; @@ -194,6 +195,7 @@ 581FABEE2A71D0E6003A8508 /* mvmcore_dev.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = mvmcore_dev.xcconfig; sourceTree = ""; }; 5836B8E22A4338DF002553D9 /* mvmcore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = mvmcore.xcconfig; sourceTree = ""; }; 5846ABF32B44BB9000FA6C76 /* Collection+Safe.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Collection+Safe.swift"; sourceTree = ""; }; + 5878F0B12BDAA63E00ADE23D /* ReadableDecodingErrors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadableDecodingErrors.swift; sourceTree = ""; }; 6042E8FB2B3094680031644B /* MVMCoreLoggingHandlerHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreLoggingHandlerHelper.h; sourceTree = ""; }; 605A9A292ABD712F00487E47 /* MVMCoreLoggingHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreLoggingHandler.swift; sourceTree = ""; }; 6079EDCD2AD97AA5004B7A85 /* MVMCoreLoggingDelegateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreLoggingDelegateProtocol.swift; sourceTree = ""; }; @@ -396,6 +398,7 @@ children = ( AF60A7F1289212CA00919EEB /* MVMError.swift */, AF60A7F3289212EB00919EEB /* MVMCoreError.swift */, + 5878F0B12BDAA63E00ADE23D /* ReadableDecodingErrors.swift */, 881D26911FCC9D180079C521 /* MVMCoreErrorObject.h */, 881D268F1FCC9D180079C521 /* MVMCoreErrorObject.m */, 881D26921FCC9D180079C521 /* MVMCoreOperation.h */, @@ -877,6 +880,7 @@ AFA4931E29E5C988001A9663 /* MVMCoreActionUtility+Extension.swift in Sources */, 1DAD0FFE26AAB40000216E83 /* ActionRunJavaScriptModel.swift in Sources */, 946EE1AB237B5C940036751F /* Decoder.swift in Sources */, + 5878F0B22BDAA63E00ADE23D /* ReadableDecodingErrors.swift in Sources */, 2723337D28BD53C2004EAEE0 /* Date+Extension.swift in Sources */, AF70699A287DD02400077CF6 /* ActionContactHandler.swift in Sources */, AF69D4F3286E9DCE00BC6862 /* ActionActionsHandler.swift in Sources */, diff --git a/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift b/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift index 5d87fea..ff2378e 100644 --- a/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift @@ -154,6 +154,12 @@ public protocol MVMCoreJSONActionHandlerProtocol: MVMCoreActionHandlerProtocol { fileprivate func logActionError(_ error: Error, _ actionType: String?, _ additionalData: [AnyHashable: Any]?, _ delegateObject: DelegateObject?) { MVMCoreActionHandler.log(string: "Failed Action: Error \(error)", additionalData: additionalData) if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: MVMCoreActionHandler.getErrorLocation(with: delegateObject?.actionDelegate, actionType: actionType ?? "noAction")) { + if let fromBridge = additionalData?["fromBridge"] as? Bool, fromBridge, let browserUrl = additionalData?["browserUrl"] as? String { + errorObject.requestUrl = browserUrl + } + if let humanReadableMessage = (error as? HumanReadableDecodingErrorProtocol)?.readableDescription { + errorObject.messageToLog = humanReadableMessage + } defaultHandleActionError(errorObject, additionalData: additionalData) } } @@ -176,7 +182,7 @@ public protocol MVMCoreJSONActionHandlerProtocol: MVMCoreActionHandlerProtocol { } catch { let actionType = json?.optionalStringForKey(KeyActionType) switch error { - case ModelRegistry.Error.decoderError, is DecodingError: + case is ModelRegistry.Error, is DecodingError: MVMCoreLoggingHandler.shared()?.logCoreEvent(.actionFailedToDecode(pageType: pageType(from: delegateObject), error: error)) logActionError(error, actionType, additionalData, delegateObject) case ModelRegistry.Error.decoderErrorModelNotMapped: diff --git a/MVMCore/MVMCore/Utility/ReadableDecodingErrors.swift b/MVMCore/MVMCore/Utility/ReadableDecodingErrors.swift new file mode 100644 index 0000000..4c9b991 --- /dev/null +++ b/MVMCore/MVMCore/Utility/ReadableDecodingErrors.swift @@ -0,0 +1,69 @@ +// +// ReadableDecodingErrors.swift +// MVMCore +// +// Created by Kyle Hedden on 10/5/23. +// Copyright © 2023 myverizon. All rights reserved. +// + +import Foundation + +public protocol HumanReadableDecodingErrorProtocol { + var readableDescription: String { get } +} + +extension JSONError: HumanReadableDecodingErrorProtocol { + public var readableDescription: String { + switch (self) { + case .other(let other): + if let other = other as? HumanReadableDecodingErrorProtocol { + return other.readableDescription + } + return description + default: + return description + } + } +} + +extension ModelRegistry.Error: HumanReadableDecodingErrorProtocol { + public var readableDescription: String { + switch (self) { + case .decoderErrorModelNotMapped(let identifier, let codingKey, let codingPath) where identifier != nil && codingKey != nil && codingPath != nil: + return "Model identifier \"\(identifier!)\" is not mapped for \"\(codingKey!.stringValue)\" @ \(codingPath!.map { return $0.stringValue })" + + case .decoderErrorObjectNotPresent(let codingKey, let codingPath): + return "Required model \"\(codingKey.stringValue)\" was not found @ \(codingPath.map { return $0.stringValue })" + + case .decoderOther(let message): + return "An issue occurred while decoding: \(message)" + + case .other(let message): + return "Registry error: \(message)" + + default: + return "Registry error: \((self as NSError).localizedFailureReason ?? self.localizedDescription)" + } + } +} + +extension DecodingError: HumanReadableDecodingErrorProtocol { + public var readableDescription: String { + switch (self) { + case .keyNotFound(let codingKey, let context): + return "Required key \(codingKey.stringValue) was not found @ \(context.codingPath.map { return $0.stringValue })" + + case .valueNotFound(_, let context): + return "Value not found @ \(context.codingPath.map { return $0.stringValue })" + + case .typeMismatch(_, let context): + return "Value type mismatch @ \(context.codingPath.map { return $0.stringValue })" + + case .dataCorrupted(let context): + return "Data corrupted @ \(context.codingPath.map { return $0.stringValue })" + + @unknown default: + return (self as NSError).localizedFailureReason ?? self.localizedDescription + } + } +}