Skip to content
This repository has been archived by the owner on Oct 4, 2023. It is now read-only.

Commit

Permalink
feat: add client tracing to on-chain & intra-ledger payments
Browse files Browse the repository at this point in the history
  • Loading branch information
Theophilus Isah authored and Theophilus Isah committed Sep 26, 2022
1 parent 5d86b21 commit 38ff2d4
Show file tree
Hide file tree
Showing 8 changed files with 407 additions and 28 deletions.
7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,21 @@
"@galoymoney/client": "^0.1.48",
"@galoymoney/react": "^0.1.12",
"@opentelemetry/api": "^1.1.0",
"@opentelemetry/context-zone": "^1.7.0",
"@opentelemetry/core": "^1.5.0",
"@opentelemetry/exporter-collector": "^0.25.0",
"@opentelemetry/exporter-jaeger": "^1.5.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.33.0",
"@opentelemetry/instrumentation": "^0.31.0",
"@opentelemetry/instrumentation-document-load": "^0.30.0",
"@opentelemetry/instrumentation-fetch": "^0.33.0",
"@opentelemetry/instrumentation-http": "^0.31.0",
"@opentelemetry/resources": "^1.5.0",
"@opentelemetry/sdk-trace-base": "^1.5.0",
"@opentelemetry/sdk-trace-node": "^1.5.0",
"@opentelemetry/semantic-conventions": "^1.5.0",
"@opentelemetry/tracing": "^0.24.0",
"@opentelemetry/web": "^0.24.0",
"@ory/client": "^0.2.0-alpha.4",
"@ory/integrations": "^0.2.6",
"@ory/kratos-client": "^0.10.1",
Expand Down
15 changes: 9 additions & 6 deletions src/components/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { KratosFlowData } from "kratos/index"

import { AuthProvider } from "components/auth-provider"
import RootComponent from "components/root-component"
import TraceProvider from "store/client-tracing/trace-provider"

type RootFCT = React.FC<{ GwwState: GwwStateType }>

Expand Down Expand Up @@ -38,12 +39,14 @@ const Root: RootFCT = ({ GwwState }) => {
return (
<AuthProvider authIdentity={state.authIdentity}>
<GwwContext.Provider value={{ state, dispatch }}>
<RootComponent
key={state.key}
path={state.path}
flowData={state.flowData}
{...state.props}
/>
<TraceProvider>
<RootComponent
key={state.key}
path={state.path}
flowData={state.flowData}
{...state.props}
/>
</TraceProvider>
</GwwContext.Provider>
</AuthProvider>
)
Expand Down
12 changes: 12 additions & 0 deletions src/components/send/send-action-display.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { MouseEvent } from "react"

import { formatUsd, GaloyGQL } from "@galoymoney/client"
import { SatFormat, Spinner, SuccessCheckmark } from "@galoymoney/react"
import { Span } from "@opentelemetry/api"

import { translate } from "store/index"
import { getTracer, withTracing } from "store/client-tracing/tracing"

import useMyUpdates from "hooks/use-my-updates"

Expand Down Expand Up @@ -59,7 +61,17 @@ const SendActionDisplay: SendActionDisplayFCT = ({
reset,
handleSend,
}) => {
const recordErrors = (sendError: string, span: Span) => {
span.setAttribute("Error sending payment", sendError)
withTracing("send bitcoin error", span)
}

if (error) {
if (typeof error === "string") {
const tracer = getTracer()
const span = tracer.startSpan("web wallet error")
recordErrors(error, span)
}
return <div className="error">{error}</div>
}

Expand Down
36 changes: 26 additions & 10 deletions src/components/send/send-intra-ledger-action.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { useMutation } from "@galoymoney/client"
import { MouseEvent } from "react"
import React, { MouseEvent } from "react"

import SendActionDisplay from "components/send/send-action-display"
import { SendActionProps } from "components/send/send-action"
import { getTracer, withTracing, reportSpan } from "store/client-tracing/tracing"

const tracer = getTracer()

export type SendIntraLedgerActionProps = SendActionProps & {
recipientWalletId: string
Expand All @@ -12,23 +15,36 @@ export type SendIntraLedgerActionProps = SendActionProps & {
type FCT = React.FC<SendIntraLedgerActionProps>

const SendIntraLedgerAction: FCT = (props) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [parentSpan, setParentSpan] = React.useState<any>(null)
const [sendPayment, { loading, errorsMessage, data }] =
useMutation.intraLedgerPaymentSend()

const handleSend = (event: MouseEvent<HTMLButtonElement>) => {
const handleSend = async (event: MouseEvent<HTMLButtonElement>) => {
event.preventDefault()
sendPayment({
variables: {
input: {
walletId: props.btcWalletId,
recipientWalletId: props.recipientWalletId,
amount: props.satAmount,
memo: props.memo,
const rootSpan = tracer.startSpan("web wallet")
await withTracing("intra-ledger send", rootSpan, async () => {
sendPayment({
variables: {
input: {
walletId: props.btcWalletId,
recipientWalletId: props.recipientWalletId,
amount: props.satAmount,
memo: props.memo,
},
},
},
})
})
setParentSpan(rootSpan)
}

React.useEffect(() => {
if (parentSpan) {
parentSpan.end()
reportSpan(parentSpan)
}
}, [parentSpan])

return (
<SendActionDisplay
loading={loading}
Expand Down
36 changes: 26 additions & 10 deletions src/components/send/send-onchain-action.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { useMutation, useQuery } from "@galoymoney/client"
import { MouseEvent } from "react"
import React, { MouseEvent } from "react"

import SendActionDisplay from "components/send/send-action-display"
import { SendActionProps } from "components/send/send-action"
import { getTracer, reportSpan, withTracing } from "store/client-tracing/tracing"

const tracer = getTracer()

export type SendOnChainActionProps = SendActionProps & {
address: string
Expand All @@ -12,6 +15,8 @@ export type SendOnChainActionProps = SendActionProps & {
type FCT = React.FC<SendOnChainActionProps>

const SendOnChainAction: FCT = (props) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [parentSpan, setParentSpan] = React.useState<any>(null)
const [sendPayment, { loading, data, errorsMessage: paymentError }] =
useMutation.onChainPaymentSend()

Expand All @@ -29,20 +34,31 @@ const SendOnChainAction: FCT = (props) => {

const feeSatAmount = feeData?.onChainTxFee?.amount

const handleSend = (event: MouseEvent<HTMLButtonElement>) => {
const handleSend = async (event: MouseEvent<HTMLButtonElement>) => {
event.preventDefault()
sendPayment({
variables: {
input: {
walletId: props.btcWalletId,
address: props.address,
amount: props.satAmount,
memo: props.memo,
const rootSpan = tracer.startSpan("web wallet")
await withTracing("on-chain send", rootSpan, async () => {
sendPayment({
variables: {
input: {
walletId: props.btcWalletId,
address: props.address,
amount: props.satAmount,
memo: props.memo,
},
},
},
})
})
setParentSpan(rootSpan)
}

React.useEffect(() => {
if (parentSpan) {
parentSpan.end()
reportSpan(parentSpan)
}
}, [parentSpan])

return (
<SendActionDisplay
loading={loading || feeLoading}
Expand Down
34 changes: 34 additions & 0 deletions src/store/client-tracing/trace-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { trace } from "@opentelemetry/api"
import { ZoneContextManager } from "@opentelemetry/context-zone"
import { registerInstrumentations } from "@opentelemetry/instrumentation"
import { FetchInstrumentation } from "@opentelemetry/instrumentation-fetch"
import { BatchSpanProcessor, ConsoleSpanExporter } from "@opentelemetry/tracing"
import { WebTracerProvider } from "@opentelemetry/web"

const provider = new WebTracerProvider({})

provider.addSpanProcessor(new BatchSpanProcessor(new ConsoleSpanExporter()))

trace.setGlobalTracerProvider(provider)
const name = "galoy-web-wallet"
const version = "0.1.0"
export const tracer = trace.getTracer(name, version)

const fetchInstrumentation = new FetchInstrumentation()
fetchInstrumentation.setTracerProvider(provider)

provider.register({
contextManager: new ZoneContextManager(),
})

registerInstrumentations({
instrumentations: [fetchInstrumentation],
})

export type TraceProviderProps = {
children?: React.ReactNode
}

export default function TraceProvider({ children }: TraceProviderProps) {
return <>{children}</>
}
42 changes: 42 additions & 0 deletions src/store/client-tracing/tracing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { trace, context, Span } from "@opentelemetry/api"

export const reportSpan = (span: Span) => {
console.log("report span:", span)

fetch("./send-trace", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(span),
})
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => {
console.error("Error:", error)
})
}

export const withTracing = async (name: string, parentSpan: Span, cb?: () => void) => {
const tracer = trace.getTracer("galoy-web-wallet")
let span = trace.getSpan(context.active())

if (parentSpan) {
const ctx = trace.setSpan(context.active(), parentSpan)
span = tracer.startSpan(name, undefined, ctx)
} else {
span = tracer.startSpan(name)
}

if (cb) {
await cb()
}

span.end()

reportSpan(span)
}

export const getTracer = () => {
return trace.getTracer("galoy-web-wallet")
}
Loading

0 comments on commit 38ff2d4

Please sign in to comment.