Skip to content

Commit

Permalink
feat: Logging framework revamped (#167)
Browse files Browse the repository at this point in the history
Co-authored-by: Praful Koppalkar <[email protected]>
  • Loading branch information
vsrivatsa-edinburgh and prafulkoppalkar authored Feb 19, 2024
1 parent 014d40e commit 6ecbadd
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 96 deletions.
38 changes: 0 additions & 38 deletions src/Components/DynamicFields.res
Original file line number Diff line number Diff line change
Expand Up @@ -287,44 +287,6 @@ let make = (
(dynamicFieldsToRenderInsideBilling->Js.Array2.length > 1 || !isOnlyInfoElementPresent)
}, (dynamicFieldsToRenderInsideBilling, isOnlyInfoElementPresent))

React.useEffect1(() => {
let fieldsArrStr = fieldsArr->Js.Array2.map(field => {
field->PaymentMethodsRecord.paymentMethodFieldToStrMapper->Js.Json.string
})
let dynamicFieldsToRenderOutsideBillingStr =
dynamicFieldsToRenderOutsideBilling->Js.Array2.map(field => {
field->PaymentMethodsRecord.paymentMethodFieldToStrMapper->Js.Json.string
})
let dynamicFieldsToRenderInsideBillingStr =
dynamicFieldsToRenderInsideBilling->Js.Array2.map(field => {
field->PaymentMethodsRecord.paymentMethodFieldToStrMapper->Js.Json.string
})
let requiredFieldsStr = requiredFields->Js.Array2.map(field => {
field.required_field->Js.Json.string
})

let loggerPayload =
[
("requiredFields", requiredFieldsStr->Js.Json.array),
("fieldsArr", fieldsArrStr->Js.Json.array),
(
"dynamicFieldsToRenderOutsideBilling",
dynamicFieldsToRenderOutsideBillingStr->Js.Json.array,
),
(
"dynamicFieldsToRenderInsideBilling",
dynamicFieldsToRenderInsideBillingStr->Js.Json.array,
),
("isRenderDynamicFieldsInsideBilling", isRenderDynamicFieldsInsideBilling->Js.Json.boolean),
("isOnlyInfoElementPresent", isOnlyInfoElementPresent->Js.Json.boolean),
("isInfoElementPresent", isInfoElementPresent->Js.Json.boolean),
]
->Js.Dict.fromArray
->Js.Json.object_
logger.setLogInfo(~value=loggerPayload->Js.Json.stringify, ~eventName=DYNAMIC_FIELDS_RENDER, ())
None
}, fieldsArr)

{
fieldsArr->Js.Array2.length > 0
? <>
Expand Down
1 change: 1 addition & 0 deletions src/GlobalVars.res
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
@val external sentryScriptUrl: string = "sentryScriptUrl"
@val external enableLogging: bool = "enableLogging"
@val external loggingLevelStr: string = "loggingLevel"
@val external maxLogsPushedPerEventName: int = "maxLogsPushedPerEventName"
let targetOrigin: string = "*"
let isInteg = sdkUrl === "https://dev.hyperswitch.io"
let isSandbox = sdkUrl === "https://beta.hyperswitch.io"
Expand Down
2 changes: 1 addition & 1 deletion src/LoaderController.res
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger) => {
}
}

logger.setLogInfo(~value="paymentElementCreate", ~eventName=APP_RENDERED, ())
logger.setLogInfo(~value=Window.href, ~eventName=APP_RENDERED, ())
[
("iframeId", "no-element"->Js.Json.string),
("publishableKey", ""->Js.Json.string),
Expand Down
6 changes: 5 additions & 1 deletion src/Window.res
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,11 @@ external userAgent: string = "userAgent"
@val @scope("navigator")
external sendBeacon: (string, string) => unit = "sendBeacon"

@val @scope(("window", "location")) external hostname: string = "hostname"
@val @scope(("window", "location"))
external hostname: string = "hostname"

@val @scope(("window", "location"))
external href: string = "href"

let isSandbox = hostname === "beta.hyperswitch.io"

Expand Down
20 changes: 11 additions & 9 deletions src/orca-loader/Hyper.res
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,7 @@ let make = (publishableKey, options: option<Js.Json.t>, analyticsInfo: option<Js
() => {
logger.setMerchantId(publishableKey)
logger.setSessionId(sessionID)
logger.setLogInfo(
~value="orca-sdk initiated",
~eventName=APP_INITIATED,
~timestamp=sdkTimestamp,
(),
)
logger.setLogInfo(~value=Window.href, ~eventName=APP_INITIATED, ~timestamp=sdkTimestamp, ())
}
}->Sentry.sentryLogger
switch Window.getHyper->Js.Nullable.toOption {
Expand Down Expand Up @@ -326,16 +321,23 @@ let make = (publishableKey, options: option<Js.Json.t>, analyticsInfo: option<Js
})
}
let elements = elementsOptions => {
logger.setLogInfo(~value="orca.elements called", ~eventName=ORCA_ELEMENTS_CALLED, ())
open Promise
let clientSecretId =
elementsOptions
->Js.Json.decodeObject
->Belt.Option.flatMap(x => x->Js.Dict.get("clientSecret"))
->Belt.Option.flatMap(Js.Json.decodeString)
->Belt.Option.getWithDefault("")
clientSecret := clientSecretId

logger.setClientSecret(clientSecretId)
Js.Promise.make((~resolve, ~reject as _) => {
logger.setClientSecret(clientSecretId)
resolve(. Js.Json.null)
})
->then(_ => {
logger.setLogInfo(~value=Window.href, ~eventName=ORCA_ELEMENTS_CALLED, ())
resolve()
})
->ignore

Elements.make(
elementsOptions,
Expand Down
8 changes: 2 additions & 6 deletions src/orca-log-catcher/ErrorBoundary.res
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,7 @@ module ErrorCard = {
let make = (~error: Sentry.ErrorBoundary.fallbackArg, ~level) => {
let beaconApiCall = data => {
if data->Js.Array2.length > 0 {
let logData =
[("data", data->Js.Array2.map(OrcaLogger.logFileToObj)->Js.Json.array)]
->Js.Dict.fromArray
->Js.Json.object_
->Js.Json.stringify
let logData = data->Js.Array2.map(OrcaLogger.logFileToObj)->Js.Json.array->Js.Json.stringify
Window.sendBeacon(GlobalVars.logEndpoint, logData)
}
}
Expand Down Expand Up @@ -131,7 +127,7 @@ module ErrorCard = {
platform: Window.platform,
userAgent: Window.userAgent,
appId: "",
eventName: "SDK_CRASH",
eventName: SDK_CRASH,
latency: "",
paymentMethod: "",
firstEvent: false,
Expand Down
94 changes: 55 additions & 39 deletions src/orca-log-catcher/OrcaLogger.res
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type eventName =
| PAYPAL_SDK_FLOW
| APP_INITIATED
| APP_REINITIATED
| LOG_INITIATED
| LOADER_CALLED
| ORCA_ELEMENTS_CALLED
| PAYMENT_OPTIONS_PROVIDED
Expand All @@ -52,7 +53,6 @@ type eventName =
| REDIRECTING_USER
| DISPLAY_BANK_TRANSFER_INFO_PAGE
| DISPLAY_QR_CODE_INFO_PAGE
| DYNAMIC_FIELDS_RENDER
| PAYMENT_METHODS_RESPONSE

let eventNameToStrMapper = eventName => {
Expand Down Expand Up @@ -82,6 +82,7 @@ let eventNameToStrMapper = eventName => {
| PAYPAL_SDK_FLOW => "PAYPAL_SDK_FLOW"
| APP_INITIATED => "APP_INITIATED"
| APP_REINITIATED => "APP_REINITIATED"
| LOG_INITIATED => "LOG_INITIATED"
| LOADER_CALLED => "LOADER_CALLED"
| ORCA_ELEMENTS_CALLED => "ORCA_ELEMENTS_CALLED"
| PAYMENT_OPTIONS_PROVIDED => "PAYMENT_OPTIONS_PROVIDED"
Expand All @@ -107,7 +108,6 @@ let eventNameToStrMapper = eventName => {
| REDIRECTING_USER => "REDIRECTING_USER"
| DISPLAY_BANK_TRANSFER_INFO_PAGE => "DISPLAY_BANK_TRANSFER_INFO_PAGE"
| DISPLAY_QR_CODE_INFO_PAGE => "DISPLAY_QR_CODE_INFO_PAGE"
| DYNAMIC_FIELDS_RENDER => "DYNAMIC_FIELDS_RENDER"
| PAYMENT_METHODS_RESPONSE => "PAYMENT_METHODS_RESPONSE"
}
}
Expand Down Expand Up @@ -138,7 +138,7 @@ type logFile = {
browserName: string,
browserVersion: string,
userAgent: string,
eventName: string,
eventName: eventName,
latency: string,
firstEvent: bool,
paymentMethod: string,
Expand Down Expand Up @@ -257,7 +257,7 @@ let logFileToObj = logFile => {
("app_id", logFile.appId->Js.Json.string),
("platform", logFile.platform->convertToScreamingSnakeCase->Js.Json.string),
("user_agent", logFile.userAgent->Js.Json.string),
("event_name", logFile.eventName->Js.Json.string),
("event_name", logFile.eventName->eventNameToStrMapper->Js.Json.string),
("browser_name", logFile.browserName->convertToScreamingSnakeCase->Js.Json.string),
("browser_version", logFile.browserVersion->Js.Json.string),
("latency", logFile.latency->Js.Json.string),
Expand Down Expand Up @@ -408,6 +408,9 @@ let make = (
| None => GlobalVars.repoName
}

let events = ref(Js.Dict.empty())
let eventsCounter = ref(Js.Dict.empty())

let timeOut = ref(None)

let merchantId = getRefFromOption(merchantId)
Expand All @@ -421,8 +424,25 @@ let make = (
metadata := value
}

let calculateAndUpdateCounterHook = eventName => {
let updatedCounter = switch eventsCounter.contents->Js.Dict.get(eventName) {
| Some(num) => num + 1
| None => 1
}
eventsCounter.contents->Js.Dict.set(eventName, updatedCounter)
updatedCounter
}

let conditionalLogPush = (log: logFile) => {
if GlobalVars.enableLogging {
let maxLogsPushedPerEventName = GlobalVars.maxLogsPushedPerEventName
let conditionalEventName = switch log.eventName {
| INPUT_FIELD_CHANGED => log.value // to enforce rate limiting for each input field independently
| _ => ""
}
let eventName = log.eventName->eventNameToStrMapper ++ conditionalEventName

let counter = eventName->calculateAndUpdateCounterHook
if GlobalVars.enableLogging && counter <= maxLogsPushedPerEventName {
switch loggingLevel {
| DEBUG => log->Js.Array2.push(mainLogFile, _)->ignore
| INFO =>
Expand All @@ -442,11 +462,7 @@ let make = (

let beaconApiCall = data => {
if data->Js.Array2.length > 0 {
let logData =
[("data", data->Js.Array2.map(logFileToObj)->Js.Json.array)]
->Js.Dict.fromArray
->Js.Json.object_
->Js.Json.stringify
let logData = data->Js.Array2.map(logFileToObj)->Js.Json.array->Js.Json.stringify
Window.sendBeacon(GlobalVars.logEndpoint, logData)
}
}
Expand All @@ -456,8 +472,6 @@ let make = (
clientSecret := value
}

let events = ref(Js.Dict.empty())

let rec sendLogs = () => {
switch timeOut.contents {
| Some(val) => {
Expand All @@ -475,16 +489,16 @@ let make = (

let checkForPriorityEvents = (arrayOfLogs: array<logFile>) => {
let priorityEventNames = [
"APP_RENDERED",
"ORCA_ELEMENTS_CALLED",
"PAYMENT_DATA_FILLED",
"PAYMENT_ATTEMPT",
"CONFIRM_CALL",
"SDK_CRASH",
"REDIRECTING_USER",
"DISPLAY_BANK_TRANSFER_INFO_PAGE",
"DISPLAY_QR_CODE_INFO_PAGE",
"SESSIONS_CALL",
APP_RENDERED,
ORCA_ELEMENTS_CALLED,
PAYMENT_DATA_FILLED,
PAYMENT_ATTEMPT,
CONFIRM_CALL,
SDK_CRASH,
REDIRECTING_USER,
DISPLAY_BANK_TRANSFER_INFO_PAGE,
DISPLAY_QR_CODE_INFO_PAGE,
SESSIONS_CALL,
]
arrayOfLogs
->Js.Array2.find(log => {
Expand All @@ -511,19 +525,20 @@ let make = (
let calculateLatencyHook = (~eventName, ~type_="", ()) => {
let currentTimestamp = Js.Date.now()
let latency = switch eventName {
| "PAYMENT_ATTEMPT" => {
let appRenderedTimestamp = events.contents->Js.Dict.get("APP_RENDERED")
| PAYMENT_ATTEMPT => {
let appRenderedTimestamp = events.contents->Js.Dict.get(APP_RENDERED->eventNameToStrMapper)
switch appRenderedTimestamp {
| Some(float) => currentTimestamp -. float
| _ => -1.
}
}
| "RETRIEVE_CALL"
| "CONFIRM_CALL"
| "SESSIONS_CALL"
| "PAYMENT_METHODS_CALL"
| "CUSTOMER_PAYMENT_METHODS_CALL" => {
let logRequestTimestamp = events.contents->Js.Dict.get(eventName ++ "_INIT")
| RETRIEVE_CALL
| CONFIRM_CALL
| SESSIONS_CALL
| PAYMENT_METHODS_CALL
| CUSTOMER_PAYMENT_METHODS_CALL => {
let logRequestTimestamp =
events.contents->Js.Dict.get(eventName->eventNameToStrMapper ++ "_INIT")
switch (logRequestTimestamp, type_) {
| (Some(_), "request") => 0.
| (Some(float), _) => currentTimestamp -. float
Expand All @@ -547,7 +562,7 @@ let make = (
) => {
let eventNameStr = eventName->eventNameToStrMapper
let firstEvent = events.contents->Js.Dict.get(eventNameStr)->Belt.Option.isNone
let latency = calculateLatencyHook(~eventName=eventNameStr, ())
let latency = calculateLatencyHook(~eventName, ())
let localTimestamp = timestamp->Belt.Option.getWithDefault(Js.Date.now()->Belt.Float.toString)
let localTimestampFloat =
localTimestamp->Belt.Float.fromString->Belt.Option.getWithDefault(Js.Date.now())
Expand All @@ -569,7 +584,7 @@ let make = (
platform: Window.platform,
userAgent: Window.userAgent,
appId: "",
eventName: eventNameStr,
eventName,
latency,
paymentMethod,
firstEvent,
Expand Down Expand Up @@ -600,7 +615,7 @@ let make = (
) => {
let eventNameStr = eventName->eventNameToStrMapper
let firstEvent = events.contents->Js.Dict.get(eventNameStr)->Belt.Option.isNone
let latency = calculateLatencyHook(~eventName=eventNameStr, ~type_, ())
let latency = calculateLatencyHook(~eventName, ~type_, ())
let localTimestamp = timestamp->Belt.Option.getWithDefault(Js.Date.now()->Belt.Float.toString)
let localTimestampFloat =
localTimestamp->Belt.Float.fromString->Belt.Option.getWithDefault(Js.Date.now())
Expand Down Expand Up @@ -628,7 +643,7 @@ let make = (
platform: Window.platform,
userAgent: Window.userAgent,
appId: "",
eventName: eventNameStr,
eventName,
latency,
paymentMethod,
firstEvent,
Expand All @@ -652,7 +667,7 @@ let make = (
) => {
let eventNameStr = eventName->eventNameToStrMapper
let firstEvent = events.contents->Js.Dict.get(eventNameStr)->Belt.Option.isNone
let latency = calculateLatencyHook(~eventName=eventNameStr, ())
let latency = calculateLatencyHook(~eventName, ())
let localTimestamp = timestamp->Belt.Option.getWithDefault(Js.Date.now()->Belt.Float.toString)
let localTimestampFloat =
localTimestamp->Belt.Float.fromString->Belt.Option.getWithDefault(Js.Date.now())
Expand All @@ -674,7 +689,7 @@ let make = (
platform: Window.platform,
userAgent: Window.userAgent,
appId: "",
eventName: eventNameStr,
eventName,
latency,
paymentMethod,
firstEvent,
Expand All @@ -687,8 +702,9 @@ let make = (
}

let setLogInitiated = () => {
let eventName = "LOG_INITIATED"
let firstEvent = events.contents->Js.Dict.get(eventName)->Belt.Option.isNone
let eventName: eventName = LOG_INITIATED
let eventNameStr = eventName->eventNameToStrMapper
let firstEvent = events.contents->Js.Dict.get(eventNameStr)->Belt.Option.isNone
let latency = calculateLatencyHook(~eventName, ())
{
logType: INFO,
Expand Down Expand Up @@ -717,7 +733,7 @@ let make = (
->conditionalLogPush
->ignore
checkLogSizeAndSendData()
events.contents->Js.Dict.set(eventName, Js.Date.now())
events.contents->Js.Dict.set(eventNameStr, Js.Date.now())
}

let handleBeforeUnload = _event => {
Expand Down
Loading

0 comments on commit 6ecbadd

Please sign in to comment.