From 334a03512211ba1158154f5e193d076876d7ff10 Mon Sep 17 00:00:00 2001 From: Rares Mardare Date: Fri, 9 Dec 2022 11:02:06 +0200 Subject: [PATCH 01/19] added grafana-faro --- grafana-plugin/package.json | 4 + grafana-plugin/src/network/index.ts | 61 ++++- .../src/plugin/GrafanaPluginRootPage.tsx | 91 ++++++-- .../src/state/rootBaseStore/index.ts | 4 + grafana-plugin/yarn.lock | 218 +++++++++++++++++- 5 files changed, 344 insertions(+), 34 deletions(-) diff --git a/grafana-plugin/package.json b/grafana-plugin/package.json index 0c74a2a9..7b150730 100644 --- a/grafana-plugin/package.json +++ b/grafana-plugin/package.json @@ -104,6 +104,10 @@ "node": ">=14" }, "dependencies": { + "@grafana/faro-core": "^1.0.0-beta3", + "@grafana/faro-react": "^1.0.0-beta3", + "@grafana/faro-web-sdk": "^1.0.0-beta3", + "@opentelemetry/api": "^1.3.0", "array-move": "^4.0.0", "change-case": "^4.1.1", "circular-dependency-plugin": "^5.2.2", diff --git a/grafana-plugin/src/network/index.ts b/grafana-plugin/src/network/index.ts index bfb7068e..18181bd9 100644 --- a/grafana-plugin/src/network/index.ts +++ b/grafana-plugin/src/network/index.ts @@ -1,3 +1,5 @@ +import { faro } from '@grafana/faro-react'; +import { SpanStatusCode } from '@opentelemetry/api'; import axios from 'axios'; import qs from 'query-string'; @@ -35,13 +37,56 @@ export const makeRequest = async (path: string, config: RequestConfig) const url = `${API_PROXY_PREFIX}${API_PATH_PREFIX}${path}`; - const response = await instance({ - method, - url, - params, - data, - validateStatus, - }); + const otel = faro.api.getOTEL(); - return response.data as RT; + if (otel) { + const tracer = otel.trace.getTracer('default'); + let span = otel.trace.getActiveSpan() ?? tracer.startSpan('http-request'); + + return new Promise((resolve, reject) => { + otel.context.with(otel.trace.setSpan(otel.context.active(), span), async () => { + faro.api.pushEvent('Sending request', { url }); + + try { + const response = await instance({ + method, + url, + params, + data, + validateStatus, + }); + + faro.api.pushEvent('Request completed', { url }); + + resolve(response.data as RT); + } catch (ex) { + faro.api.pushEvent('Request failed', { url }); + faro.api.pushError(ex); + + span.setStatus({ code: SpanStatusCode.ERROR }); + reject(ex); + } finally { + span.end(); + } + }); + }); + } + + try { + const response = await instance({ + method, + url, + params, + data, + validateStatus, + }); + + faro.api.pushEvent('Request completed', { url }); + + return response.data as RT; + } catch (ex) { + faro.api.pushEvent('Request failed', { url }); + faro.api.pushError(ex); + throw ex; + } }; diff --git a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx index 3eaa6d5d..8b7e40f4 100644 --- a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx +++ b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx @@ -1,5 +1,7 @@ import React, { useEffect, useMemo, useState } from 'react'; +import { initializeFaro, getWebInstrumentations, ReactIntegration, ReactRouterVersion } from '@grafana/faro-react'; +import { TracingInstrumentation } from '@grafana/faro-web-tracing'; import { locationService } from '@grafana/runtime'; import classnames from 'classnames'; import dayjs from 'dayjs'; @@ -8,6 +10,8 @@ import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'; import isoWeek from 'dayjs/plugin/isoWeek'; import localeData from 'dayjs/plugin/localeData'; import timezone from 'dayjs/plugin/timezone'; +import { Route, useHistory } from 'react-router'; + import utc from 'dayjs/plugin/utc'; import weekday from 'dayjs/plugin/weekday'; import { observer, Provider } from 'mobx-react'; @@ -25,6 +29,8 @@ import { useStore } from 'state/useStore'; import { isUserActionAllowed } from 'utils/authorization'; import { useQueryParams, useQueryPath } from 'utils/hooks'; +import { FaroErrorBoundary } from '@grafana/faro-react'; + dayjs.extend(utc); dayjs.extend(timezone); dayjs.extend(weekday); @@ -40,6 +46,8 @@ import 'style/utils.css'; import { getQueryParams, isTopNavbar } from './GrafanaPluginRootPage.helpers'; import PluginSetup from './PluginSetup'; +import { RootBaseStore } from 'state/rootBaseStore'; + export const GrafanaPluginRootPage = (props: AppRootProps) => ( @@ -56,6 +64,7 @@ export const Root = observer((props: AppRootProps) => { const pathWithoutLeadingSlash = path.replace(/^\//, ''); const store = useStore(); + const history = useHistory(); useEffect(() => { updateBasicData(); @@ -69,6 +78,8 @@ export const Root = observer((props: AppRootProps) => { document.head.appendChild(link); + initFaro(store, history); + return () => { document.head.removeChild(link); }; @@ -89,33 +100,67 @@ export const Root = observer((props: AppRootProps) => { const userHasAccess = pagePermissionAction ? isUserActionAllowed(pagePermissionAction) : true; return ( - - {!isTopNavbar() && ( - <> -
- - - )} + + + {!isTopNavbar() && ( + <> +
+ + + )} -
- {userHasAccess ? ( - - ) : ( - - )} -
- +
+ {userHasAccess ? ( + + ) : ( + + )} +
+ + ); }); +function initFaro(store: RootBaseStore, history: any) { + const faro = initializeFaro({ + url: `http://localhost:${''}/collect`, + apiKey: '', + instrumentations: [ + ...getWebInstrumentations({ + captureConsole: true, + }), + new TracingInstrumentation(), + new ReactIntegration({ + router: { + version: ReactRouterVersion.V5, + dependencies: { + history, + Route, + }, + }, + }), + ], + session: (window as any).__PRELOADED_STATE__?.faro?.session, + app: { + name: '', + version: '', + environment: '', + }, + }); + + faro.api.pushLog(['Faro was initialized for Grafana On Call']); + + store.faro = faro; +} + function getPageMatchingComponent(pageId: string): (props?: any) => JSX.Element { let matchingPage = routes[pageId]; if (!matchingPage) { diff --git a/grafana-plugin/src/state/rootBaseStore/index.ts b/grafana-plugin/src/state/rootBaseStore/index.ts index 6b069ca7..d30d13dd 100644 --- a/grafana-plugin/src/state/rootBaseStore/index.ts +++ b/grafana-plugin/src/state/rootBaseStore/index.ts @@ -1,3 +1,4 @@ +import { Faro } from '@grafana/faro-core'; import { action, observable } from 'mobx'; import moment from 'moment-timezone'; import qs from 'query-string'; @@ -72,6 +73,9 @@ export class RootBaseStore { @observable onCallApiUrl: string; + @observable + faro: Faro = undefined; + // -------------------------- userStore: UserStore = new UserStore(this); diff --git a/grafana-plugin/yarn.lock b/grafana-plugin/yarn.lock index b09206b0..8b6b11ab 100644 --- a/grafana-plugin/yarn.lock +++ b/grafana-plugin/yarn.lock @@ -1604,6 +1604,25 @@ "@opentelemetry/otlp-transformer" "^0.33.0" fast-deep-equal "^3.1.3" +"@grafana/faro-core@^1.0.0-beta3": + version "1.0.0-beta3" + resolved "https://registry.yarnpkg.com/@grafana/faro-core/-/faro-core-1.0.0-beta3.tgz#705f561790b6f1d8b65a0a3507a1955519d393f8" + integrity sha512-P+mp2CMIYovmFFLJx7fvds65m+u0NB9l6RI0kKEPQHiMoR7cnHhe/dK049mk8widK0Z5Vmz1QBaNWxn3jO52cg== + dependencies: + "@opentelemetry/api" "^1.3.0" + "@opentelemetry/api-metrics" "^0.33.0" + "@opentelemetry/otlp-transformer" "^0.34.0" + fast-deep-equal "^3.1.3" + +"@grafana/faro-react@^1.0.0-beta3": + version "1.0.0-beta3" + resolved "https://registry.yarnpkg.com/@grafana/faro-react/-/faro-react-1.0.0-beta3.tgz#f28ba2fba136cd6d0417f6894218f359a5cdc88e" + integrity sha512-E8aI8FPqzs9NgOa3ApfeCNtmhakgMgfg1xu0snNz7Gt0KHssoHyIYrOHlI/C45BhkSXRMetIvhJv/YQkE9Ua7Q== + dependencies: + "@grafana/faro-web-sdk" "^1.0.0-beta3" + "@grafana/faro-web-tracing" "^1.0.0-beta3" + hoist-non-react-statics "^3.3.2" + "@grafana/faro-web-sdk@1.0.0-beta2": version "1.0.0-beta2" resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-1.0.0-beta2.tgz#d096a350d6366a108428a205753c797802eb480d" @@ -1613,6 +1632,36 @@ ua-parser-js "^1.0.32" web-vitals "^3.0.4" +"@grafana/faro-web-sdk@^1.0.0-beta3": + version "1.0.0-beta3" + resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-1.0.0-beta3.tgz#b26e0a3888228d59555a36ae4dcda4d711d4102f" + integrity sha512-vtU53oPrDXt655ggkusvogrTpDHHBm5JO0MbYlrYqvJprUpGaTsEgnb6lDRpXht3Vy6nk9h0+q0tBzgryZtY/w== + dependencies: + "@grafana/faro-core" "^1.0.0-beta3" + ua-parser-js "^1.0.32" + web-vitals "^3.1.0" + +"@grafana/faro-web-tracing@^1.0.0-beta3": + version "1.0.0-beta3" + resolved "https://registry.yarnpkg.com/@grafana/faro-web-tracing/-/faro-web-tracing-1.0.0-beta3.tgz#a2b760f0f6beb64417e8e5f54706ae7ac1ae63c7" + integrity sha512-PIa3M8NNn6lIwr1zaJ3BIr/TAAZcNGipcPs7TZGEFgNenrCHIKghW7o2v6VW+ttSRTc4zaymphy5zCoXy5Hvug== + dependencies: + "@grafana/faro-core" "^1.0.0-beta3" + "@opentelemetry/api" "^1.3.0" + "@opentelemetry/context-zone" "^1.8.0" + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/exporter-trace-otlp-http" "^0.34.0" + "@opentelemetry/instrumentation" "^0.34.0" + "@opentelemetry/instrumentation-document-load" "^0.31.0" + "@opentelemetry/instrumentation-fetch" "^0.34.0" + "@opentelemetry/instrumentation-user-interaction" "^0.32.0" + "@opentelemetry/instrumentation-xml-http-request" "^0.34.0" + "@opentelemetry/otlp-transformer" "^0.34.0" + "@opentelemetry/resources" "^1.8.0" + "@opentelemetry/sdk-trace-base" "^1.8.0" + "@opentelemetry/sdk-trace-web" "^1.8.0" + "@opentelemetry/semantic-conventions" "^1.8.0" + "@grafana/runtime@9.3.0-beta1": version "9.3.0-beta1" resolved "https://registry.yarnpkg.com/@grafana/runtime/-/runtime-9.3.0-beta1.tgz#4bcd5d8c24c1e810b254f113598cbb1cb759ee16" @@ -2360,11 +2409,24 @@ dependencies: "@opentelemetry/api" "^1.0.0" -"@opentelemetry/api@^1.0.0", "@opentelemetry/api@^1.1.0": +"@opentelemetry/api@^1.0.0", "@opentelemetry/api@^1.1.0", "@opentelemetry/api@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.3.0.tgz#27c6f776ac3c1c616651e506a89f438a0ed6a055" integrity sha512-YveTnGNsFFixTKJz09Oi4zYkiLT5af3WpZDu4aIUM7xX+2bHAkOJayFTVQd6zB8kkWPpbua4Ha6Ql00grdLlJQ== +"@opentelemetry/context-zone-peer-dep@1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/context-zone-peer-dep/-/context-zone-peer-dep-1.8.0.tgz#79e38b7f1d6b10424a628723eeb6fe7d80082692" + integrity sha512-j8hnrH9OOU9Rw4NN15fwXvaKtdXdsk0vj48YqC/c0mngf0xWroDvruOyOu2i43N+0mBRAv7YOcf52hFD4YQDng== + +"@opentelemetry/context-zone@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/context-zone/-/context-zone-1.8.0.tgz#41c3b60b59bec1d195f63937919b9c233b359e2d" + integrity sha512-IcDyvP3qSQq2ekH7CPYG6qeDHHi5edRK3bmf19gAi/kmr+pEzQL70/66BDLXThHPEWyklu0OfMFPypOrA1roMQ== + dependencies: + "@opentelemetry/context-zone-peer-dep" "1.8.0" + zone.js "^0.11.0" + "@opentelemetry/core@1.7.0": version "1.7.0" resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.7.0.tgz#83bdd1b7a4ceafcdffd6590420657caec5f7b34c" @@ -2372,6 +2434,90 @@ dependencies: "@opentelemetry/semantic-conventions" "1.7.0" +"@opentelemetry/core@1.8.0", "@opentelemetry/core@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.8.0.tgz#cca18594dd48ded6dc0d08c7e789c79af0315934" + integrity sha512-6SDjwBML4Am0AQmy7z1j6HGrWDgeK8awBRUvl1PGw6HayViMk4QpnUXvv4HTHisecgVBy43NE/cstWprm8tIfw== + dependencies: + "@opentelemetry/semantic-conventions" "1.8.0" + +"@opentelemetry/exporter-trace-otlp-http@^0.34.0": + version "0.34.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.34.0.tgz#baca4cebb1666ed801288e24215d96a65f2e8ae5" + integrity sha512-MBtUwMvgpdoRo9iqK2eDJ8SP2xKYWeBCSu99s4cc1kg4HKKOpenXLE/6daGsSZ+QTPwd8j+9xMSd+hhBg+Bvzw== + dependencies: + "@opentelemetry/core" "1.8.0" + "@opentelemetry/otlp-exporter-base" "0.34.0" + "@opentelemetry/otlp-transformer" "0.34.0" + "@opentelemetry/resources" "1.8.0" + "@opentelemetry/sdk-trace-base" "1.8.0" + +"@opentelemetry/instrumentation-document-load@^0.31.0": + version "0.31.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-document-load/-/instrumentation-document-load-0.31.0.tgz#8e6117b68e420fe962963baf7526d97c861b4c36" + integrity sha512-IlbJxUOyvJiatNerKuTii6cEW8iX/9F42zGmyqi8WjgxCZtncRAhkl9argG0xlQvpIoOWEotWB9S+++CjJfvfw== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.34.0" + "@opentelemetry/sdk-trace-base" "^1.0.0" + "@opentelemetry/sdk-trace-web" "^1.8.0" + "@opentelemetry/semantic-conventions" "^1.0.0" + +"@opentelemetry/instrumentation-fetch@^0.34.0": + version "0.34.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-fetch/-/instrumentation-fetch-0.34.0.tgz#059b2a389acaa1cf8af509fe3c5302c0d480710a" + integrity sha512-5ihgQiRG7UGDcj0JnsLZmN/VbZj1vcKaw1frGjsEnMzvjbulYXPwmUbtxzZGxe0lpX6u6zQIpo28Ccdzxt1pJg== + dependencies: + "@opentelemetry/core" "1.8.0" + "@opentelemetry/instrumentation" "0.34.0" + "@opentelemetry/sdk-trace-web" "1.8.0" + "@opentelemetry/semantic-conventions" "1.8.0" + +"@opentelemetry/instrumentation-user-interaction@^0.32.0": + version "0.32.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-user-interaction/-/instrumentation-user-interaction-0.32.0.tgz#f4f2f9836d0374a51f97833e34d6a5d7aff9c40d" + integrity sha512-FW/N4Wu2EHv06sXyl2j57lMTAHkBb9b47+YVcUgDU+g2hpz1zC07Ajo1eZQF99tYtRy/25XX2lMOriLrrviyQg== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.34.0" + "@opentelemetry/sdk-trace-web" "^1.8.0" + +"@opentelemetry/instrumentation-xml-http-request@^0.34.0": + version "0.34.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-xml-http-request/-/instrumentation-xml-http-request-0.34.0.tgz#349818aecd967196bb2568af7496980a9ecb6498" + integrity sha512-STJuL7smHN09Q1cqN6cfQmg/9FDjPnzbIzmFV7UIWcZnHH38x2v6s8kPRZrsN8HJEH9SkS4SKbrtPW8fHX+Blw== + dependencies: + "@opentelemetry/core" "1.8.0" + "@opentelemetry/instrumentation" "0.34.0" + "@opentelemetry/sdk-trace-web" "1.8.0" + "@opentelemetry/semantic-conventions" "1.8.0" + +"@opentelemetry/instrumentation@0.34.0", "@opentelemetry/instrumentation@^0.34.0": + version "0.34.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.34.0.tgz#bae86da46ea4466594689975cd10f0c3720b4071" + integrity sha512-VET/bOh4StOQV4vf1sAvn2JD67BhW2vPZ/ynl2gHXyafme2yB8Hs9+tr1TLzFwNGo7jwMFviFQkZjCYxMuK0AA== + dependencies: + require-in-the-middle "^5.0.3" + semver "^7.3.2" + shimmer "^1.2.1" + +"@opentelemetry/otlp-exporter-base@0.34.0": + version "0.34.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.34.0.tgz#c6020b63590d4b8ac3833eda345a6f582fa014b1" + integrity sha512-xVNvQm7oXeQogeI21iTZRnBrBYS0OVekPutEJgb7jQtHg7x2GWuCBQK9sDo84FRWNXBpNOgSYqsf8/+PxIJ2vA== + dependencies: + "@opentelemetry/core" "1.8.0" + +"@opentelemetry/otlp-transformer@0.34.0", "@opentelemetry/otlp-transformer@^0.34.0": + version "0.34.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.34.0.tgz#71023706233c7bc6c3cdcf954c749fea9338084c" + integrity sha512-NghPJvn3pVoWBuhWyBe1n/nWIrj1D1EFUH/bIkWEp0CMVWFLux6R+BkRPZQo5klTcj8xFhCZZIZsL/ubkYPryg== + dependencies: + "@opentelemetry/core" "1.8.0" + "@opentelemetry/resources" "1.8.0" + "@opentelemetry/sdk-metrics" "1.8.0" + "@opentelemetry/sdk-trace-base" "1.8.0" + "@opentelemetry/otlp-transformer@^0.33.0": version "0.33.0" resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.33.0.tgz#6fd3ddc944f017da08d445f142cad1779770e0e0" @@ -2391,6 +2537,14 @@ "@opentelemetry/core" "1.7.0" "@opentelemetry/semantic-conventions" "1.7.0" +"@opentelemetry/resources@1.8.0", "@opentelemetry/resources@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.8.0.tgz#260be9742cf7bceccc0db928d8ca8d64391acfe3" + integrity sha512-KSyMH6Jvss/PFDy16z5qkCK0ERlpyqixb1xwb73wLMvVq+j7i89lobDjw3JkpCcd1Ws0J6jAI4fw28Zufj2ssg== + dependencies: + "@opentelemetry/core" "1.8.0" + "@opentelemetry/semantic-conventions" "1.8.0" + "@opentelemetry/sdk-metrics@0.33.0": version "0.33.0" resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-0.33.0.tgz#c4e51decc6e3bb0e1e97c7b081955d357e46c2fe" @@ -2401,6 +2555,15 @@ "@opentelemetry/resources" "1.7.0" lodash.merge "4.6.2" +"@opentelemetry/sdk-metrics@1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-1.8.0.tgz#d061060f03861ab3f345d0f924922bc1a6396157" + integrity sha512-+KYb+uj0vHhl8xzJO+oChS4oP1e+/2Wl3SXoHoIdcEjd1TQfDV+lxOm4oqxWq6wykXvI35/JHyejxSoT+qxGmg== + dependencies: + "@opentelemetry/core" "1.8.0" + "@opentelemetry/resources" "1.8.0" + lodash.merge "4.6.2" + "@opentelemetry/sdk-trace-base@1.7.0": version "1.7.0" resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.7.0.tgz#b498424e0c6340a9d80de63fd408c5c2130a60a5" @@ -2410,11 +2573,34 @@ "@opentelemetry/resources" "1.7.0" "@opentelemetry/semantic-conventions" "1.7.0" +"@opentelemetry/sdk-trace-base@1.8.0", "@opentelemetry/sdk-trace-base@^1.0.0", "@opentelemetry/sdk-trace-base@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.8.0.tgz#70713aab90978a16dea188c8335209f857be7384" + integrity sha512-iH41m0UTddnCKJzZx3M85vlhKzRcmT48pUeBbnzsGrq4nIay1oWVHKM5nhB5r8qRDGvd/n7f/YLCXClxwM0tvA== + dependencies: + "@opentelemetry/core" "1.8.0" + "@opentelemetry/resources" "1.8.0" + "@opentelemetry/semantic-conventions" "1.8.0" + +"@opentelemetry/sdk-trace-web@1.8.0", "@opentelemetry/sdk-trace-web@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-web/-/sdk-trace-web-1.8.0.tgz#78432fe77567cbf46846169f9f7b7643f421965b" + integrity sha512-SfotgAOOy6WTDtIxo97DjE+4l+hCiMqI0A3/TbJjixMPpk4ir/32uFqU9urhH/+zRybwwGYkQ6eILeuyZUi0ZQ== + dependencies: + "@opentelemetry/core" "1.8.0" + "@opentelemetry/sdk-trace-base" "1.8.0" + "@opentelemetry/semantic-conventions" "1.8.0" + "@opentelemetry/semantic-conventions@1.7.0": version "1.7.0" resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.7.0.tgz#af80a1ef7cf110ea3a68242acd95648991bcd763" integrity sha512-FGBx/Qd09lMaqQcogCHyYrFEpTx4cAjeS+48lMIR12z7LdH+zofGDVQSubN59nL6IpubfKqTeIDu9rNO28iHVA== +"@opentelemetry/semantic-conventions@1.8.0", "@opentelemetry/semantic-conventions@^1.0.0", "@opentelemetry/semantic-conventions@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.8.0.tgz#fe2aa90e6df050a11cd57f5c0f47b0641fd2cad3" + integrity sha512-TYh1MRcm4JnvpqtqOwT9WYaBYY4KERHdToxs/suDTLviGRsQkIjS5yYROTYTSJQUnYLOn/TuOh5GoMwfLSU+Ew== + "@petamoriken/float16@^3.4.7": version "3.6.6" resolved "https://registry.yarnpkg.com/@petamoriken/float16/-/float16-3.6.6.tgz#641f73913a6be402b34e4bdfca98d6832ed55586" @@ -9360,6 +9546,11 @@ mobx@5.13.0: resolved "https://registry.yarnpkg.com/mobx/-/mobx-5.13.0.tgz#0fd68f10aa5ff2d146a4ed9e145b53337cfbca59" integrity sha512-eSAntMSMNj0PFL705rgv+aB/z1RjNqDnFEpBe18yQVreXTWiVgIrmBUXzjnJfuba+eo4eAk6zi+/gXQkSUea8A== +module-details-from-path@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/module-details-from-path/-/module-details-from-path-1.0.3.tgz#114c949673e2a8a35e9d35788527aa37b679da2b" + integrity sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A== + moment-timezone@0.5.35: version "0.5.35" resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.35.tgz#6fa2631bdbe8ff04f6b8753f7199516be6dc9839" @@ -11778,6 +11969,15 @@ require-from-string@^2.0.2: resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== +require-in-the-middle@^5.0.3: + version "5.2.0" + resolved "https://registry.yarnpkg.com/require-in-the-middle/-/require-in-the-middle-5.2.0.tgz#4b71e3cc7f59977100af9beb76bf2d056a5a6de2" + integrity sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg== + dependencies: + debug "^4.1.1" + module-details-from-path "^1.0.3" + resolve "^1.22.1" + requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -11835,7 +12035,7 @@ resolve.exports@^1.1.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== -resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.0: +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.22.1: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -12142,6 +12342,11 @@ shell-quote@^1.7.3: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.4.tgz#33fe15dee71ab2a81fcbd3a52106c5cfb9fb75d8" integrity sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw== +shimmer@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" + integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== + side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -13505,7 +13710,7 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" -web-vitals@^3.0.4: +web-vitals@^3.0.4, web-vitals@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-3.1.0.tgz#a6f5156cb6c7fee562da46078540265ac2cd2d16" integrity sha512-zCeQ+bOjWjJbXv5ZL0r8Py3XP2doCQMZXNKlBGfUjPAVZWokApdeF/kFlK1peuKlCt8sL9TFkKzyXE9/cmNJQA== @@ -13775,6 +13980,13 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== +zone.js@^0.11.0: + version "0.11.8" + resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.11.8.tgz#40dea9adc1ad007b5effb2bfed17f350f1f46a21" + integrity sha512-82bctBg2hKcEJ21humWIkXRlLBBmrc3nN7DFh5LGGhcyycO2S7FN8NmdvlcKaGFDNVL4/9kFLmwmInTavdJERA== + dependencies: + tslib "^2.3.0" + zwitch@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" From e0175fa2efc5ec899e83e116a72878e60b0bd193 Mon Sep 17 00:00:00 2001 From: Rares Mardare Date: Tue, 13 Dec 2022 15:28:30 +0200 Subject: [PATCH 02/19] working faro changes --- grafana-plugin/src/network/index.ts | 11 ++++++++ .../src/plugin/GrafanaPluginRootPage.tsx | 27 ++++++------------- grafana-plugin/src/state/plugin/index.ts | 1 - 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/grafana-plugin/src/network/index.ts b/grafana-plugin/src/network/index.ts index 18181bd9..6763e965 100644 --- a/grafana-plugin/src/network/index.ts +++ b/grafana-plugin/src/network/index.ts @@ -37,6 +37,17 @@ export const makeRequest = async (path: string, config: RequestConfig) const url = `${API_PROXY_PREFIX}${API_PATH_PREFIX}${path}`; + const response = await instance({ + method, + url, + params, + data, + validateStatus, + }); + + // for now just return response.data and figure OTEL later on + return response.data as RT; + const otel = faro.api.getOTEL(); if (otel) { diff --git a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx index 8b7e40f4..5530e3b3 100644 --- a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx +++ b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useMemo, useState } from 'react'; -import { initializeFaro, getWebInstrumentations, ReactIntegration, ReactRouterVersion } from '@grafana/faro-react'; +import { initializeFaro, getWebInstrumentations } from '@grafana/faro-react'; import { TracingInstrumentation } from '@grafana/faro-web-tracing'; import { locationService } from '@grafana/runtime'; import classnames from 'classnames'; @@ -10,7 +10,6 @@ import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'; import isoWeek from 'dayjs/plugin/isoWeek'; import localeData from 'dayjs/plugin/localeData'; import timezone from 'dayjs/plugin/timezone'; -import { Route, useHistory } from 'react-router'; import utc from 'dayjs/plugin/utc'; import weekday from 'dayjs/plugin/weekday'; @@ -64,7 +63,6 @@ export const Root = observer((props: AppRootProps) => { const pathWithoutLeadingSlash = path.replace(/^\//, ''); const store = useStore(); - const history = useHistory(); useEffect(() => { updateBasicData(); @@ -78,7 +76,7 @@ export const Root = observer((props: AppRootProps) => { document.head.appendChild(link); - initFaro(store, history); + initFaro(store); return () => { document.head.removeChild(link); @@ -129,30 +127,21 @@ export const Root = observer((props: AppRootProps) => { ); }); -function initFaro(store: RootBaseStore, history: any) { +function initFaro(store: RootBaseStore) { const faro = initializeFaro({ - url: `http://localhost:${''}/collect`, - apiKey: '', + url: `http://localhost:12345/collect`, + apiKey: 'secret', instrumentations: [ ...getWebInstrumentations({ captureConsole: true, }), new TracingInstrumentation(), - new ReactIntegration({ - router: { - version: ReactRouterVersion.V5, - dependencies: { - history, - Route, - }, - }, - }), ], session: (window as any).__PRELOADED_STATE__?.faro?.session, app: { - name: '', - version: '', - environment: '', + name: 'oncall', + version: '1.0.0', + environment: 'dev', }, }); diff --git a/grafana-plugin/src/state/plugin/index.ts b/grafana-plugin/src/state/plugin/index.ts index c0920900..aea010af 100644 --- a/grafana-plugin/src/state/plugin/index.ts +++ b/grafana-plugin/src/state/plugin/index.ts @@ -201,7 +201,6 @@ class PluginState { ): Promise => { try { const startSyncResponse = await makeRequest(`${this.ONCALL_BASE_URL}/sync`, { method: 'POST' }); - if (typeof startSyncResponse === 'string') { // an error occured trying to initiate the sync return startSyncResponse; From 7a6587bf02126c5eb129eea2fa45f5d14ece6206 Mon Sep 17 00:00:00 2001 From: Rares Mardare Date: Wed, 14 Dec 2022 13:53:09 +0200 Subject: [PATCH 03/19] removed store dependency, use global Faro object --- grafana-plugin/package.json | 3 +- grafana-plugin/src/network/index.ts | 23 ++---- .../src/plugin/GrafanaPluginRootPage.tsx | 75 +++++++++---------- .../src/state/rootBaseStore/index.ts | 4 - grafana-plugin/yarn.lock | 9 --- 5 files changed, 42 insertions(+), 72 deletions(-) diff --git a/grafana-plugin/package.json b/grafana-plugin/package.json index 7b150730..22443f27 100644 --- a/grafana-plugin/package.json +++ b/grafana-plugin/package.json @@ -104,9 +104,8 @@ "node": ">=14" }, "dependencies": { - "@grafana/faro-core": "^1.0.0-beta3", - "@grafana/faro-react": "^1.0.0-beta3", "@grafana/faro-web-sdk": "^1.0.0-beta3", + "@grafana/faro-web-tracing": "^1.0.0-beta3", "@opentelemetry/api": "^1.3.0", "array-move": "^4.0.0", "change-case": "^4.1.1", diff --git a/grafana-plugin/src/network/index.ts b/grafana-plugin/src/network/index.ts index 6763e965..cf9f37af 100644 --- a/grafana-plugin/src/network/index.ts +++ b/grafana-plugin/src/network/index.ts @@ -1,4 +1,4 @@ -import { faro } from '@grafana/faro-react'; +import { faro } from '@grafana/faro-web-sdk'; import { SpanStatusCode } from '@opentelemetry/api'; import axios from 'axios'; import qs from 'query-string'; @@ -37,18 +37,7 @@ export const makeRequest = async (path: string, config: RequestConfig) const url = `${API_PROXY_PREFIX}${API_PATH_PREFIX}${path}`; - const response = await instance({ - method, - url, - params, - data, - validateStatus, - }); - - // for now just return response.data and figure OTEL later on - return response.data as RT; - - const otel = faro.api.getOTEL(); + const otel = faro?.api?.getOTEL(); if (otel) { const tracer = otel.trace.getTracer('default'); @@ -92,12 +81,12 @@ export const makeRequest = async (path: string, config: RequestConfig) validateStatus, }); - faro.api.pushEvent('Request completed', { url }); + faro?.api?.pushEvent('Request completed', { url }); return response.data as RT; } catch (ex) { - faro.api.pushEvent('Request failed', { url }); - faro.api.pushError(ex); - throw ex; + faro?.api?.pushEvent('Request failed', { url }); + faro?.api?.pushError(ex); + return undefined; } }; diff --git a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx index 5530e3b3..cd9753aa 100644 --- a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx +++ b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useMemo, useState } from 'react'; -import { initializeFaro, getWebInstrumentations } from '@grafana/faro-react'; -import { TracingInstrumentation } from '@grafana/faro-web-tracing'; +import { initializeFaro, getWebInstrumentations } from '@grafana/faro-web-sdk'; +import { TracingInstrumentation, getDefaultOTELInstrumentations } from '@grafana/faro-web-tracing'; import { locationService } from '@grafana/runtime'; import classnames from 'classnames'; import dayjs from 'dayjs'; @@ -10,12 +10,13 @@ import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'; import isoWeek from 'dayjs/plugin/isoWeek'; import localeData from 'dayjs/plugin/localeData'; import timezone from 'dayjs/plugin/timezone'; - import utc from 'dayjs/plugin/utc'; import weekday from 'dayjs/plugin/weekday'; import { observer, Provider } from 'mobx-react'; import Header from 'navbar/Header/Header'; import LegacyNavTabsBar from 'navbar/LegacyNavTabsBar'; + +import plugin from '../../package.json'; // eslint-disable-line import { AppRootProps } from 'types'; import Unauthorized from 'components/Unauthorized'; @@ -28,8 +29,6 @@ import { useStore } from 'state/useStore'; import { isUserActionAllowed } from 'utils/authorization'; import { useQueryParams, useQueryPath } from 'utils/hooks'; -import { FaroErrorBoundary } from '@grafana/faro-react'; - dayjs.extend(utc); dayjs.extend(timezone); dayjs.extend(weekday); @@ -45,8 +44,6 @@ import 'style/utils.css'; import { getQueryParams, isTopNavbar } from './GrafanaPluginRootPage.helpers'; import PluginSetup from './PluginSetup'; -import { RootBaseStore } from 'state/rootBaseStore'; - export const GrafanaPluginRootPage = (props: AppRootProps) => ( @@ -76,7 +73,7 @@ export const Root = observer((props: AppRootProps) => { document.head.appendChild(link); - initFaro(store); + initFaro(); return () => { document.head.removeChild(link); @@ -98,36 +95,34 @@ export const Root = observer((props: AppRootProps) => { const userHasAccess = pagePermissionAction ? isUserActionAllowed(pagePermissionAction) : true; return ( - - - {!isTopNavbar() && ( - <> -
- - - )} + + {!isTopNavbar() && ( + <> +
+ + + )} -
- {userHasAccess ? ( - - ) : ( - - )} -
- - +
+ {userHasAccess ? ( + + ) : ( + + )} +
+ ); }); -function initFaro(store: RootBaseStore) { +function initFaro() { const faro = initializeFaro({ url: `http://localhost:12345/collect`, apiKey: 'secret', @@ -135,19 +130,19 @@ function initFaro(store: RootBaseStore) { ...getWebInstrumentations({ captureConsole: true, }), - new TracingInstrumentation(), + new TracingInstrumentation({ + instrumentations: [...getDefaultOTELInstrumentations([/^((?!\/{0,1}a\/grafana\-oncall\-app\\).)*$/])], + }), ], session: (window as any).__PRELOADED_STATE__?.faro?.session, app: { - name: 'oncall', - version: '1.0.0', - environment: 'dev', + name: plugin?.name || 'Grafana OnCall', + version: plugin?.version || '1.0.0', + // environment: 'dev', // TODO: sort this out }, }); faro.api.pushLog(['Faro was initialized for Grafana On Call']); - - store.faro = faro; } function getPageMatchingComponent(pageId: string): (props?: any) => JSX.Element { diff --git a/grafana-plugin/src/state/rootBaseStore/index.ts b/grafana-plugin/src/state/rootBaseStore/index.ts index d30d13dd..6b069ca7 100644 --- a/grafana-plugin/src/state/rootBaseStore/index.ts +++ b/grafana-plugin/src/state/rootBaseStore/index.ts @@ -1,4 +1,3 @@ -import { Faro } from '@grafana/faro-core'; import { action, observable } from 'mobx'; import moment from 'moment-timezone'; import qs from 'query-string'; @@ -73,9 +72,6 @@ export class RootBaseStore { @observable onCallApiUrl: string; - @observable - faro: Faro = undefined; - // -------------------------- userStore: UserStore = new UserStore(this); diff --git a/grafana-plugin/yarn.lock b/grafana-plugin/yarn.lock index 8b6b11ab..3a44bb62 100644 --- a/grafana-plugin/yarn.lock +++ b/grafana-plugin/yarn.lock @@ -1614,15 +1614,6 @@ "@opentelemetry/otlp-transformer" "^0.34.0" fast-deep-equal "^3.1.3" -"@grafana/faro-react@^1.0.0-beta3": - version "1.0.0-beta3" - resolved "https://registry.yarnpkg.com/@grafana/faro-react/-/faro-react-1.0.0-beta3.tgz#f28ba2fba136cd6d0417f6894218f359a5cdc88e" - integrity sha512-E8aI8FPqzs9NgOa3ApfeCNtmhakgMgfg1xu0snNz7Gt0KHssoHyIYrOHlI/C45BhkSXRMetIvhJv/YQkE9Ua7Q== - dependencies: - "@grafana/faro-web-sdk" "^1.0.0-beta3" - "@grafana/faro-web-tracing" "^1.0.0-beta3" - hoist-non-react-statics "^3.3.2" - "@grafana/faro-web-sdk@1.0.0-beta2": version "1.0.0-beta2" resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-1.0.0-beta2.tgz#d096a350d6366a108428a205753c797802eb480d" From cc37596141a020214f96bdc1c386c1c9d8723dc9 Mon Sep 17 00:00:00 2001 From: Rares Mardare Date: Wed, 14 Dec 2022 17:22:19 +0200 Subject: [PATCH 04/19] isolate faro, use singleton and rely on config file instead --- grafana-plugin/package.json | 6 +++ grafana-plugin/src/network/index.ts | 22 +++++------ .../src/plugin/GrafanaPluginRootPage.tsx | 30 +-------------- grafana-plugin/src/utils/faro.ts | 38 +++++++++++++++++++ 4 files changed, 57 insertions(+), 39 deletions(-) create mode 100644 grafana-plugin/src/utils/faro.ts diff --git a/grafana-plugin/package.json b/grafana-plugin/package.json index 22443f27..09152ffa 100644 --- a/grafana-plugin/package.json +++ b/grafana-plugin/package.json @@ -20,6 +20,11 @@ "plop": "plop", "setversion": "setversion" }, + "faro": { + "url": "http://localhost:12345/collect", + "apiKey": "secret", + "enabled": true + }, "repository": { "type": "git", "url": "git+https://github.com/grafana/oncall.git" @@ -104,6 +109,7 @@ "node": ">=14" }, "dependencies": { + "@grafana/faro-core": "^1.0.0-beta3", "@grafana/faro-web-sdk": "^1.0.0-beta3", "@grafana/faro-web-tracing": "^1.0.0-beta3", "@opentelemetry/api": "^1.3.0", diff --git a/grafana-plugin/src/network/index.ts b/grafana-plugin/src/network/index.ts index cf9f37af..1e2c5025 100644 --- a/grafana-plugin/src/network/index.ts +++ b/grafana-plugin/src/network/index.ts @@ -1,8 +1,9 @@ -import { faro } from '@grafana/faro-web-sdk'; import { SpanStatusCode } from '@opentelemetry/api'; import axios from 'axios'; import qs from 'query-string'; +import FaroHelper from 'utils/faro'; + export const API_HOST = `${window.location.protocol}//${window.location.host}/`; export const API_PROXY_PREFIX = 'api/plugin-proxy/grafana-oncall-app'; export const API_PATH_PREFIX = '/api/internal/v1'; @@ -36,16 +37,15 @@ export const makeRequest = async (path: string, config: RequestConfig) const { method = 'GET', params, data, validateStatus } = config; const url = `${API_PROXY_PREFIX}${API_PATH_PREFIX}${path}`; + const otel = FaroHelper.faro?.api?.getOTEL(); - const otel = faro?.api?.getOTEL(); - - if (otel) { + if (FaroHelper.faro && otel) { const tracer = otel.trace.getTracer('default'); let span = otel.trace.getActiveSpan() ?? tracer.startSpan('http-request'); return new Promise((resolve, reject) => { otel.context.with(otel.trace.setSpan(otel.context.active(), span), async () => { - faro.api.pushEvent('Sending request', { url }); + FaroHelper.faro.api.pushEvent('Sending request', { url }); try { const response = await instance({ @@ -56,12 +56,12 @@ export const makeRequest = async (path: string, config: RequestConfig) validateStatus, }); - faro.api.pushEvent('Request completed', { url }); + FaroHelper.faro.api.pushEvent('Request completed', { url }); resolve(response.data as RT); } catch (ex) { - faro.api.pushEvent('Request failed', { url }); - faro.api.pushError(ex); + FaroHelper.faro.api.pushEvent('Request failed', { url }); + FaroHelper.faro.api.pushError(ex); span.setStatus({ code: SpanStatusCode.ERROR }); reject(ex); @@ -81,12 +81,12 @@ export const makeRequest = async (path: string, config: RequestConfig) validateStatus, }); - faro?.api?.pushEvent('Request completed', { url }); + FaroHelper.faro?.api.pushEvent('Request completed', { url }); return response.data as RT; } catch (ex) { - faro?.api?.pushEvent('Request failed', { url }); - faro?.api?.pushError(ex); + FaroHelper.faro?.api.pushEvent('Request failed', { url }); + FaroHelper.faro?.api.pushError(ex); return undefined; } }; diff --git a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx index cd9753aa..4bf791cd 100644 --- a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx +++ b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx @@ -1,7 +1,5 @@ import React, { useEffect, useMemo, useState } from 'react'; -import { initializeFaro, getWebInstrumentations } from '@grafana/faro-web-sdk'; -import { TracingInstrumentation, getDefaultOTELInstrumentations } from '@grafana/faro-web-tracing'; import { locationService } from '@grafana/runtime'; import classnames from 'classnames'; import dayjs from 'dayjs'; @@ -15,8 +13,6 @@ import weekday from 'dayjs/plugin/weekday'; import { observer, Provider } from 'mobx-react'; import Header from 'navbar/Header/Header'; import LegacyNavTabsBar from 'navbar/LegacyNavTabsBar'; - -import plugin from '../../package.json'; // eslint-disable-line import { AppRootProps } from 'types'; import Unauthorized from 'components/Unauthorized'; @@ -27,6 +23,7 @@ import { routes } from 'pages/routes'; import { rootStore } from 'state'; import { useStore } from 'state/useStore'; import { isUserActionAllowed } from 'utils/authorization'; +import FaroHelper from 'utils/faro'; import { useQueryParams, useQueryPath } from 'utils/hooks'; dayjs.extend(utc); @@ -73,7 +70,7 @@ export const Root = observer((props: AppRootProps) => { document.head.appendChild(link); - initFaro(); + FaroHelper.initializeFaro(); return () => { document.head.removeChild(link); @@ -122,29 +119,6 @@ export const Root = observer((props: AppRootProps) => { ); }); -function initFaro() { - const faro = initializeFaro({ - url: `http://localhost:12345/collect`, - apiKey: 'secret', - instrumentations: [ - ...getWebInstrumentations({ - captureConsole: true, - }), - new TracingInstrumentation({ - instrumentations: [...getDefaultOTELInstrumentations([/^((?!\/{0,1}a\/grafana\-oncall\-app\\).)*$/])], - }), - ], - session: (window as any).__PRELOADED_STATE__?.faro?.session, - app: { - name: plugin?.name || 'Grafana OnCall', - version: plugin?.version || '1.0.0', - // environment: 'dev', // TODO: sort this out - }, - }); - - faro.api.pushLog(['Faro was initialized for Grafana On Call']); -} - function getPageMatchingComponent(pageId: string): (props?: any) => JSX.Element { let matchingPage = routes[pageId]; if (!matchingPage) { diff --git a/grafana-plugin/src/utils/faro.ts b/grafana-plugin/src/utils/faro.ts new file mode 100644 index 00000000..2e3ca258 --- /dev/null +++ b/grafana-plugin/src/utils/faro.ts @@ -0,0 +1,38 @@ +import { Faro } from '@grafana/faro-core'; +import { initializeFaro, getWebInstrumentations } from '@grafana/faro-web-sdk'; +import { TracingInstrumentation, getDefaultOTELInstrumentations } from '@grafana/faro-web-tracing'; + +import plugin from '../../package.json'; // eslint-disable-line + +class FaroHelper { + public faro: Faro; + + public initializeFaro() { + const { faro: faroConfig } = plugin as any; + + if (!faroConfig.enabled || this.faro) return; + + const faroInstance = initializeFaro({ + url: faroConfig.url, + apiKey: faroConfig.apiKey, + isolate: true, + instrumentations: [ + ...getWebInstrumentations({ + captureConsole: true, + }), + new TracingInstrumentation({ + instrumentations: [...getDefaultOTELInstrumentations([/^((?!\/{0,1}a\/grafana\-oncall\-app\\).)*$/])], + }), + ], + session: (window as any).__PRELOADED_STATE__?.faro?.session, + app: { + name: 'Grafana OnCall', + version: plugin?.version, + }, + }); + + faroInstance.api.pushLog(['Faro was initialized for Grafana OnCall']); + } +} + +export default new FaroHelper(); From 6253cc887835476c503451b3515ff84c888e8237 Mon Sep 17 00:00:00 2001 From: Rares Mardare Date: Thu, 15 Dec 2022 17:47:30 +0200 Subject: [PATCH 05/19] added dotenv to read env variables, pass faro instance to this.faro --- grafana-plugin/.eslintrc.js | 1 + grafana-plugin/package.json | 2 ++ grafana-plugin/src/utils/faro.ts | 48 +++++++++++++++++--------------- grafana-plugin/webpack.config.js | 6 ++++ grafana-plugin/yarn.lock | 14 ++++++++++ 5 files changed, 49 insertions(+), 22 deletions(-) diff --git a/grafana-plugin/.eslintrc.js b/grafana-plugin/.eslintrc.js index a25b9cf3..9a8d2b07 100644 --- a/grafana-plugin/.eslintrc.js +++ b/grafana-plugin/.eslintrc.js @@ -64,5 +64,6 @@ module.exports = { */ 'react-hooks/exhaustive-deps': 'off', 'rulesdir/no-relative-import-paths': ['error', { allowSameFolder: true }], + '@typescript-eslint/explicit-member-accessibility': 'off', }, }; diff --git a/grafana-plugin/package.json b/grafana-plugin/package.json index 09152ffa..d9f5f62f 100644 --- a/grafana-plugin/package.json +++ b/grafana-plugin/package.json @@ -61,6 +61,7 @@ "@babel/preset-typescript": "^7.18.6", "@grafana/data": "^9.2.4", "@grafana/eslint-config": "^5.0.0", + "@grafana/faro-react": "^1.0.0-beta3", "@grafana/runtime": "9.3.0-beta1", "@grafana/toolkit": "^9.2.4", "@grafana/ui": "^9.2.4", @@ -83,6 +84,7 @@ "babel-plugin-dynamic-import-node": "^2.3.3", "copy-webpack-plugin": "^11.0.0", "dompurify": "^2.3.12", + "dotenv": "^16.0.3", "eslint": "^8.25.0", "eslint-plugin-jsdoc": "^39.3.14", "eslint-plugin-react": "^7.31.10", diff --git a/grafana-plugin/src/utils/faro.ts b/grafana-plugin/src/utils/faro.ts index 2e3ca258..a6b4f997 100644 --- a/grafana-plugin/src/utils/faro.ts +++ b/grafana-plugin/src/utils/faro.ts @@ -5,33 +5,37 @@ import { TracingInstrumentation, getDefaultOTELInstrumentations } from '@grafana import plugin from '../../package.json'; // eslint-disable-line class FaroHelper { - public faro: Faro; + faro: Faro; - public initializeFaro() { + initializeFaro() { const { faro: faroConfig } = plugin as any; - if (!faroConfig.enabled || this.faro) return; + if (!faroConfig.enabled || this.faro) { + return; + } - const faroInstance = initializeFaro({ - url: faroConfig.url, - apiKey: faroConfig.apiKey, - isolate: true, - instrumentations: [ - ...getWebInstrumentations({ - captureConsole: true, - }), - new TracingInstrumentation({ - instrumentations: [...getDefaultOTELInstrumentations([/^((?!\/{0,1}a\/grafana\-oncall\-app\\).)*$/])], - }), - ], - session: (window as any).__PRELOADED_STATE__?.faro?.session, - app: { - name: 'Grafana OnCall', - version: plugin?.version, - }, - }); + try { + this.faro = initializeFaro({ + url: faroConfig.url, + apiKey: faroConfig.apiKey, + isolate: true, + instrumentations: [ + ...getWebInstrumentations({ + captureConsole: true, + }), + new TracingInstrumentation({ + instrumentations: [...getDefaultOTELInstrumentations([/^((?!\/{0,1}a\/grafana\-oncall\-app\\).)*$/])], + }), + ], + session: (window as any).__PRELOADED_STATE__?.faro?.session, + app: { + name: 'Grafana OnCall', + version: plugin?.version, + }, + }); - faroInstance.api.pushLog(['Faro was initialized for Grafana OnCall']); + this.faro.api.pushLog(['Faro was initialized for Grafana OnCall']); + } catch (ex) {} } } diff --git a/grafana-plugin/webpack.config.js b/grafana-plugin/webpack.config.js index b733cbb3..fddc69a5 100644 --- a/grafana-plugin/webpack.config.js +++ b/grafana-plugin/webpack.config.js @@ -1,5 +1,6 @@ const webpack = require('webpack'); const path = require('path'); +const dotenv = require('dotenv'); const CircularDependencyPlugin = require('circular-dependency-plugin'); @@ -9,6 +10,8 @@ Object.defineProperty(RegExp.prototype, 'toJSON', { value: RegExp.prototype.toString, }); +dotenv.config({ path: path.resolve(__dirname, '.env') }); + module.exports.getWebpackConfig = (config, options) => { const cssLoader = config.module.rules.find((rule) => rule.test.toString() === '/\\.css$/'); @@ -143,6 +146,9 @@ module.exports.getWebpackConfig = (config, options) => { new webpack.EnvironmentPlugin({ ONCALL_API_URL: null, }), + new webpack.DefinePlugin({ + 'process.env': JSON.stringify(dotenv.config().parsed), + }), ], resolve: { diff --git a/grafana-plugin/yarn.lock b/grafana-plugin/yarn.lock index 3a44bb62..bc444e77 100644 --- a/grafana-plugin/yarn.lock +++ b/grafana-plugin/yarn.lock @@ -1614,6 +1614,15 @@ "@opentelemetry/otlp-transformer" "^0.34.0" fast-deep-equal "^3.1.3" +"@grafana/faro-react@^1.0.0-beta3": + version "1.0.0-beta3" + resolved "https://registry.yarnpkg.com/@grafana/faro-react/-/faro-react-1.0.0-beta3.tgz#f28ba2fba136cd6d0417f6894218f359a5cdc88e" + integrity sha512-E8aI8FPqzs9NgOa3ApfeCNtmhakgMgfg1xu0snNz7Gt0KHssoHyIYrOHlI/C45BhkSXRMetIvhJv/YQkE9Ua7Q== + dependencies: + "@grafana/faro-web-sdk" "^1.0.0-beta3" + "@grafana/faro-web-tracing" "^1.0.0-beta3" + hoist-non-react-statics "^3.3.2" + "@grafana/faro-web-sdk@1.0.0-beta2": version "1.0.0-beta2" resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-1.0.0-beta2.tgz#d096a350d6366a108428a205753c797802eb480d" @@ -6089,6 +6098,11 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" +dotenv@^16.0.3: + version "16.0.3" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07" + integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ== + duplexer@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" From 93ee675c3804f9cf891fb014e927304d5eae2176 Mon Sep 17 00:00:00 2001 From: Rares Mardare Date: Fri, 16 Dec 2022 16:04:02 +0200 Subject: [PATCH 06/19] more faro changes --- grafana-plugin/package.json | 7 ++- grafana-plugin/src/network/index.ts | 10 +++- .../src/plugin/GrafanaPluginRootPage.tsx | 3 -- grafana-plugin/src/state/plugin/index.ts | 5 ++ grafana-plugin/src/utils/faro.ts | 15 +++++- grafana-plugin/webpack.config.js | 7 +++ grafana-plugin/yarn.lock | 48 ++++++++----------- 7 files changed, 56 insertions(+), 39 deletions(-) diff --git a/grafana-plugin/package.json b/grafana-plugin/package.json index d9f5f62f..3bbfb033 100644 --- a/grafana-plugin/package.json +++ b/grafana-plugin/package.json @@ -61,7 +61,9 @@ "@babel/preset-typescript": "^7.18.6", "@grafana/data": "^9.2.4", "@grafana/eslint-config": "^5.0.0", - "@grafana/faro-react": "^1.0.0-beta3", + "@grafana/faro-core": "1.0.0-beta4", + "@grafana/faro-web-sdk": "1.0.0-beta4", + "@grafana/faro-web-tracing": "1.0.0-beta4", "@grafana/runtime": "9.3.0-beta1", "@grafana/toolkit": "^9.2.4", "@grafana/ui": "^9.2.4", @@ -111,9 +113,6 @@ "node": ">=14" }, "dependencies": { - "@grafana/faro-core": "^1.0.0-beta3", - "@grafana/faro-web-sdk": "^1.0.0-beta3", - "@grafana/faro-web-tracing": "^1.0.0-beta3", "@opentelemetry/api": "^1.3.0", "array-move": "^4.0.0", "change-case": "^4.1.1", diff --git a/grafana-plugin/src/network/index.ts b/grafana-plugin/src/network/index.ts index 1e2c5025..a73950a3 100644 --- a/grafana-plugin/src/network/index.ts +++ b/grafana-plugin/src/network/index.ts @@ -1,4 +1,5 @@ import { SpanStatusCode } from '@opentelemetry/api'; +import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; import axios from 'axios'; import qs from 'query-string'; @@ -41,7 +42,14 @@ export const makeRequest = async (path: string, config: RequestConfig) if (FaroHelper.faro && otel) { const tracer = otel.trace.getTracer('default'); - let span = otel.trace.getActiveSpan() ?? tracer.startSpan('http-request'); + let span = otel.trace.getActiveSpan(); + + if (!span) { + span = tracer.startSpan('http-request'); + span.setAttribute('page_url', document.URL.split('//')[1]); + span.setAttribute(SemanticAttributes.HTTP_URL, url); + span.setAttribute(SemanticAttributes.HTTP_METHOD, method); + } return new Promise((resolve, reject) => { otel.context.with(otel.trace.setSpan(otel.context.active(), span), async () => { diff --git a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx index 4bf791cd..3eaa6d5d 100644 --- a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx +++ b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx @@ -23,7 +23,6 @@ import { routes } from 'pages/routes'; import { rootStore } from 'state'; import { useStore } from 'state/useStore'; import { isUserActionAllowed } from 'utils/authorization'; -import FaroHelper from 'utils/faro'; import { useQueryParams, useQueryPath } from 'utils/hooks'; dayjs.extend(utc); @@ -70,8 +69,6 @@ export const Root = observer((props: AppRootProps) => { document.head.appendChild(link); - FaroHelper.initializeFaro(); - return () => { document.head.removeChild(link); }; diff --git a/grafana-plugin/src/state/plugin/index.ts b/grafana-plugin/src/state/plugin/index.ts index aea010af..55326cd0 100644 --- a/grafana-plugin/src/state/plugin/index.ts +++ b/grafana-plugin/src/state/plugin/index.ts @@ -3,6 +3,7 @@ import axios from 'axios'; import { OnCallAppPluginMeta, OnCallPluginMetaJSONData, OnCallPluginMetaSecureJSONData } from 'types'; import { makeRequest } from 'network'; +import FaroHelper from 'utils/faro'; export type UpdateGrafanaPluginSettingsProps = { jsonData?: Partial; @@ -206,6 +207,10 @@ class PluginState { return startSyncResponse; } + if (!FaroHelper.faro) { + FaroHelper.initializeFaro(); + } + return await this.pollOnCallDataSyncStatus(onCallApiUrl, onCallApiUrlIsConfiguredThroughEnvVar); } catch (e) { return this.getHumanReadableErrorFromOnCallError(e, onCallApiUrl, 'sync', onCallApiUrlIsConfiguredThroughEnvVar); diff --git a/grafana-plugin/src/utils/faro.ts b/grafana-plugin/src/utils/faro.ts index a6b4f997..f1e98484 100644 --- a/grafana-plugin/src/utils/faro.ts +++ b/grafana-plugin/src/utils/faro.ts @@ -1,9 +1,15 @@ import { Faro } from '@grafana/faro-core'; import { initializeFaro, getWebInstrumentations } from '@grafana/faro-web-sdk'; -import { TracingInstrumentation, getDefaultOTELInstrumentations } from '@grafana/faro-web-tracing'; +import { TracingInstrumentation } from '@grafana/faro-web-tracing'; +import { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load'; +import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch'; +import { UserInteractionInstrumentation } from '@opentelemetry/instrumentation-user-interaction'; +import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request'; import plugin from '../../package.json'; // eslint-disable-line +const IGNORE_URLS = [/^((?!\/{0,1}a\/grafana\-oncall\-app\\).)*$/]; + class FaroHelper { faro: Faro; @@ -24,7 +30,12 @@ class FaroHelper { captureConsole: true, }), new TracingInstrumentation({ - instrumentations: [...getDefaultOTELInstrumentations([/^((?!\/{0,1}a\/grafana\-oncall\-app\\).)*$/])], + instrumentations: [ + new DocumentLoadInstrumentation(), + new FetchInstrumentation({ ignoreUrls: IGNORE_URLS }), + new XMLHttpRequestInstrumentation({}), + new UserInteractionInstrumentation(), + ], }), ], session: (window as any).__PRELOADED_STATE__?.faro?.session, diff --git a/grafana-plugin/webpack.config.js b/grafana-plugin/webpack.config.js index fddc69a5..17763bf9 100644 --- a/grafana-plugin/webpack.config.js +++ b/grafana-plugin/webpack.config.js @@ -120,6 +120,13 @@ module.exports.getWebpackConfig = (config, options) => { 'sass-loader', ], }, + + { + test: /\.m?js/, + resolve: { + fullySpecified: false, + }, + }, ], }, diff --git a/grafana-plugin/yarn.lock b/grafana-plugin/yarn.lock index bc444e77..757e45e4 100644 --- a/grafana-plugin/yarn.lock +++ b/grafana-plugin/yarn.lock @@ -1594,6 +1594,15 @@ eslint-plugin-react-hooks "4.3.0" typescript "4.6.4" +"@grafana/faro-core@1.0.0-beta4", "@grafana/faro-core@^1.0.0-beta4": + version "1.0.0-beta4" + resolved "https://registry.yarnpkg.com/@grafana/faro-core/-/faro-core-1.0.0-beta4.tgz#2f38e18764c0a3c3f1af889d510a2896bcb742ab" + integrity sha512-tB7705aYCByw4CNWt3WNoV39+sZCudBMiStmiEKHzM17VRRLBjPcrMQTkVYu4zMkEAdWMuAdYhT3xjzHlQpXIA== + dependencies: + "@opentelemetry/api" "^1.3.0" + "@opentelemetry/api-metrics" "^0.33.0" + "@opentelemetry/otlp-transformer" "^0.34.0" + "@grafana/faro-core@^1.0.0-beta2": version "1.0.0-beta2" resolved "https://registry.yarnpkg.com/@grafana/faro-core/-/faro-core-1.0.0-beta2.tgz#97636677c1d687b0b238642a3978334652f263a5" @@ -1604,25 +1613,6 @@ "@opentelemetry/otlp-transformer" "^0.33.0" fast-deep-equal "^3.1.3" -"@grafana/faro-core@^1.0.0-beta3": - version "1.0.0-beta3" - resolved "https://registry.yarnpkg.com/@grafana/faro-core/-/faro-core-1.0.0-beta3.tgz#705f561790b6f1d8b65a0a3507a1955519d393f8" - integrity sha512-P+mp2CMIYovmFFLJx7fvds65m+u0NB9l6RI0kKEPQHiMoR7cnHhe/dK049mk8widK0Z5Vmz1QBaNWxn3jO52cg== - dependencies: - "@opentelemetry/api" "^1.3.0" - "@opentelemetry/api-metrics" "^0.33.0" - "@opentelemetry/otlp-transformer" "^0.34.0" - fast-deep-equal "^3.1.3" - -"@grafana/faro-react@^1.0.0-beta3": - version "1.0.0-beta3" - resolved "https://registry.yarnpkg.com/@grafana/faro-react/-/faro-react-1.0.0-beta3.tgz#f28ba2fba136cd6d0417f6894218f359a5cdc88e" - integrity sha512-E8aI8FPqzs9NgOa3ApfeCNtmhakgMgfg1xu0snNz7Gt0KHssoHyIYrOHlI/C45BhkSXRMetIvhJv/YQkE9Ua7Q== - dependencies: - "@grafana/faro-web-sdk" "^1.0.0-beta3" - "@grafana/faro-web-tracing" "^1.0.0-beta3" - hoist-non-react-statics "^3.3.2" - "@grafana/faro-web-sdk@1.0.0-beta2": version "1.0.0-beta2" resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-1.0.0-beta2.tgz#d096a350d6366a108428a205753c797802eb480d" @@ -1632,21 +1622,21 @@ ua-parser-js "^1.0.32" web-vitals "^3.0.4" -"@grafana/faro-web-sdk@^1.0.0-beta3": - version "1.0.0-beta3" - resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-1.0.0-beta3.tgz#b26e0a3888228d59555a36ae4dcda4d711d4102f" - integrity sha512-vtU53oPrDXt655ggkusvogrTpDHHBm5JO0MbYlrYqvJprUpGaTsEgnb6lDRpXht3Vy6nk9h0+q0tBzgryZtY/w== +"@grafana/faro-web-sdk@1.0.0-beta4", "@grafana/faro-web-sdk@^1.0.0-beta4": + version "1.0.0-beta4" + resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-1.0.0-beta4.tgz#de9ec9b1201b4f02e3746f31dc0e7a3f77df47b3" + integrity sha512-yEBprcLn+L4zy/qYwrTEoSRpdbiN29EnesHlonYP5rj+K1G9CU+Oa0BL7PyS1oTEYZ2xOOv/gGYjiyi3PX9PEg== dependencies: - "@grafana/faro-core" "^1.0.0-beta3" + "@grafana/faro-core" "^1.0.0-beta4" ua-parser-js "^1.0.32" web-vitals "^3.1.0" -"@grafana/faro-web-tracing@^1.0.0-beta3": - version "1.0.0-beta3" - resolved "https://registry.yarnpkg.com/@grafana/faro-web-tracing/-/faro-web-tracing-1.0.0-beta3.tgz#a2b760f0f6beb64417e8e5f54706ae7ac1ae63c7" - integrity sha512-PIa3M8NNn6lIwr1zaJ3BIr/TAAZcNGipcPs7TZGEFgNenrCHIKghW7o2v6VW+ttSRTc4zaymphy5zCoXy5Hvug== +"@grafana/faro-web-tracing@1.0.0-beta4": + version "1.0.0-beta4" + resolved "https://registry.yarnpkg.com/@grafana/faro-web-tracing/-/faro-web-tracing-1.0.0-beta4.tgz#c65ace7ccf0c00da901e5532ce83bb07e6713627" + integrity sha512-a+SM+Wm2uONUCtGVFjxrz1O+tHKaQy10YBcqPZZcPDpanf8YMbo1bdYv9mFICvzg4rrvB/OI7mRO0Unr4+zGMQ== dependencies: - "@grafana/faro-core" "^1.0.0-beta3" + "@grafana/faro-web-sdk" "^1.0.0-beta4" "@opentelemetry/api" "^1.3.0" "@opentelemetry/context-zone" "^1.8.0" "@opentelemetry/core" "^1.8.0" From f5be86e1d2f4d41ec4ea3bd8fab17b7ac7c73c50 Mon Sep 17 00:00:00 2001 From: Rares Mardare Date: Fri, 16 Dec 2022 19:49:30 +0200 Subject: [PATCH 07/19] a few more tweaks --- grafana-plugin/.env.example | 3 +++ grafana-plugin/package.json | 5 ----- grafana-plugin/src/utils/faro.ts | 15 +++++++++++++-- 3 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 grafana-plugin/.env.example diff --git a/grafana-plugin/.env.example b/grafana-plugin/.env.example new file mode 100644 index 00000000..7c145aa5 --- /dev/null +++ b/grafana-plugin/.env.example @@ -0,0 +1,3 @@ +FARO_URL=http://localhost:12345/collect +FARO_API_KEY=secret +FARO_ENABLED=true \ No newline at end of file diff --git a/grafana-plugin/package.json b/grafana-plugin/package.json index 3bbfb033..b0b9392b 100644 --- a/grafana-plugin/package.json +++ b/grafana-plugin/package.json @@ -20,11 +20,6 @@ "plop": "plop", "setversion": "setversion" }, - "faro": { - "url": "http://localhost:12345/collect", - "apiKey": "secret", - "enabled": true - }, "repository": { "type": "git", "url": "git+https://github.com/grafana/oncall.git" diff --git a/grafana-plugin/src/utils/faro.ts b/grafana-plugin/src/utils/faro.ts index f1e98484..93038d03 100644 --- a/grafana-plugin/src/utils/faro.ts +++ b/grafana-plugin/src/utils/faro.ts @@ -10,13 +10,24 @@ import plugin from '../../package.json'; // eslint-disable-line const IGNORE_URLS = [/^((?!\/{0,1}a\/grafana\-oncall\-app\\).)*$/]; +interface FaroConfig { + url: string; + apiKey: string; + enabled: boolean; +} + class FaroHelper { faro: Faro; initializeFaro() { - const { faro: faroConfig } = plugin as any; + const enabled = process.env['FARO_ENABLED'].toLowerCase(); + const faroConfig: FaroConfig = { + url: process.env['FARO_URL'], + apiKey: process.env['FARO_API_KEY'], + enabled: enabled === 'true', + }; - if (!faroConfig.enabled || this.faro) { + if (!faroConfig?.enabled || !faroConfig?.url || !faroConfig?.apiKey || this.faro) { return; } From fb164d3b019b81dbcd193aee0511356c6b2b6c00 Mon Sep 17 00:00:00 2001 From: Rares Mardare Date: Fri, 16 Dec 2022 19:51:08 +0200 Subject: [PATCH 08/19] npe guard --- grafana-plugin/src/utils/faro.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grafana-plugin/src/utils/faro.ts b/grafana-plugin/src/utils/faro.ts index 93038d03..277baa9d 100644 --- a/grafana-plugin/src/utils/faro.ts +++ b/grafana-plugin/src/utils/faro.ts @@ -20,7 +20,7 @@ class FaroHelper { faro: Faro; initializeFaro() { - const enabled = process.env['FARO_ENABLED'].toLowerCase(); + const enabled = process.env['FARO_ENABLED']?.toLowerCase(); const faroConfig: FaroConfig = { url: process.env['FARO_URL'], apiKey: process.env['FARO_API_KEY'], From d1f962bfbd00d928fe5416e7c7c1895db8258d8a Mon Sep 17 00:00:00 2001 From: teodosii Date: Mon, 19 Dec 2022 13:30:40 +0200 Subject: [PATCH 09/19] default to {} for process.env check --- grafana-plugin/src/utils/faro.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/grafana-plugin/src/utils/faro.ts b/grafana-plugin/src/utils/faro.ts index 277baa9d..34a13ba1 100644 --- a/grafana-plugin/src/utils/faro.ts +++ b/grafana-plugin/src/utils/faro.ts @@ -20,11 +20,11 @@ class FaroHelper { faro: Faro; initializeFaro() { - const enabled = process.env['FARO_ENABLED']?.toLowerCase(); + const faroInput = process.env || {}; const faroConfig: FaroConfig = { - url: process.env['FARO_URL'], - apiKey: process.env['FARO_API_KEY'], - enabled: enabled === 'true', + url: faroInput['FARO_URL'], + apiKey: faroInput['FARO_API_KEY'], + enabled: faroInput['FARO_ENABLED']?.toLowerCase() === 'true', }; if (!faroConfig?.enabled || !faroConfig?.url || !faroConfig?.apiKey || this.faro) { From 93553b177606d6dc7a864d4f48db964d15856389 Mon Sep 17 00:00:00 2001 From: teodosii Date: Mon, 19 Dec 2022 17:00:47 +0200 Subject: [PATCH 10/19] mock faro packages so tests can pass --- .../src/pages/outgoing_webhooks/OutgoingWebhooks.test.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/grafana-plugin/src/pages/outgoing_webhooks/OutgoingWebhooks.test.tsx b/grafana-plugin/src/pages/outgoing_webhooks/OutgoingWebhooks.test.tsx index dcfe429e..c016b0f6 100644 --- a/grafana-plugin/src/pages/outgoing_webhooks/OutgoingWebhooks.test.tsx +++ b/grafana-plugin/src/pages/outgoing_webhooks/OutgoingWebhooks.test.tsx @@ -20,6 +20,14 @@ const outgoingWebhookStore = () => ({ }, {}), }); +jest.mock('@grafana/faro-web-sdk', () => ({ + initializeFaro: jest.fn(), + TracingInstrumentation: undefined, +})); +jest.mock('@grafana/faro-web-tracing', () => ({ + TracingInstrumentation: undefined, +})); + jest.mock('plugin/GrafanaPluginRootPage.helpers', () => ({ isTopNavbar: () => false, })); From b7ac9e4a85a6060ef97d31cd6b8ea936e93ebcb8 Mon Sep 17 00:00:00 2001 From: teodosii Date: Tue, 20 Dec 2022 11:22:41 +0200 Subject: [PATCH 11/19] basic test for faro --- grafana-plugin/src/utils/faro.test.ts | 84 +++++++++++++++++++++++++++ grafana-plugin/src/utils/faro.ts | 4 +- 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 grafana-plugin/src/utils/faro.test.ts diff --git a/grafana-plugin/src/utils/faro.test.ts b/grafana-plugin/src/utils/faro.test.ts new file mode 100644 index 00000000..04bb93de --- /dev/null +++ b/grafana-plugin/src/utils/faro.test.ts @@ -0,0 +1,84 @@ +import FaroHelper from 'utils/faro'; + +import 'jest/matchMedia.ts'; + +import { describe, test } from '@jest/globals'; +import '@testing-library/jest-dom'; + +jest.mock('@grafana/faro-web-sdk', () => ({ + initializeFaro: jest.fn().mockReturnValue({ + api: { + pushLog: jest.fn(), + }, + }), + getWebInstrumentations: () => [], +})); + +jest.mock('@grafana/faro-web-tracing', () => ({ + TracingInstrumentation: jest.fn(), +})); +jest.mock('@opentelemetry/instrumentation-document-load', () => ({ + DocumentLoadInstrumentation: jest.fn(), +})); +jest.mock('@opentelemetry/instrumentation-fetch', () => ({ + FetchInstrumentation: jest.fn(), +})); + +describe('Faro', () => { + const OLD_ENV = process.env; + + beforeEach(() => { + jest.resetModules(); + process.env = { ...OLD_ENV }; + }); + + afterAll(() => { + process.env = OLD_ENV; + }); + + const getProcessEnv = ( + config: { faroUrl?: string; apiKey?: string; enabled?: string } = { + faroUrl: 'localhost:12345/collect', + apiKey: 'secret', + enabled: 'true', + } + ) => { + const { faroUrl, apiKey, enabled } = config; + + return { + FARO_URL: faroUrl, + FARO_API_KEY: apiKey, + FARO_ENABLED: enabled, + }; + }; + + test('It initializes faro ENABLED === true', () => { + process.env = getProcessEnv(); + const faro = FaroHelper.initializeFaro(); + + expect(faro).toBeDefined(); + expect(faro.api.pushLog).toHaveBeenCalledTimes(1); + }); + + test('It does not initialize faro if ENABLED != true', () => { + process.env = getProcessEnv({ enabled: 'some-other-value-here' }); + const faro = FaroHelper.initializeFaro(); + expect(faro).toBeUndefined(); + }); + + test('It skips initializing if values are missing', () => { + let faro; + + process.env = getProcessEnv({ faroUrl: undefined }); + faro = FaroHelper.initializeFaro(); + expect(faro).toBeUndefined(); + + process.env = getProcessEnv({ apiKey: undefined }); + faro = FaroHelper.initializeFaro(); + expect(faro).toBeUndefined(); + + process.env = getProcessEnv({ enabled: undefined }); + faro = FaroHelper.initializeFaro(); + expect(faro).toBeUndefined(); + }); +}); diff --git a/grafana-plugin/src/utils/faro.ts b/grafana-plugin/src/utils/faro.ts index 34a13ba1..7cec49c0 100644 --- a/grafana-plugin/src/utils/faro.ts +++ b/grafana-plugin/src/utils/faro.ts @@ -28,7 +28,7 @@ class FaroHelper { }; if (!faroConfig?.enabled || !faroConfig?.url || !faroConfig?.apiKey || this.faro) { - return; + return undefined; } try { @@ -58,6 +58,8 @@ class FaroHelper { this.faro.api.pushLog(['Faro was initialized for Grafana OnCall']); } catch (ex) {} + + return this.faro; } } From 2948b2f87d7c8b31533ce6bd41741d5ba460dbd5 Mon Sep 17 00:00:00 2001 From: teodosii Date: Tue, 20 Dec 2022 17:47:22 +0200 Subject: [PATCH 12/19] lint fix package --- grafana-plugin/package.json | 42 +++++++++++++-------------- grafana-plugin/src/utils/faro.test.ts | 6 ++-- grafana-plugin/yarn.lock | 12 ++++---- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/grafana-plugin/package.json b/grafana-plugin/package.json index b0b9392b..264c1abe 100644 --- a/grafana-plugin/package.json +++ b/grafana-plugin/package.json @@ -40,28 +40,7 @@ "author": "Grafana Labs", "license": "Apache-2.0", "devDependencies": { - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-decorators": "^7.20.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.18.9", - "@babel/plugin-proposal-optional-chaining": "^7.18.9", - "@babel/plugin-syntax-decorators": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-destructuring": "^7.20.0", - "@babel/plugin-transform-react-constant-elements": "^7.18.12", - "@babel/plugin-transform-runtime": "^7.19.6", - "@babel/plugin-transform-typescript": "^7.18.12", - "@babel/preset-env": "^7.18.10", - "@babel/preset-react": "^7.18.6", - "@babel/preset-typescript": "^7.18.6", - "@grafana/data": "^9.2.4", - "@grafana/eslint-config": "^5.0.0", - "@grafana/faro-core": "1.0.0-beta4", - "@grafana/faro-web-sdk": "1.0.0-beta4", - "@grafana/faro-web-tracing": "1.0.0-beta4", - "@grafana/runtime": "9.3.0-beta1", "@grafana/toolkit": "^9.2.4", - "@grafana/ui": "^9.2.4", "@jest/globals": "^27.5.1", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "12", @@ -108,6 +87,27 @@ "node": ">=14" }, "dependencies": { + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-decorators": "^7.20.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-syntax-decorators": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-destructuring": "^7.20.0", + "@babel/plugin-transform-react-constant-elements": "^7.18.12", + "@babel/plugin-transform-runtime": "^7.19.6", + "@babel/plugin-transform-typescript": "^7.18.12", + "@babel/preset-env": "^7.18.10", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "@grafana/data": "^9.2.4", + "@grafana/eslint-config": "^5.0.0", + "@grafana/faro-core": " ^1.0.0-beta4", + "@grafana/faro-web-sdk": "^1.0.0-beta4", + "@grafana/faro-web-tracing": "^1.0.0-beta4", + "@grafana/runtime": "9.3.0-beta1", + "@grafana/ui": "^9.2.4", "@opentelemetry/api": "^1.3.0", "array-move": "^4.0.0", "change-case": "^4.1.1", diff --git a/grafana-plugin/src/utils/faro.test.ts b/grafana-plugin/src/utils/faro.test.ts index 04bb93de..7a1b3fca 100644 --- a/grafana-plugin/src/utils/faro.test.ts +++ b/grafana-plugin/src/utils/faro.test.ts @@ -1,8 +1,8 @@ +import 'jest/matchMedia.ts'; +import { describe, test } from '@jest/globals'; + import FaroHelper from 'utils/faro'; -import 'jest/matchMedia.ts'; - -import { describe, test } from '@jest/globals'; import '@testing-library/jest-dom'; jest.mock('@grafana/faro-web-sdk', () => ({ diff --git a/grafana-plugin/yarn.lock b/grafana-plugin/yarn.lock index 894b36d8..e8eb8d4f 100644 --- a/grafana-plugin/yarn.lock +++ b/grafana-plugin/yarn.lock @@ -1594,7 +1594,7 @@ eslint-plugin-react-hooks "4.3.0" typescript "4.6.4" -"@grafana/faro-core@1.0.0-beta4", "@grafana/faro-core@^1.0.0-beta4": +"@grafana/faro-core@ ^1.0.0-beta4", "@grafana/faro-core@^1.0.0-beta4": version "1.0.0-beta4" resolved "https://registry.yarnpkg.com/@grafana/faro-core/-/faro-core-1.0.0-beta4.tgz#2f38e18764c0a3c3f1af889d510a2896bcb742ab" integrity sha512-tB7705aYCByw4CNWt3WNoV39+sZCudBMiStmiEKHzM17VRRLBjPcrMQTkVYu4zMkEAdWMuAdYhT3xjzHlQpXIA== @@ -1622,7 +1622,7 @@ ua-parser-js "^1.0.32" web-vitals "^3.0.4" -"@grafana/faro-web-sdk@1.0.0-beta4", "@grafana/faro-web-sdk@^1.0.0-beta4": +"@grafana/faro-web-sdk@^1.0.0-beta4": version "1.0.0-beta4" resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-1.0.0-beta4.tgz#de9ec9b1201b4f02e3746f31dc0e7a3f77df47b3" integrity sha512-yEBprcLn+L4zy/qYwrTEoSRpdbiN29EnesHlonYP5rj+K1G9CU+Oa0BL7PyS1oTEYZ2xOOv/gGYjiyi3PX9PEg== @@ -1631,10 +1631,10 @@ ua-parser-js "^1.0.32" web-vitals "^3.1.0" -"@grafana/faro-web-tracing@1.0.0-beta4": - version "1.0.0-beta4" - resolved "https://registry.yarnpkg.com/@grafana/faro-web-tracing/-/faro-web-tracing-1.0.0-beta4.tgz#c65ace7ccf0c00da901e5532ce83bb07e6713627" - integrity sha512-a+SM+Wm2uONUCtGVFjxrz1O+tHKaQy10YBcqPZZcPDpanf8YMbo1bdYv9mFICvzg4rrvB/OI7mRO0Unr4+zGMQ== +"@grafana/faro-web-tracing@^1.0.0-beta4": + version "1.0.0-beta5" + resolved "https://registry.yarnpkg.com/@grafana/faro-web-tracing/-/faro-web-tracing-1.0.0-beta5.tgz#855f2714131bbc6855f3b2fd81c7e1b0995fc922" + integrity sha512-wHTv5F1eKUzf46dFKJRi4KBXHC1VRALhtgWbR+IeiXZboJn7hvRF7lwvelJzX++RcnApycFdjLi3RVEpbinZOA== dependencies: "@grafana/faro-web-sdk" "^1.0.0-beta4" "@opentelemetry/api" "^1.3.0" From 6deede63859d651eb1e8cec8b29b0b46f3aa9775 Mon Sep 17 00:00:00 2001 From: teodosii Date: Wed, 21 Dec 2022 11:32:49 +0200 Subject: [PATCH 13/19] Concat environment next to 'Grafana OnCall' for differentiating environments --- grafana-plugin/.env.example | 1 + grafana-plugin/src/utils/faro.ts | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/grafana-plugin/.env.example b/grafana-plugin/.env.example index 7c145aa5..294236a1 100644 --- a/grafana-plugin/.env.example +++ b/grafana-plugin/.env.example @@ -1,3 +1,4 @@ FARO_URL=http://localhost:12345/collect +FARO_ENV=DEV FARO_API_KEY=secret FARO_ENABLED=true \ No newline at end of file diff --git a/grafana-plugin/src/utils/faro.ts b/grafana-plugin/src/utils/faro.ts index 7cec49c0..7bbf64ac 100644 --- a/grafana-plugin/src/utils/faro.ts +++ b/grafana-plugin/src/utils/faro.ts @@ -14,17 +14,22 @@ interface FaroConfig { url: string; apiKey: string; enabled: boolean; + environment: string; } +const ONCALL = 'Grafana OnCall'; + class FaroHelper { faro: Faro; initializeFaro() { const faroInput = process.env || {}; + const FARO_ENV = faroInput['FARO_ENV']; const faroConfig: FaroConfig = { url: faroInput['FARO_URL'], apiKey: faroInput['FARO_API_KEY'], enabled: faroInput['FARO_ENABLED']?.toLowerCase() === 'true', + environment: FARO_ENV ? `${ONCALL} ${FARO_ENV}` : ONCALL, }; if (!faroConfig?.enabled || !faroConfig?.url || !faroConfig?.apiKey || this.faro) { @@ -51,12 +56,12 @@ class FaroHelper { ], session: (window as any).__PRELOADED_STATE__?.faro?.session, app: { - name: 'Grafana OnCall', + name: faroConfig.environment, version: plugin?.version, }, }); - this.faro.api.pushLog(['Faro was initialized for Grafana OnCall']); + this.faro.api.pushLog([`Faro was initialized for ${faroConfig.environment}`]); } catch (ex) {} return this.faro; From d92ab4bca657cd907717cf473bb1ea8dd8c4d6f2 Mon Sep 17 00:00:00 2001 From: teodosii Date: Thu, 22 Dec 2022 00:02:11 +0200 Subject: [PATCH 14/19] make api key optional to follow appo11y config convention --- grafana-plugin/src/utils/faro.test.ts | 33 +++++++++++++++------------ grafana-plugin/src/utils/faro.ts | 12 +++++++--- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/grafana-plugin/src/utils/faro.test.ts b/grafana-plugin/src/utils/faro.test.ts index 7a1b3fca..6a3c0553 100644 --- a/grafana-plugin/src/utils/faro.test.ts +++ b/grafana-plugin/src/utils/faro.test.ts @@ -30,20 +30,23 @@ describe('Faro', () => { beforeEach(() => { jest.resetModules(); process.env = { ...OLD_ENV }; + FaroHelper.faro = undefined; + jest.clearAllMocks(); }); - afterAll(() => { - process.env = OLD_ENV; + const getDefaultValues = () => ({ + faroUrl: 'localhost:12345/collect', + apiKey: 'secret', + enabled: 'true', }); - const getProcessEnv = ( - config: { faroUrl?: string; apiKey?: string; enabled?: string } = { - faroUrl: 'localhost:12345/collect', - apiKey: 'secret', - enabled: 'true', - } - ) => { - const { faroUrl, apiKey, enabled } = config; + const getProcessEnv = (config: { faroUrl?: string; apiKey?: string; enabled?: string } = {}) => { + const configObject = { + ...getDefaultValues(), + ...config, + }; + + const { faroUrl, apiKey, enabled } = configObject; return { FARO_URL: faroUrl, @@ -52,6 +55,12 @@ describe('Faro', () => { }; }; + test('It initializes without api key', () => { + process.env = getProcessEnv({ apiKey: '' }); + const faro = FaroHelper.initializeFaro(); + expect(faro).toBeDefined(); + }); + test('It initializes faro ENABLED === true', () => { process.env = getProcessEnv(); const faro = FaroHelper.initializeFaro(); @@ -73,10 +82,6 @@ describe('Faro', () => { faro = FaroHelper.initializeFaro(); expect(faro).toBeUndefined(); - process.env = getProcessEnv({ apiKey: undefined }); - faro = FaroHelper.initializeFaro(); - expect(faro).toBeUndefined(); - process.env = getProcessEnv({ enabled: undefined }); faro = FaroHelper.initializeFaro(); expect(faro).toBeUndefined(); diff --git a/grafana-plugin/src/utils/faro.ts b/grafana-plugin/src/utils/faro.ts index 7bbf64ac..15d8883f 100644 --- a/grafana-plugin/src/utils/faro.ts +++ b/grafana-plugin/src/utils/faro.ts @@ -32,12 +32,12 @@ class FaroHelper { environment: FARO_ENV ? `${ONCALL} ${FARO_ENV}` : ONCALL, }; - if (!faroConfig?.enabled || !faroConfig?.url || !faroConfig?.apiKey || this.faro) { + if (!faroConfig?.enabled || !faroConfig?.url || this.faro) { return undefined; } try { - this.faro = initializeFaro({ + const faroOptions = { url: faroConfig.url, apiKey: faroConfig.apiKey, isolate: true, @@ -59,7 +59,13 @@ class FaroHelper { name: faroConfig.environment, version: plugin?.version, }, - }); + }; + + if (!faroConfig.apiKey) { + delete faroOptions.apiKey; // appo11y has the key in the API instead + } + + this.faro = initializeFaro(faroOptions); this.faro.api.pushLog([`Faro was initialized for ${faroConfig.environment}`]); } catch (ex) {} From 89f6f74490a7050a7d758a0300bf4c23a50cc6cd Mon Sep 17 00:00:00 2001 From: teodosii Date: Thu, 22 Dec 2022 00:34:25 +0200 Subject: [PATCH 15/19] enforce hyphen naming for app --- grafana-plugin/.env.example | 2 +- grafana-plugin/src/utils/faro.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/grafana-plugin/.env.example b/grafana-plugin/.env.example index 294236a1..cda4f504 100644 --- a/grafana-plugin/.env.example +++ b/grafana-plugin/.env.example @@ -1,4 +1,4 @@ FARO_URL=http://localhost:12345/collect -FARO_ENV=DEV +FARO_ENV=dev FARO_API_KEY=secret FARO_ENABLED=true \ No newline at end of file diff --git a/grafana-plugin/src/utils/faro.ts b/grafana-plugin/src/utils/faro.ts index 15d8883f..b3268a20 100644 --- a/grafana-plugin/src/utils/faro.ts +++ b/grafana-plugin/src/utils/faro.ts @@ -17,7 +17,7 @@ interface FaroConfig { environment: string; } -const ONCALL = 'Grafana OnCall'; +const ONCALL = 'grafana-oncall'; class FaroHelper { faro: Faro; @@ -29,7 +29,7 @@ class FaroHelper { url: faroInput['FARO_URL'], apiKey: faroInput['FARO_API_KEY'], enabled: faroInput['FARO_ENABLED']?.toLowerCase() === 'true', - environment: FARO_ENV ? `${ONCALL} ${FARO_ENV}` : ONCALL, + environment: FARO_ENV ? `${ONCALL}-${FARO_ENV}` : ONCALL, }; if (!faroConfig?.enabled || !faroConfig?.url || this.faro) { From f935803354fa9759a6d4ab0ce777a57902035267 Mon Sep 17 00:00:00 2001 From: teodosii Date: Thu, 22 Dec 2022 13:38:47 +0200 Subject: [PATCH 16/19] review reordered dependencies --- grafana-plugin/package.json | 28 +++++++++--------- grafana-plugin/src/network/index.ts | 45 ++++++++++++++--------------- grafana-plugin/webpack.config.js | 7 ----- 3 files changed, 35 insertions(+), 45 deletions(-) diff --git a/grafana-plugin/package.json b/grafana-plugin/package.json index 264c1abe..122584a4 100644 --- a/grafana-plugin/package.json +++ b/grafana-plugin/package.json @@ -40,6 +40,20 @@ "author": "Grafana Labs", "license": "Apache-2.0", "devDependencies": { + "@babel/preset-env": "^7.18.10", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-decorators": "^7.20.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-syntax-decorators": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-destructuring": "^7.20.0", + "@babel/plugin-transform-react-constant-elements": "^7.18.12", + "@babel/plugin-transform-runtime": "^7.19.6", + "@babel/plugin-transform-typescript": "^7.18.12", "@grafana/toolkit": "^9.2.4", "@jest/globals": "^27.5.1", "@testing-library/jest-dom": "^5.16.5", @@ -87,20 +101,6 @@ "node": ">=14" }, "dependencies": { - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-decorators": "^7.20.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.18.9", - "@babel/plugin-proposal-optional-chaining": "^7.18.9", - "@babel/plugin-syntax-decorators": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-destructuring": "^7.20.0", - "@babel/plugin-transform-react-constant-elements": "^7.18.12", - "@babel/plugin-transform-runtime": "^7.19.6", - "@babel/plugin-transform-typescript": "^7.18.12", - "@babel/preset-env": "^7.18.10", - "@babel/preset-react": "^7.18.6", - "@babel/preset-typescript": "^7.18.6", "@grafana/data": "^9.2.4", "@grafana/eslint-config": "^5.0.0", "@grafana/faro-core": " ^1.0.0-beta4", diff --git a/grafana-plugin/src/network/index.ts b/grafana-plugin/src/network/index.ts index a73950a3..29b9bb2e 100644 --- a/grafana-plugin/src/network/index.ts +++ b/grafana-plugin/src/network/index.ts @@ -51,36 +51,34 @@ export const makeRequest = async (path: string, config: RequestConfig) span.setAttribute(SemanticAttributes.HTTP_METHOD, method); } - return new Promise((resolve, reject) => { + try { + // OTEL requests otel.context.with(otel.trace.setSpan(otel.context.active(), span), async () => { FaroHelper.faro.api.pushEvent('Sending request', { url }); - try { - const response = await instance({ - method, - url, - params, - data, - validateStatus, - }); + const response = await instance({ + method, + url, + params, + data, + validateStatus, + }); - FaroHelper.faro.api.pushEvent('Request completed', { url }); - - resolve(response.data as RT); - } catch (ex) { - FaroHelper.faro.api.pushEvent('Request failed', { url }); - FaroHelper.faro.api.pushError(ex); - - span.setStatus({ code: SpanStatusCode.ERROR }); - reject(ex); - } finally { - span.end(); - } + FaroHelper.faro.api.pushEvent('Request completed', { url }); + return response.data as RT; }); - }); + } catch (ex) { + FaroHelper.faro.api.pushEvent('Request failed', { url }); + FaroHelper.faro.api.pushError(ex); + span.setStatus({ code: SpanStatusCode.ERROR }); + return Promise.reject(ex); + } finally { + span.end(); + } } try { + // non-OTEL requests const response = await instance({ method, url, @@ -90,11 +88,10 @@ export const makeRequest = async (path: string, config: RequestConfig) }); FaroHelper.faro?.api.pushEvent('Request completed', { url }); - return response.data as RT; } catch (ex) { FaroHelper.faro?.api.pushEvent('Request failed', { url }); FaroHelper.faro?.api.pushError(ex); - return undefined; + return Promise.reject(ex); } }; diff --git a/grafana-plugin/webpack.config.js b/grafana-plugin/webpack.config.js index 57310c57..4e895287 100644 --- a/grafana-plugin/webpack.config.js +++ b/grafana-plugin/webpack.config.js @@ -120,13 +120,6 @@ module.exports.getWebpackConfig = (config, options) => { 'sass-loader', ], }, - - { - test: /\.m?js/, - resolve: { - fullySpecified: false, - }, - }, ], }, From 3315e9dab1fe89ca991e56eed95a89261c455ddd Mon Sep 17 00:00:00 2001 From: teodosii Date: Thu, 22 Dec 2022 15:06:55 +0200 Subject: [PATCH 17/19] just promises? dev dependency type reuse from sdk package --- grafana-plugin/package.json | 9 ++-- grafana-plugin/src/network/index.ts | 64 ++++++++++++++--------------- grafana-plugin/src/utils/faro.ts | 3 +- grafana-plugin/yarn.lock | 18 ++++---- 4 files changed, 46 insertions(+), 48 deletions(-) diff --git a/grafana-plugin/package.json b/grafana-plugin/package.json index 122584a4..ee4efd6f 100644 --- a/grafana-plugin/package.json +++ b/grafana-plugin/package.json @@ -40,9 +40,6 @@ "author": "Grafana Labs", "license": "Apache-2.0", "devDependencies": { - "@babel/preset-env": "^7.18.10", - "@babel/preset-react": "^7.18.6", - "@babel/preset-typescript": "^7.18.6", "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-proposal-decorators": "^7.20.0", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", @@ -54,6 +51,10 @@ "@babel/plugin-transform-react-constant-elements": "^7.18.12", "@babel/plugin-transform-runtime": "^7.19.6", "@babel/plugin-transform-typescript": "^7.18.12", + "@babel/preset-env": "^7.18.10", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "@grafana/eslint-config": "^5.0.0", "@grafana/toolkit": "^9.2.4", "@jest/globals": "^27.5.1", "@testing-library/jest-dom": "^5.16.5", @@ -102,8 +103,6 @@ }, "dependencies": { "@grafana/data": "^9.2.4", - "@grafana/eslint-config": "^5.0.0", - "@grafana/faro-core": " ^1.0.0-beta4", "@grafana/faro-web-sdk": "^1.0.0-beta4", "@grafana/faro-web-tracing": "^1.0.0-beta4", "@grafana/runtime": "9.3.0-beta1", diff --git a/grafana-plugin/src/network/index.ts b/grafana-plugin/src/network/index.ts index 29b9bb2e..e9c1930e 100644 --- a/grafana-plugin/src/network/index.ts +++ b/grafana-plugin/src/network/index.ts @@ -51,47 +51,47 @@ export const makeRequest = async (path: string, config: RequestConfig) span.setAttribute(SemanticAttributes.HTTP_METHOD, method); } - try { - // OTEL requests + return new Promise((resolve, reject) => { otel.context.with(otel.trace.setSpan(otel.context.active(), span), async () => { FaroHelper.faro.api.pushEvent('Sending request', { url }); - const response = await instance({ + instance({ method, url, params, data, validateStatus, - }); - - FaroHelper.faro.api.pushEvent('Request completed', { url }); - return response.data as RT; + }) + .then((response) => { + FaroHelper.faro.api.pushEvent('Request completed', { url }); + span.end(); + resolve(response.data as RT); + }) + .catch((ex) => { + FaroHelper.faro.api.pushEvent('Request failed', { url }); + FaroHelper.faro.api.pushError(ex); + span.setStatus({ code: SpanStatusCode.ERROR }); + span.end(); + reject(ex); + }); }); - } catch (ex) { - FaroHelper.faro.api.pushEvent('Request failed', { url }); - FaroHelper.faro.api.pushError(ex); - span.setStatus({ code: SpanStatusCode.ERROR }); - return Promise.reject(ex); - } finally { - span.end(); - } - } - - try { - // non-OTEL requests - const response = await instance({ - method, - url, - params, - data, - validateStatus, }); - - FaroHelper.faro?.api.pushEvent('Request completed', { url }); - return response.data as RT; - } catch (ex) { - FaroHelper.faro?.api.pushEvent('Request failed', { url }); - FaroHelper.faro?.api.pushError(ex); - return Promise.reject(ex); } + + return instance({ + method, + url, + params, + data, + validateStatus, + }) + .then((response) => { + FaroHelper.faro?.api.pushEvent('Request completed', { url }); + return response.data as RT; + }) + .catch((ex) => { + FaroHelper.faro?.api.pushEvent('Request failed', { url }); + FaroHelper.faro?.api.pushError(ex); + return Promise.reject(ex); + }); }; diff --git a/grafana-plugin/src/utils/faro.ts b/grafana-plugin/src/utils/faro.ts index b3268a20..98ec7cc2 100644 --- a/grafana-plugin/src/utils/faro.ts +++ b/grafana-plugin/src/utils/faro.ts @@ -1,5 +1,4 @@ -import { Faro } from '@grafana/faro-core'; -import { initializeFaro, getWebInstrumentations } from '@grafana/faro-web-sdk'; +import { Faro, initializeFaro, getWebInstrumentations } from '@grafana/faro-web-sdk'; import { TracingInstrumentation } from '@grafana/faro-web-tracing'; import { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load'; import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch'; diff --git a/grafana-plugin/yarn.lock b/grafana-plugin/yarn.lock index e8eb8d4f..68b6f8de 100644 --- a/grafana-plugin/yarn.lock +++ b/grafana-plugin/yarn.lock @@ -1594,15 +1594,6 @@ eslint-plugin-react-hooks "4.3.0" typescript "4.6.4" -"@grafana/faro-core@ ^1.0.0-beta4", "@grafana/faro-core@^1.0.0-beta4": - version "1.0.0-beta4" - resolved "https://registry.yarnpkg.com/@grafana/faro-core/-/faro-core-1.0.0-beta4.tgz#2f38e18764c0a3c3f1af889d510a2896bcb742ab" - integrity sha512-tB7705aYCByw4CNWt3WNoV39+sZCudBMiStmiEKHzM17VRRLBjPcrMQTkVYu4zMkEAdWMuAdYhT3xjzHlQpXIA== - dependencies: - "@opentelemetry/api" "^1.3.0" - "@opentelemetry/api-metrics" "^0.33.0" - "@opentelemetry/otlp-transformer" "^0.34.0" - "@grafana/faro-core@^1.0.0-beta2": version "1.0.0-beta2" resolved "https://registry.yarnpkg.com/@grafana/faro-core/-/faro-core-1.0.0-beta2.tgz#97636677c1d687b0b238642a3978334652f263a5" @@ -1613,6 +1604,15 @@ "@opentelemetry/otlp-transformer" "^0.33.0" fast-deep-equal "^3.1.3" +"@grafana/faro-core@^1.0.0-beta4": + version "1.0.0-beta4" + resolved "https://registry.yarnpkg.com/@grafana/faro-core/-/faro-core-1.0.0-beta4.tgz#2f38e18764c0a3c3f1af889d510a2896bcb742ab" + integrity sha512-tB7705aYCByw4CNWt3WNoV39+sZCudBMiStmiEKHzM17VRRLBjPcrMQTkVYu4zMkEAdWMuAdYhT3xjzHlQpXIA== + dependencies: + "@opentelemetry/api" "^1.3.0" + "@opentelemetry/api-metrics" "^0.33.0" + "@opentelemetry/otlp-transformer" "^0.34.0" + "@grafana/faro-web-sdk@1.0.0-beta2": version "1.0.0-beta2" resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-1.0.0-beta2.tgz#d096a350d6366a108428a205753c797802eb480d" From 4f5c2503e162145544095e9dd80d561ea0a69d75 Mon Sep 17 00:00:00 2001 From: Maxim Date: Tue, 3 Jan 2023 12:30:53 +0300 Subject: [PATCH 18/19] use hardcoded faro creds instead of env defined --- grafana-plugin/.env.example | 4 -- grafana-plugin/src/state/plugin/index.ts | 2 +- .../{faro.test.ts => faro.test.disabled} | 0 grafana-plugin/src/utils/faro.ts | 37 +++++++++++-------- 4 files changed, 22 insertions(+), 21 deletions(-) rename grafana-plugin/src/utils/{faro.test.ts => faro.test.disabled} (100%) diff --git a/grafana-plugin/.env.example b/grafana-plugin/.env.example index cda4f504..e69de29b 100644 --- a/grafana-plugin/.env.example +++ b/grafana-plugin/.env.example @@ -1,4 +0,0 @@ -FARO_URL=http://localhost:12345/collect -FARO_ENV=dev -FARO_API_KEY=secret -FARO_ENABLED=true \ No newline at end of file diff --git a/grafana-plugin/src/state/plugin/index.ts b/grafana-plugin/src/state/plugin/index.ts index 55326cd0..454fee84 100644 --- a/grafana-plugin/src/state/plugin/index.ts +++ b/grafana-plugin/src/state/plugin/index.ts @@ -208,7 +208,7 @@ class PluginState { } if (!FaroHelper.faro) { - FaroHelper.initializeFaro(); + FaroHelper.initializeFaro(onCallApiUrl); } return await this.pollOnCallDataSyncStatus(onCallApiUrl, onCallApiUrlIsConfiguredThroughEnvVar); diff --git a/grafana-plugin/src/utils/faro.test.ts b/grafana-plugin/src/utils/faro.test.disabled similarity index 100% rename from grafana-plugin/src/utils/faro.test.ts rename to grafana-plugin/src/utils/faro.test.disabled diff --git a/grafana-plugin/src/utils/faro.ts b/grafana-plugin/src/utils/faro.ts index 98ec7cc2..bde13444 100644 --- a/grafana-plugin/src/utils/faro.ts +++ b/grafana-plugin/src/utils/faro.ts @@ -11,26 +11,35 @@ const IGNORE_URLS = [/^((?!\/{0,1}a\/grafana\-oncall\-app\\).)*$/]; interface FaroConfig { url: string; - apiKey: string; enabled: boolean; environment: string; } -const ONCALL = 'grafana-oncall'; - class FaroHelper { faro: Faro; - initializeFaro() { - const faroInput = process.env || {}; - const FARO_ENV = faroInput['FARO_ENV']; + initializeFaro(onCallApiUrl: string) { const faroConfig: FaroConfig = { - url: faroInput['FARO_URL'], - apiKey: faroInput['FARO_API_KEY'], - enabled: faroInput['FARO_ENABLED']?.toLowerCase() === 'true', - environment: FARO_ENV ? `${ONCALL}-${FARO_ENV}` : ONCALL, + url: 'https://faro-collector-prod-us-central-0.grafana.net/collect/f3a038193e7802cf47531ca94cfbada7', + enabled: false, + environment: undefined, }; + if (onCallApiUrl === 'https://oncall-prod-us-central-0.grafana.net/oncall') { + faroConfig.enabled = true; + faroConfig.environment = 'prod'; + } else if (onCallApiUrl === 'https://oncall-ops-us-east-0.grafana.net/oncall') { + faroConfig.enabled = true; + faroConfig.environment = 'ops'; + } else if (onCallApiUrl === 'https://oncall-dev-us-central-0.grafana.net/oncall') { + faroConfig.enabled = true; + faroConfig.environment = 'dev'; + } else { + // This opensource, don't send traces + /* faroConfig.enabled = true; + faroConfig.environment = 'local'; */ + } + if (!faroConfig?.enabled || !faroConfig?.url || this.faro) { return undefined; } @@ -38,7 +47,6 @@ class FaroHelper { try { const faroOptions = { url: faroConfig.url, - apiKey: faroConfig.apiKey, isolate: true, instrumentations: [ ...getWebInstrumentations({ @@ -55,15 +63,12 @@ class FaroHelper { ], session: (window as any).__PRELOADED_STATE__?.faro?.session, app: { - name: faroConfig.environment, + name: 'grafana-oncall-test', version: plugin?.version, + environment: faroConfig.environment, }, }; - if (!faroConfig.apiKey) { - delete faroOptions.apiKey; // appo11y has the key in the API instead - } - this.faro = initializeFaro(faroOptions); this.faro.api.pushLog([`Faro was initialized for ${faroConfig.environment}`]); From 3583c5ea4903837d9ec61d880c6972417fef88d0 Mon Sep 17 00:00:00 2001 From: Ildar Iskhakov Date: Wed, 4 Jan 2023 08:57:22 +0800 Subject: [PATCH 19/19] Update faro.ts --- grafana-plugin/src/utils/faro.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grafana-plugin/src/utils/faro.ts b/grafana-plugin/src/utils/faro.ts index bde13444..357b9e94 100644 --- a/grafana-plugin/src/utils/faro.ts +++ b/grafana-plugin/src/utils/faro.ts @@ -63,7 +63,7 @@ class FaroHelper { ], session: (window as any).__PRELOADED_STATE__?.faro?.session, app: { - name: 'grafana-oncall-test', + name: 'grafana-oncall', version: plugin?.version, environment: faroConfig.environment, },