diff --git a/apps/pay/package.json b/apps/pay/package.json index ae9f073c0e..177bfe75fc 100644 --- a/apps/pay/package.json +++ b/apps/pay/package.json @@ -14,6 +14,18 @@ "dependencies": { "@apollo/client": "^3.7.12", "@galoymoney/client": "^0.2.2", + "@opentelemetry/api": "^1.7.0", + "@opentelemetry/context-zone": "^1.21.0", + "@opentelemetry/core": "^1.21.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.48.0", + "@opentelemetry/instrumentation": "^0.47.0", + "@opentelemetry/instrumentation-fetch": "^0.48.0", + "@opentelemetry/instrumentation-xml-http-request": "^0.48.0", + "@opentelemetry/propagator-b3": "^1.21.0", + "@opentelemetry/sdk-metrics": "^1.21.0", + "@opentelemetry/sdk-trace-base": "^1.20.0", + "@opentelemetry/sdk-trace-web": "^1.21.0", + "@opentelemetry/semantic-conventions": "^1.21.0", "@t3-oss/env-nextjs": "^0.6.1", "bech32": "^2.0.0", "bitcoinjs-lib": "5.0.5", diff --git a/apps/pay/pages/index.tsx b/apps/pay/pages/index.tsx index 72aa16c44a..69fdf0debb 100644 --- a/apps/pay/pages/index.tsx +++ b/apps/pay/pages/index.tsx @@ -12,6 +12,8 @@ import { useRouter } from "next/router" import CurrencyDropdown from "../components/Currency/currency-dropdown" import { getClientSideGqlConfig } from "../config/config" +import initializeTelemetry from "./otel" + const GET_NODE_STATS = gql` query nodeIds { globals { @@ -29,6 +31,8 @@ function Home() { localStorage.getItem("display") ?? "USD", ) + initializeTelemetry() + const router = useRouter() const [username, setUsername] = React.useState("") @@ -68,8 +72,8 @@ function Home() { {error ? "Unavailable" : loading - ? "Loading..." - : data.globals.nodesIds[0]} + ? "Loading..." + : data.globals.nodesIds[0]}

diff --git a/apps/pay/pages/otel.ts b/apps/pay/pages/otel.ts new file mode 100644 index 0000000000..708af09ce4 --- /dev/null +++ b/apps/pay/pages/otel.ts @@ -0,0 +1,43 @@ +// Importing necessary modules from OpenTelemetry packages +import { context, trace } from "@opentelemetry/api" +import { ConsoleSpanExporter, SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base" +import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http" +import { WebTracerProvider } from "@opentelemetry/sdk-trace-web" +import { FetchInstrumentation } from "@opentelemetry/instrumentation-fetch" +import { ZoneContextManager } from "@opentelemetry/context-zone" +import { B3Propagator } from "@opentelemetry/propagator-b3" +import { registerInstrumentations } from "@opentelemetry/instrumentation" + +// Define the initialization function +export default function initializeTelemetry() { + const provider = new WebTracerProvider() + + provider.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter())) + provider.register({ + contextManager: new ZoneContextManager(), + propagator: new B3Propagator(), + }) + + registerInstrumentations({ + instrumentations: [ + new FetchInstrumentation({ + ignoreUrls: [/localhost:8090\/sockjs-node/], + propagateTraceHeaderCorsUrls: [ + "https://cors-test.appspot.com/test", + "https://httpbin.org/get", + ], + clearTimingResources: true, + }), + ], + }) + + // Example of how you might use the provider to create a tracer + // This example function doesn't do anything by itself but is here to show how you might use it + const webTracerWithZone = provider.getTracer("example-tracer-web") + + // Placeholder for any setup logic you might have + console.log("OpenTelemetry initialized") +} + +// Note: This file does not include the event listener setup from the original otel.js example, +// as those are typically handled within the components or pages themselves in a React application. diff --git a/apps/pay/public/BBLogo.png b/apps/pay/public/BBLogo.png deleted file mode 100644 index 6b10c3b652..0000000000 Binary files a/apps/pay/public/BBLogo.png and /dev/null differ diff --git a/apps/pay/public/BBQRLogo.png b/apps/pay/public/BBQRLogo.png deleted file mode 100644 index 80223cc374..0000000000 Binary files a/apps/pay/public/BBQRLogo.png and /dev/null differ diff --git a/apps/pay/public/BBW-QRLOGO.png b/apps/pay/public/BBW-QRLOGO.png deleted file mode 100644 index 6dd409b17b..0000000000 Binary files a/apps/pay/public/BBW-QRLOGO.png and /dev/null differ diff --git a/apps/pay/public/QRLOGO-BBW.png b/apps/pay/public/QRLOGO-BBW.png deleted file mode 100644 index 41ac95fa90..0000000000 Binary files a/apps/pay/public/QRLOGO-BBW.png and /dev/null differ diff --git a/apps/pay/public/otel.js b/apps/pay/public/otel.js new file mode 100644 index 0000000000..0f1842a6e1 --- /dev/null +++ b/apps/pay/public/otel.js @@ -0,0 +1,72 @@ +const { context, trace } = require( '@opentelemetry/api'); +const { ConsoleSpanExporter, SimpleSpanProcessor } = require( '@opentelemetry/sdk-trace-base'); +const { OTLPTraceExporter } = require( '@opentelemetry/exporter-trace-otlp-http'); +const { WebTracerProvider } = require( '@opentelemetry/sdk-trace-web'); +const { FetchInstrumentation } = require( '@opentelemetry/instrumentation-fetch'); +const { ZoneContextManager } = require( '@opentelemetry/context-zone'); +const { B3Propagator } = require( '@opentelemetry/propagator-b3'); +const { registerInstrumentations } = require( '@opentelemetry/instrumentation'); + +const provider = new WebTracerProvider(); + +// Note: For production consider using the "BatchSpanProcessor" to reduce the number of requests +// to your exporter. Using the SimpleSpanProcessor here as it sends the spans immediately to the +// exporter without delay +// provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); +provider.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter())); +provider.register({ + contextManager: new ZoneContextManager(), + propagator: new B3Propagator(), +}); + +registerInstrumentations({ + instrumentations: [ + new FetchInstrumentation({ + ignoreUrls: [/localhost:8090\/sockjs-node/], + propagateTraceHeaderCorsUrls: [ + 'https://cors-test.appspot.com/test', + 'https://httpbin.org/get', + ], + clearTimingResources: true, + }), + ], +}); + +const webTracerWithZone = provider.getTracer('example-tracer-web'); + +const getData = (url) => fetch(url, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, +}); + +// example of keeping track of context between async operations +const prepareClickEvent = () => { + const url = 'https://httpbin.org/get'; + + const element = document.getElementById('button1'); + + const onClick = () => { + const singleSpan = webTracerWithZone.startSpan('files-series-info'); + context.with(trace.setSpan(context.active(), singleSpan), () => { + getData(url).then((_data) => { + trace.getSpan(context.active()).addEvent('fetching-single-span-completed'); + singleSpan.end(); + }); + }); + for (let i = 0, j = 5; i < j; i += 1) { + const span = webTracerWithZone.startSpan(`files-series-info-${i}`); + context.with(trace.setSpan(context.active(), span), () => { + getData(url).then((_data) => { + trace.getSpan(context.active()).addEvent(`fetching-span-${i}-completed`); + span.end(); + }); + }); + } + }; + element.addEventListener('click', onClick); +}; + +window.addEventListener('load', prepareClickEvent); diff --git a/core/api/dev/otel-agent-config.yaml b/core/api/dev/otel-agent-config.yaml index 0a7995ab2c..702e5171a1 100644 --- a/core/api/dev/otel-agent-config.yaml +++ b/core/api/dev/otel-agent-config.yaml @@ -9,6 +9,10 @@ receivers: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 + cors: + allowed_origins: + - http://* + - https://* processors: filter/ottl: diff --git a/dev/config/otel-agent-config.yaml b/dev/config/otel-agent-config.yaml index 0a7995ab2c..702e5171a1 100644 --- a/dev/config/otel-agent-config.yaml +++ b/dev/config/otel-agent-config.yaml @@ -9,6 +9,10 @@ receivers: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 + cors: + allowed_origins: + - http://* + - https://* processors: filter/ottl: diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 132015f20e..cea0a1d3b9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -574,6 +574,42 @@ importers: '@galoymoney/client': specifier: ^0.2.2 version: 0.2.6(@bitcoinerlab/secp256k1@1.0.5)(bitcoinjs-lib@5.0.5)(bolt11@1.3.4)(lnurl-pay@1.0.1)(url@0.11.3) + '@opentelemetry/api': + specifier: ^1.7.0 + version: 1.7.0 + '@opentelemetry/context-zone': + specifier: ^1.21.0 + version: 1.21.0(@opentelemetry/api@1.7.0) + '@opentelemetry/core': + specifier: ^1.21.0 + version: 1.21.0(@opentelemetry/api@1.7.0) + '@opentelemetry/exporter-trace-otlp-http': + specifier: ^0.48.0 + version: 0.48.0(@opentelemetry/api@1.7.0) + '@opentelemetry/instrumentation': + specifier: ^0.47.0 + version: 0.47.0(@opentelemetry/api@1.7.0) + '@opentelemetry/instrumentation-fetch': + specifier: ^0.48.0 + version: 0.48.0(@opentelemetry/api@1.7.0) + '@opentelemetry/instrumentation-xml-http-request': + specifier: ^0.48.0 + version: 0.48.0(@opentelemetry/api@1.7.0) + '@opentelemetry/propagator-b3': + specifier: ^1.21.0 + version: 1.21.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-metrics': + specifier: ^1.21.0 + version: 1.21.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-base': + specifier: ^1.20.0 + version: 1.21.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-web': + specifier: ^1.21.0 + version: 1.21.0(@opentelemetry/api@1.7.0) + '@opentelemetry/semantic-conventions': + specifier: ^1.21.0 + version: 1.21.0 '@t3-oss/env-nextjs': specifier: ^0.6.1 version: 0.6.1(typescript@5.2.2)(zod@3.22.4) @@ -612,7 +648,7 @@ importers: version: 4.0.8 next: specifier: ^13.4.19 - version: 13.5.6(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0) + version: 13.5.6(@babel/core@7.23.9)(@opentelemetry/api@1.7.0)(react-dom@18.2.0)(react@18.2.0) react: specifier: ^18.2.0 version: 18.2.0 @@ -6387,8 +6423,8 @@ packages: optional: true dependencies: '@babel/generator': 7.23.6 - '@babel/template': 7.22.15 - '@babel/types': 7.23.6 + '@babel/template': 7.23.9 + '@babel/types': 7.23.9 '@graphql-codegen/core': 4.0.0(graphql@16.8.1) '@graphql-codegen/plugin-helpers': 5.0.1(graphql@16.8.1) '@graphql-tools/apollo-engine-loader': 8.0.0(graphql@16.8.1) @@ -7266,7 +7302,7 @@ packages: '@graphql-tools/utils': 8.9.0(graphql@16.8.1) dataloader: 2.1.0 graphql: 16.8.1 - tslib: 2.4.1 + tslib: 2.6.2 value-or-promise: 1.0.11 dev: false @@ -9625,6 +9661,27 @@ packages: '@opentelemetry/api': 1.7.0 dev: false + /@opentelemetry/context-zone-peer-dep@1.21.0(@opentelemetry/api@1.7.0)(zone.js@0.11.8): + resolution: {integrity: sha512-VShgSOPlc2UWaNdJST7syUDLdFKstkiqVDBaFEwSwvXP9IIaE7XxS5uAVkd55EVOzfB7PhdEQ91roAt5pHyzhQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.8.0' + zone.js: ^0.10.2 || ^0.11.0 || ^0.13.0 + dependencies: + '@opentelemetry/api': 1.7.0 + zone.js: 0.11.8 + dev: false + + /@opentelemetry/context-zone@1.21.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-YJQH3LroaZZBN0baGLkvw1WlNNpdNxXf7wfdJrst5v+lYGOus5HX9GUAOB9dByj3Z6yGlPIboPPojnc+ybxKGA==} + engines: {node: '>=14'} + dependencies: + '@opentelemetry/context-zone-peer-dep': 1.21.0(@opentelemetry/api@1.7.0)(zone.js@0.11.8) + zone.js: 0.11.8 + transitivePeerDependencies: + - '@opentelemetry/api' + dev: false + /@opentelemetry/core@1.17.1(@opentelemetry/api@1.7.0): resolution: {integrity: sha512-I6LrZvl1FF97FQXPR0iieWQmKnGxYtMbWA1GrAXnLUR+B1Hn2m8KqQNEIlZAucyv00GBgpWkpllmULmZfG8P3g==} engines: {node: '>=14'} @@ -9807,6 +9864,21 @@ packages: '@opentelemetry/semantic-conventions': 1.21.0 dev: false + /@opentelemetry/instrumentation-fetch@0.48.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-y4Zw9VeUUMaowg3aXYZXcaUJQ7IKfpR6sjClrAQOJwWG8LYFpM6NIRSoAeJv/ShfxWWCPWC0P4zgXcKRqpURFQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.0.0 + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) + '@opentelemetry/instrumentation': 0.48.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-web': 1.21.0(@opentelemetry/api@1.7.0) + '@opentelemetry/semantic-conventions': 1.21.0 + transitivePeerDependencies: + - supports-color + dev: false + /@opentelemetry/instrumentation-graphql@0.35.2(@opentelemetry/api@1.7.0): resolution: {integrity: sha512-lJv7BbHFK0ExwogdQMtVHfnWhCBMDQEz8KYvhShXfRPiSStU5aVwa3TmT0O00KiJFpATSKJNZMv1iZNHbF6z1g==} engines: {node: '>=14'} @@ -9951,7 +10023,7 @@ packages: dependencies: '@opentelemetry/api': 1.7.0 '@opentelemetry/instrumentation': 0.46.0(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-metrics': 1.20.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-metrics': 1.21.0(@opentelemetry/api@1.7.0) '@opentelemetry/semantic-conventions': 1.21.0 transitivePeerDependencies: - supports-color @@ -9996,6 +10068,21 @@ packages: - supports-color dev: false + /@opentelemetry/instrumentation-xml-http-request@0.48.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-YJ9d1sR28hcEVtP4/tHtPX5Hhu0w2LsAMp3M+75YGTHkkunsN8PwcY/1FcSHUP9xwy7Z2myQvT7fTpL3g4tn4A==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.0.0 + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) + '@opentelemetry/instrumentation': 0.48.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-web': 1.21.0(@opentelemetry/api@1.7.0) + '@opentelemetry/semantic-conventions': 1.21.0 + transitivePeerDependencies: + - supports-color + dev: false + /@opentelemetry/instrumentation@0.44.0(@opentelemetry/api@1.7.0): resolution: {integrity: sha512-B6OxJTRRCceAhhnPDBshyQO7K07/ltX3quOLu0icEvPK9QZ7r9P1y0RQX8O5DxB4vTv4URRkxkg+aFU/plNtQw==} engines: {node: '>=14'} @@ -10576,6 +10663,18 @@ packages: semver: 7.6.0 dev: false + /@opentelemetry/sdk-trace-web@1.21.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-MxkmY/UNXkDiZj7JUu5T7wWt8Ai4NJEwSjGoQQ9YLvgLUIivvaIo9Mne+Q+KLOUG2v/uhivz3qzxbCODVa0c1A==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.8.0' + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-base': 1.21.0(@opentelemetry/api@1.7.0) + '@opentelemetry/semantic-conventions': 1.21.0 + dev: false + /@opentelemetry/semantic-conventions@1.17.1: resolution: {integrity: sha512-xbR2U+2YjauIuo42qmE8XyJK6dYeRMLJuOlUP5SO4auET4VtOHOzgkRVOq+Ik18N+Xf3YPcqJs9dZMiDddz1eQ==} engines: {node: '>=14'} @@ -15055,7 +15154,7 @@ packages: debug: 4.3.4(supports-color@5.5.0) globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.4 + semver: 7.6.0 tsutils: 3.21.0(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: @@ -15076,7 +15175,7 @@ packages: debug: 4.3.4(supports-color@5.5.0) globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.4 + semver: 7.6.0 tsutils: 3.21.0(typescript@5.2.2) typescript: 5.2.2 transitivePeerDependencies: @@ -15097,7 +15196,7 @@ packages: debug: 4.3.4(supports-color@5.5.0) globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.4 + semver: 7.6.0 tsutils: 3.21.0(typescript@5.3.3) typescript: 5.3.3 transitivePeerDependencies: @@ -15141,7 +15240,7 @@ packages: globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 - semver: 7.5.4 + semver: 7.6.0 ts-api-utils: 1.0.3(typescript@5.2.2) typescript: 5.2.2 transitivePeerDependencies: @@ -15163,7 +15262,7 @@ packages: globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 - semver: 7.5.4 + semver: 7.6.0 ts-api-utils: 1.0.3(typescript@5.3.3) typescript: 5.3.3 transitivePeerDependencies: @@ -15267,7 +15366,7 @@ packages: '@typescript-eslint/types': 6.17.0 '@typescript-eslint/typescript-estree': 6.17.0(typescript@5.3.3) eslint: 8.56.0 - semver: 7.5.4 + semver: 7.6.0 transitivePeerDependencies: - supports-color - typescript @@ -25717,7 +25816,7 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false - /next@13.5.6(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0): + /next@13.5.6(@babel/core@7.23.9)(@opentelemetry/api@1.7.0)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-Y2wTcTbO4WwEsVb4A8VSnOsG1I9ok+h74q0ZdxkwM3EODqrs4pasq7O0iUxbcS9VtWMicG7f3+HAj0r1+NtKSw==} engines: {node: '>=16.14.0'} hasBin: true @@ -25733,6 +25832,7 @@ packages: optional: true dependencies: '@next/env': 13.5.6 + '@opentelemetry/api': 1.7.0 '@swc/helpers': 0.5.2 busboy: 1.6.0 caniuse-lite: 1.0.30001561 @@ -25887,7 +25987,7 @@ packages: resolution: {integrity: sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==} engines: {node: '>=10'} dependencies: - semver: 7.5.4 + semver: 7.6.0 dev: false /node-abort-controller@3.1.1: @@ -28843,7 +28943,7 @@ packages: resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} engines: {node: '>=10'} dependencies: - semver: 7.5.4 + semver: 7.6.0 dev: true /sisteransi@1.0.5: @@ -29824,7 +29924,7 @@ packages: hasBin: true dependencies: '@jridgewell/source-map': 0.3.5 - acorn: 8.11.2 + acorn: 8.11.3 commander: 2.20.3 source-map-support: 0.5.21 dev: true @@ -30612,7 +30712,7 @@ packages: /unplugin@1.5.1: resolution: {integrity: sha512-0QkvG13z6RD+1L1FoibQqnvTwVBXvS4XSPwAyinVgoOCl2jAgwzdUKmEj05o4Lt8xwQI85Hb6mSyYkcAGwZPew==} dependencies: - acorn: 8.11.2 + acorn: 8.11.3 chokidar: 3.6.0 webpack-sources: 3.2.3 webpack-virtual-modules: 0.6.1 @@ -31533,3 +31633,9 @@ packages: /zod@3.22.4: resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} dev: false + + /zone.js@0.11.8: + resolution: {integrity: sha512-82bctBg2hKcEJ21humWIkXRlLBBmrc3nN7DFh5LGGhcyycO2S7FN8NmdvlcKaGFDNVL4/9kFLmwmInTavdJERA==} + dependencies: + tslib: 2.6.2 + dev: false