From 47ac43753a03e8507165eb885cc13b2bdc45298c Mon Sep 17 00:00:00 2001 From: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> Date: Mon, 25 Dec 2023 20:57:36 +0530 Subject: [PATCH 1/5] feat: remove ReactGA and migrate to GA4 Signed-off-by: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> --- packages/jaeger-ui/package.json | 1 - packages/jaeger-ui/src/utils/tracking/ga.tsx | 66 +++++++++++++++++--- yarn.lock | 5 -- 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/packages/jaeger-ui/package.json b/packages/jaeger-ui/package.json index f5eff1ab16..67319d7918 100644 --- a/packages/jaeger-ui/package.json +++ b/packages/jaeger-ui/package.json @@ -74,7 +74,6 @@ "react": "^18.2.0", "react-circular-progressbar": "^2.1.0", "react-dom": "^18.2.0", - "react-ga": "^3.3.1", "react-helmet": "^6.1.0", "react-icons": "^4.10.1", "react-is": "^18.2.0", diff --git a/packages/jaeger-ui/src/utils/tracking/ga.tsx b/packages/jaeger-ui/src/utils/tracking/ga.tsx index a85d681e56..07c82ee36e 100644 --- a/packages/jaeger-ui/src/utils/tracking/ga.tsx +++ b/packages/jaeger-ui/src/utils/tracking/ga.tsx @@ -13,7 +13,6 @@ // limitations under the License. import _get from 'lodash/get'; -import ReactGA from 'react-ga'; import Raven, { RavenOptions, RavenTransportOptions } from 'raven-js'; import convRavenToGa from './conv-raven-to-ga'; @@ -24,6 +23,40 @@ import { logTrackingCalls } from './utils'; import { getAppEnvironment, shouldDebugGoogleAnalytics } from '../constants'; import parseQuery from '../parseQuery'; +// Modify the global scope to add the `gtag` function and the `dataLayer` array +declare global { + // eslint-disable-next-line @typescript-eslint/naming-convention + interface Window { + dataLayer: object[]; + gtag: (...args: (string | object)[]) => void; + } +} + +// Function to initialize the Google Analytics script +const initGA = (GA_MEASUREMENT_ID: string, gtagUrl = 'https://www.googletagmanager.com/gtag/js') => { + if (typeof window === 'undefined' || typeof document === 'undefined') { + return; + } + + const script = document.createElement('script'); + script.async = true; + script.src = `${gtagUrl}?id=${GA_MEASUREMENT_ID}`; + document.body.appendChild(script); + + window.dataLayer = window.dataLayer || []; + window.gtag = (...args) => { + window.dataLayer.push(args); + }; +}; + +// Function to call the `gtag` function defined on the window object +const gtag = (...args: (string | object)[]) => { + if (typeof window !== 'undefined') + if (typeof window.gtag === 'function') { + window.gtag(...args); + } +}; + const isTruish = (value?: string | string[]) => { return Boolean(value) && value !== '0' && value !== 'false'; }; @@ -56,7 +89,12 @@ const GA: IWebAnalyticsFunc = (config: Config, versionShort: string, versionLong msg = `jaeger/${msg}`; } msg = msg.slice(0, 149); - ReactGA.exception({ description: msg, fatal: false }); + + gtag('event', 'exception', { + description: msg, + fatal: false, + }); + if (isDebugMode) { logTrackingCalls(); } @@ -90,7 +128,13 @@ const GA: IWebAnalyticsFunc = (config: Config, versionShort: string, versionLong if (value != null) { event.value = Math.round(value); } - ReactGA.event(event); + + gtag('event', event.action, { + event_category: event.category, + event_label: event.label, + value: event.value, + }); + if (isDebugMode) { logTrackingCalls(); } @@ -107,18 +151,22 @@ const GA: IWebAnalyticsFunc = (config: Config, versionShort: string, versionLong return; } - const gaConfig = { testMode: isTest || isDebugMode, titleCase: false, debug: true }; - ReactGA.initialize(gaID || 'debug-mode', gaConfig); - ReactGA.set({ + initGA(gaID || 'debug-mode'); + gtag('set', { appId: 'github.com/jaegertracing/jaeger-ui', appName: 'Jaeger UI', appVersion: versionLong, }); + if (cookiesToDimensions !== undefined) { (cookiesToDimensions as unknown as Array<{ cookie: string; dimension: string }>).forEach( ({ cookie, dimension }: { cookie: string; dimension: string }) => { const match = ` ${document.cookie}`.match(new RegExp(`[; ]${cookie}=([^\\s;]*)`)); - if (match) ReactGA.set({ [dimension]: match[1] }); + if (match) { + gtag('set', { + [dimension]: match[1], + }); + } // eslint-disable-next-line no-console else console.warn(`${cookie} not present in cookies, could not set dimension: ${dimension}`); } @@ -152,7 +200,9 @@ const GA: IWebAnalyticsFunc = (config: Config, versionShort: string, versionLong const trackPageView = (pathname: string, search: string | TNil) => { const pagePath = search ? `${pathname}${search}` : pathname; - ReactGA.pageview(pagePath); + gtag('event', 'page_view', { + page_path: pagePath, + }); if (isDebugMode) { logTrackingCalls(); } diff --git a/yarn.lock b/yarn.lock index eede1fd901..3b83649d5d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8470,11 +8470,6 @@ react-fast-compare@^3.1.1: resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== -react-ga@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-3.3.1.tgz#d8e1f4e05ec55ed6ff944dcb14b99011dfaf9504" - integrity sha512-4Vc0W5EvXAXUN/wWyxvsAKDLLgtJ3oLmhYYssx+YzphJpejtOst6cbIHCIyF50Fdxuf5DDKqRYny24yJ2y7GFQ== - react-helmet@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726" From 23098d7d31c2098feb2c516f7b728cad34502526 Mon Sep 17 00:00:00 2001 From: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> Date: Tue, 26 Dec 2023 13:02:35 +0530 Subject: [PATCH 2/5] fix types and implementation Signed-off-by: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> --- packages/jaeger-ui/src/utils/tracking/ga.tsx | 34 +++++++++++--------- packages/jaeger-ui/src/vite-env.d.ts | 9 ++++++ 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/packages/jaeger-ui/src/utils/tracking/ga.tsx b/packages/jaeger-ui/src/utils/tracking/ga.tsx index 07c82ee36e..62583df86c 100644 --- a/packages/jaeger-ui/src/utils/tracking/ga.tsx +++ b/packages/jaeger-ui/src/utils/tracking/ga.tsx @@ -23,38 +23,41 @@ import { logTrackingCalls } from './utils'; import { getAppEnvironment, shouldDebugGoogleAnalytics } from '../constants'; import parseQuery from '../parseQuery'; -// Modify the global scope to add the `gtag` function and the `dataLayer` array +// Modify the `window` object to have an additional attribute `dataLayer` +// This is required by the gtag.js script to work declare global { // eslint-disable-next-line @typescript-eslint/naming-convention interface Window { - dataLayer: object[]; - gtag: (...args: (string | object)[]) => void; + dataLayer: (string | object)[][] | undefined; } } +// Function to add a new event to the Google Analytics dataLayer +const gtag = (...args: (string | object)[]) => { + if (window !== undefined) + if (window.dataLayer !== undefined) { + window.dataLayer.push(args); + } +}; + // Function to initialize the Google Analytics script -const initGA = (GA_MEASUREMENT_ID: string, gtagUrl = 'https://www.googletagmanager.com/gtag/js') => { +const initGA = (GA_MEASUREMENT_ID: string) => { if (typeof window === 'undefined' || typeof document === 'undefined') { return; } + const gtagUrl = 'https://www.googletagmanager.com/gtag/js'; + + // Load the script asynchronously const script = document.createElement('script'); script.async = true; script.src = `${gtagUrl}?id=${GA_MEASUREMENT_ID}`; document.body.appendChild(script); + // Initialize the dataLayer and send initial configuration data window.dataLayer = window.dataLayer || []; - window.gtag = (...args) => { - window.dataLayer.push(args); - }; -}; - -// Function to call the `gtag` function defined on the window object -const gtag = (...args: (string | object)[]) => { - if (typeof window !== 'undefined') - if (typeof window.gtag === 'function') { - window.gtag(...args); - } + gtag('js', new Date()); + gtag('config', GA_MEASUREMENT_ID); }; const isTruish = (value?: string | string[]) => { @@ -152,6 +155,7 @@ const GA: IWebAnalyticsFunc = (config: Config, versionShort: string, versionLong } initGA(gaID || 'debug-mode'); + gtag('set', { appId: 'github.com/jaegertracing/jaeger-ui', appName: 'Jaeger UI', diff --git a/packages/jaeger-ui/src/vite-env.d.ts b/packages/jaeger-ui/src/vite-env.d.ts index c70e348b4d..5afdcd36c9 100644 --- a/packages/jaeger-ui/src/vite-env.d.ts +++ b/packages/jaeger-ui/src/vite-env.d.ts @@ -14,3 +14,12 @@ // eslint-disable-next-line spaced-comment /// + +declare namespace JaegerUI { + // eslint-disable-next-line @typescript-eslint/naming-convention + interface Window { + // dataLayer is used by Google Tag Manager + // It should never be changed by any module except utils/tracking/ga.ts + dataLayer: never; + } +} From daacac33df4d540ffdf291d44ed3d90de9f0f90f Mon Sep 17 00:00:00 2001 From: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> Date: Tue, 26 Dec 2023 13:54:07 +0530 Subject: [PATCH 3/5] update tests Signed-off-by: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> --- .../jaeger-ui/src/utils/tracking/ga.test.js | 71 ++++++++++--------- packages/jaeger-ui/src/utils/tracking/ga.tsx | 4 +- .../jaeger-ui/src/utils/tracking/utils.tsx | 11 +-- packages/jaeger-ui/src/vite-env.d.ts | 2 +- 4 files changed, 42 insertions(+), 46 deletions(-) diff --git a/packages/jaeger-ui/src/utils/tracking/ga.test.js b/packages/jaeger-ui/src/utils/tracking/ga.test.js index d9944851d1..8d1528d88a 100644 --- a/packages/jaeger-ui/src/utils/tracking/ga.test.js +++ b/packages/jaeger-ui/src/utils/tracking/ga.test.js @@ -12,10 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -import ReactGA from 'react-ga'; import * as GA from './ga'; import * as utils from './utils'; -import { getVersionInfo, getAppEnvironment } from '../constants'; +import { getAppEnvironment } from '../constants'; jest.mock('./conv-raven-to-ga', () => () => ({ category: 'jaeger/a', @@ -35,7 +34,6 @@ function getStr(len) { } describe('google analytics tracking', () => { - let calls; let tracking; beforeAll(() => { @@ -54,16 +52,18 @@ describe('google analytics tracking', () => { }); beforeEach(() => { - getVersionInfo.mockReturnValue('{}'); - calls = ReactGA.testModeAPI.calls; - calls.length = 0; + jest.useFakeTimers(); + // Set an arbitrary date so that we can test the date-based dimension + jest.setSystemTime(new Date('2023-01-01')); + window.dataLayer = []; }); describe('init', () => { it('check init function (no cookies)', () => { tracking.init(); - expect(calls).toEqual([ - ['create', 'UA-123456', 'auto'], + expect(window.dataLayer).toEqual([ + ['js', new Date()], + ['config', 'UA-123456'], [ 'set', { @@ -78,8 +78,9 @@ describe('google analytics tracking', () => { it('check init function (no cookies)', () => { document.cookie = 'page=1;'; tracking.init(); - expect(calls).toEqual([ - ['create', 'UA-123456', 'auto'], + expect(window.dataLayer).toEqual([ + ['js', new Date()], + ['config', 'UA-123456'], [ 'set', { @@ -96,33 +97,33 @@ describe('google analytics tracking', () => { describe('trackPageView', () => { it('tracks a page view', () => { tracking.trackPageView('a', 'b'); - expect(calls).toEqual([['send', { hitType: 'pageview', page: 'ab' }]]); + expect(window.dataLayer).toEqual([['event', 'page_view', { page_path: 'ab' }]]); }); it('ignores search when it is falsy', () => { tracking.trackPageView('a'); - expect(calls).toEqual([['send', { hitType: 'pageview', page: 'a' }]]); + expect(window.dataLayer).toEqual([['event', 'page_view', { page_path: 'a' }]]); }); }); describe('trackError', () => { it('tracks an error', () => { tracking.trackError('a'); - expect(calls).toEqual([ - ['send', { hitType: 'exception', exDescription: expect.any(String), exFatal: false }], + expect(window.dataLayer).toEqual([ + ['event', 'exception', { description: expect.any(String), fatal: false }], ]); }); it('ensures "jaeger" is prepended', () => { tracking.trackError('a'); - expect(calls).toEqual([['send', { hitType: 'exception', exDescription: 'jaeger/a', exFatal: false }]]); + expect(window.dataLayer).toEqual([['event', 'exception', { description: 'jaeger/a', fatal: false }]]); }); it('truncates if needed', () => { const str = `jaeger/${getStr(200)}`; tracking.trackError(str); - expect(calls).toEqual([ - ['send', { hitType: 'exception', exDescription: str.slice(0, 149), exFatal: false }], + expect(window.dataLayer).toEqual([ + ['event', 'exception', { description: str.slice(0, 149), fatal: false }], ]); }); }); @@ -132,13 +133,12 @@ describe('google analytics tracking', () => { const category = 'jaeger/some-category'; const action = 'some-action'; tracking.trackEvent(category, action); - expect(calls).toEqual([ + expect(window.dataLayer).toEqual([ [ - 'send', + 'event', + 'some-action', { - hitType: 'event', - eventCategory: category, - eventAction: action, + event_category: category, }, ], ]); @@ -148,22 +148,19 @@ describe('google analytics tracking', () => { const category = 'some-category'; const action = 'some-action'; tracking.trackEvent(category, action); - expect(calls).toEqual([ - ['send', { hitType: 'event', eventCategory: `jaeger/${category}`, eventAction: action }], - ]); + expect(window.dataLayer).toEqual([['event', 'some-action', { event_category: `jaeger/${category}` }]]); }); it('truncates values, if needed', () => { const str = `jaeger/${getStr(600)}`; tracking.trackEvent(str, str, str); - expect(calls).toEqual([ + expect(window.dataLayer).toEqual([ [ - 'send', + 'event', + str.slice(0, 499), { - hitType: 'event', - eventCategory: str.slice(0, 149), - eventAction: str.slice(0, 499), - eventLabel: str.slice(0, 499), + event_category: str.slice(0, 149), + event_label: str.slice(0, 499), }, ], ]); @@ -171,10 +168,12 @@ describe('google analytics tracking', () => { }); it('converting raven-js errors', () => { - window.onunhandledrejection({ reason: new Error('abc') }); - expect(calls).toEqual([ - ['send', { hitType: 'exception', exDescription: expect.any(String), exFatal: false }], - ['send', { hitType: 'event', eventCategory: expect.any(String), eventAction: expect.any(String) }], + window.onunhandledrejection({ + reason: new Error('abc'), + }); + expect(window.dataLayer).toEqual([ + ['event', 'exception', { description: expect.any(String), fatal: false }], + ['event', expect.any(String), { event_category: expect.any(String) }], ]); }); @@ -209,10 +208,12 @@ describe('google analytics tracking', () => { it('isDebugMode = true', () => { // eslint-disable-next-line no-import-assign utils.logTrackingCalls = jest.fn(); + trackingDebug.init(); trackingDebug.trackError(); trackingDebug.trackEvent('jaeger/some-category', 'some-action'); trackingDebug.trackPageView('a', 'b'); + expect(utils.logTrackingCalls).toHaveBeenCalledTimes(4); }); }); diff --git a/packages/jaeger-ui/src/utils/tracking/ga.tsx b/packages/jaeger-ui/src/utils/tracking/ga.tsx index 62583df86c..03779b65e3 100644 --- a/packages/jaeger-ui/src/utils/tracking/ga.tsx +++ b/packages/jaeger-ui/src/utils/tracking/ga.tsx @@ -134,8 +134,8 @@ const GA: IWebAnalyticsFunc = (config: Config, versionShort: string, versionLong gtag('event', event.action, { event_category: event.category, - event_label: event.label, - value: event.value, + ...(event.label && { event_label: event.label }), + ...(event.value && { event_value: event.value }), }); if (isDebugMode) { diff --git a/packages/jaeger-ui/src/utils/tracking/utils.tsx b/packages/jaeger-ui/src/utils/tracking/utils.tsx index 75f826da59..0abc1f46f1 100644 --- a/packages/jaeger-ui/src/utils/tracking/utils.tsx +++ b/packages/jaeger-ui/src/utils/tracking/utils.tsx @@ -12,14 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -import ReactGA from 'react-ga'; - // eslint-disable-next-line import/prefer-default-export export const logTrackingCalls = () => { - const calls = ReactGA.testModeAPI.calls; - for (let i = 0; i < calls.length; i++) { - // eslint-disable-next-line no-console - console.log('[react-ga]', ...calls[i]); - } - calls.length = 0; + // eslint-disable-next-line no-console + window.dataLayer?.forEach(callArgs => console.log('[GA Tracking]', ...callArgs)); + window.dataLayer = []; }; diff --git a/packages/jaeger-ui/src/vite-env.d.ts b/packages/jaeger-ui/src/vite-env.d.ts index 5afdcd36c9..71bbc6b698 100644 --- a/packages/jaeger-ui/src/vite-env.d.ts +++ b/packages/jaeger-ui/src/vite-env.d.ts @@ -15,7 +15,7 @@ // eslint-disable-next-line spaced-comment /// -declare namespace JaegerUI { +declare namespace global { // eslint-disable-next-line @typescript-eslint/naming-convention interface Window { // dataLayer is used by Google Tag Manager From 6a486405cb7368e1a58d051f8cb3648ec022e8e1 Mon Sep 17 00:00:00 2001 From: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> Date: Tue, 26 Dec 2023 14:12:23 +0530 Subject: [PATCH 4/5] fix leaking of window type Signed-off-by: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> --- packages/jaeger-ui/src/utils/tracking/ga.tsx | 15 ++++++--------- packages/jaeger-ui/src/utils/tracking/utils.tsx | 4 ++++ packages/jaeger-ui/src/vite-env.d.ts | 5 +++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/jaeger-ui/src/utils/tracking/ga.tsx b/packages/jaeger-ui/src/utils/tracking/ga.tsx index 03779b65e3..90f2450ce1 100644 --- a/packages/jaeger-ui/src/utils/tracking/ga.tsx +++ b/packages/jaeger-ui/src/utils/tracking/ga.tsx @@ -25,13 +25,14 @@ import parseQuery from '../parseQuery'; // Modify the `window` object to have an additional attribute `dataLayer` // This is required by the gtag.js script to work -declare global { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface Window { - dataLayer: (string | object)[][] | undefined; - } + +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface WindowWithGATracking extends Window { + dataLayer: (string | object)[][] | undefined; } +declare let window: WindowWithGATracking; + // Function to add a new event to the Google Analytics dataLayer const gtag = (...args: (string | object)[]) => { if (window !== undefined) @@ -42,10 +43,6 @@ const gtag = (...args: (string | object)[]) => { // Function to initialize the Google Analytics script const initGA = (GA_MEASUREMENT_ID: string) => { - if (typeof window === 'undefined' || typeof document === 'undefined') { - return; - } - const gtagUrl = 'https://www.googletagmanager.com/gtag/js'; // Load the script asynchronously diff --git a/packages/jaeger-ui/src/utils/tracking/utils.tsx b/packages/jaeger-ui/src/utils/tracking/utils.tsx index 0abc1f46f1..d78a8a2cb1 100644 --- a/packages/jaeger-ui/src/utils/tracking/utils.tsx +++ b/packages/jaeger-ui/src/utils/tracking/utils.tsx @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { WindowWithGATracking } from './ga'; + +declare let window: WindowWithGATracking; + // eslint-disable-next-line import/prefer-default-export export const logTrackingCalls = () => { // eslint-disable-next-line no-console diff --git a/packages/jaeger-ui/src/vite-env.d.ts b/packages/jaeger-ui/src/vite-env.d.ts index 71bbc6b698..0cfcf9462c 100644 --- a/packages/jaeger-ui/src/vite-env.d.ts +++ b/packages/jaeger-ui/src/vite-env.d.ts @@ -18,8 +18,9 @@ declare namespace global { // eslint-disable-next-line @typescript-eslint/naming-convention interface Window { - // dataLayer is used by Google Tag Manager - // It should never be changed by any module except utils/tracking/ga.ts + // dataLayer property is used by Google Tag Manager + // It should be only be changed with the help of the custom Interface WindowWithGATracking + // defined in utils/tracking/ga.ts dataLayer: never; } } From ada2383ff15f4d7a580e7c13e715f92b3fe0bbfb Mon Sep 17 00:00:00 2001 From: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> Date: Tue, 26 Dec 2023 23:47:25 +0530 Subject: [PATCH 5/5] remove logging utils Signed-off-by: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> --- .../jaeger-ui/src/utils/tracking/ga.test.js | 9 +-- packages/jaeger-ui/src/utils/tracking/ga.tsx | 66 +++++++------------ .../src/utils/tracking/utils.test.js | 23 ------- .../jaeger-ui/src/utils/tracking/utils.tsx | 24 ------- packages/jaeger-ui/src/vite-env.d.ts | 10 --- 5 files changed, 30 insertions(+), 102 deletions(-) delete mode 100644 packages/jaeger-ui/src/utils/tracking/utils.test.js delete mode 100644 packages/jaeger-ui/src/utils/tracking/utils.tsx diff --git a/packages/jaeger-ui/src/utils/tracking/ga.test.js b/packages/jaeger-ui/src/utils/tracking/ga.test.js index 8d1528d88a..dbe48d9bdd 100644 --- a/packages/jaeger-ui/src/utils/tracking/ga.test.js +++ b/packages/jaeger-ui/src/utils/tracking/ga.test.js @@ -13,7 +13,6 @@ // limitations under the License. import * as GA from './ga'; -import * as utils from './utils'; import { getAppEnvironment } from '../constants'; jest.mock('./conv-raven-to-ga', () => () => ({ @@ -205,16 +204,18 @@ describe('google analytics tracking', () => { ); }); + /* eslint-disable no-console */ it('isDebugMode = true', () => { // eslint-disable-next-line no-import-assign - utils.logTrackingCalls = jest.fn(); + console.log = jest.fn(); trackingDebug.init(); + expect(console.log).toHaveBeenCalledTimes(4); + trackingDebug.trackError(); trackingDebug.trackEvent('jaeger/some-category', 'some-action'); trackingDebug.trackPageView('a', 'b'); - - expect(utils.logTrackingCalls).toHaveBeenCalledTimes(4); + expect(console.log).toHaveBeenCalledTimes(7); }); }); }); diff --git a/packages/jaeger-ui/src/utils/tracking/ga.tsx b/packages/jaeger-ui/src/utils/tracking/ga.tsx index 90f2450ce1..b7bdfa52ec 100644 --- a/packages/jaeger-ui/src/utils/tracking/ga.tsx +++ b/packages/jaeger-ui/src/utils/tracking/ga.tsx @@ -19,7 +19,6 @@ import convRavenToGa from './conv-raven-to-ga'; import { TNil } from '../../types'; import { Config } from '../../types/config'; import { IWebAnalyticsFunc } from '../../types/tracking'; -import { logTrackingCalls } from './utils'; import { getAppEnvironment, shouldDebugGoogleAnalytics } from '../constants'; import parseQuery from '../parseQuery'; @@ -27,36 +26,12 @@ import parseQuery from '../parseQuery'; // This is required by the gtag.js script to work // eslint-disable-next-line @typescript-eslint/naming-convention -export interface WindowWithGATracking extends Window { +interface WindowWithGATracking extends Window { dataLayer: (string | object)[][] | undefined; } declare let window: WindowWithGATracking; -// Function to add a new event to the Google Analytics dataLayer -const gtag = (...args: (string | object)[]) => { - if (window !== undefined) - if (window.dataLayer !== undefined) { - window.dataLayer.push(args); - } -}; - -// Function to initialize the Google Analytics script -const initGA = (GA_MEASUREMENT_ID: string) => { - const gtagUrl = 'https://www.googletagmanager.com/gtag/js'; - - // Load the script asynchronously - const script = document.createElement('script'); - script.async = true; - script.src = `${gtagUrl}?id=${GA_MEASUREMENT_ID}`; - document.body.appendChild(script); - - // Initialize the dataLayer and send initial configuration data - window.dataLayer = window.dataLayer || []; - gtag('js', new Date()); - gtag('config', GA_MEASUREMENT_ID); -}; - const isTruish = (value?: string | string[]) => { return Boolean(value) && value !== '0' && value !== 'false'; }; @@ -83,6 +58,18 @@ const GA: IWebAnalyticsFunc = (config: Config, versionShort: string, versionLong return isTest || isDebugMode || (isProd && Boolean(gaID)); }; + // Function to add a new event to the Google Analytics dataLayer + const gtag = (...args: (string | object)[]) => { + if (window !== undefined) + if (window.dataLayer !== undefined && Array.isArray(window.dataLayer)) { + window.dataLayer.push(args); + if (isDebugMode) { + // eslint-disable-next-line no-console + console.log('[GA Tracking]', ...args); + } + } + }; + const trackError = (description: string) => { let msg = description; if (!/^jaeger/i.test(msg)) { @@ -94,10 +81,6 @@ const GA: IWebAnalyticsFunc = (config: Config, versionShort: string, versionLong description: msg, fatal: false, }); - - if (isDebugMode) { - logTrackingCalls(); - } }; const trackEvent = ( @@ -134,10 +117,6 @@ const GA: IWebAnalyticsFunc = (config: Config, versionShort: string, versionLong ...(event.label && { event_label: event.label }), ...(event.value && { event_value: event.value }), }); - - if (isDebugMode) { - logTrackingCalls(); - } }; const trackRavenError = (ravenData: RavenTransportOptions) => { @@ -151,8 +130,19 @@ const GA: IWebAnalyticsFunc = (config: Config, versionShort: string, versionLong return; } - initGA(gaID || 'debug-mode'); + const gtagUrl = 'https://www.googletagmanager.com/gtag/js'; + const GA_MEASUREMENT_ID = gaID || 'debug-mode'; + + // Load the script asynchronously + const script = document.createElement('script'); + script.async = true; + script.src = `${gtagUrl}?id=${GA_MEASUREMENT_ID}`; + document.body.appendChild(script); + // Initialize the dataLayer and send initial configuration data + window.dataLayer = window.dataLayer || []; + gtag('js', new Date()); + gtag('config', GA_MEASUREMENT_ID); gtag('set', { appId: 'github.com/jaegertracing/jaeger-ui', appName: 'Jaeger UI', @@ -194,9 +184,6 @@ const GA: IWebAnalyticsFunc = (config: Config, versionShort: string, versionLong Raven.captureException(evt.reason); }; } - if (isDebugMode) { - logTrackingCalls(); - } }; const trackPageView = (pathname: string, search: string | TNil) => { @@ -204,9 +191,6 @@ const GA: IWebAnalyticsFunc = (config: Config, versionShort: string, versionLong gtag('event', 'page_view', { page_path: pagePath, }); - if (isDebugMode) { - logTrackingCalls(); - } }; return { diff --git a/packages/jaeger-ui/src/utils/tracking/utils.test.js b/packages/jaeger-ui/src/utils/tracking/utils.test.js deleted file mode 100644 index 30c61067d3..0000000000 --- a/packages/jaeger-ui/src/utils/tracking/utils.test.js +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2021 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as utils from './utils'; - -describe('utils', () => { - describe('logTrackingCalls', () => { - it('dry run', () => { - expect(utils.logTrackingCalls()).toBeUndefined(); - }); - }); -}); diff --git a/packages/jaeger-ui/src/utils/tracking/utils.tsx b/packages/jaeger-ui/src/utils/tracking/utils.tsx deleted file mode 100644 index d78a8a2cb1..0000000000 --- a/packages/jaeger-ui/src/utils/tracking/utils.tsx +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2021 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import { WindowWithGATracking } from './ga'; - -declare let window: WindowWithGATracking; - -// eslint-disable-next-line import/prefer-default-export -export const logTrackingCalls = () => { - // eslint-disable-next-line no-console - window.dataLayer?.forEach(callArgs => console.log('[GA Tracking]', ...callArgs)); - window.dataLayer = []; -}; diff --git a/packages/jaeger-ui/src/vite-env.d.ts b/packages/jaeger-ui/src/vite-env.d.ts index 0cfcf9462c..c70e348b4d 100644 --- a/packages/jaeger-ui/src/vite-env.d.ts +++ b/packages/jaeger-ui/src/vite-env.d.ts @@ -14,13 +14,3 @@ // eslint-disable-next-line spaced-comment /// - -declare namespace global { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface Window { - // dataLayer property is used by Google Tag Manager - // It should be only be changed with the help of the custom Interface WindowWithGATracking - // defined in utils/tracking/ga.ts - dataLayer: never; - } -}