feat: update logEvent to pass eventType and replace segment calls wit… (#7209)

* feat: update logEvent to pass eventType and replace segment calls with logEvent

* feat: update logEvent to handle rate limiting

---------

Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
This commit is contained in:
Yunus M 2025-03-07 15:42:51 +05:30 committed by GitHub
parent 42f7511e06
commit d362f5bce3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 52 additions and 105 deletions

View File

@ -1,13 +1,13 @@
import { ConfigProvider } from 'antd'; import { ConfigProvider } from 'antd';
import getLocalStorageApi from 'api/browser/localstorage/get'; import getLocalStorageApi from 'api/browser/localstorage/get';
import setLocalStorageApi from 'api/browser/localstorage/set'; import setLocalStorageApi from 'api/browser/localstorage/set';
import logEvent from 'api/common/logEvent';
import NotFound from 'components/NotFound'; import NotFound from 'components/NotFound';
import Spinner from 'components/Spinner'; import Spinner from 'components/Spinner';
import { FeatureKeys } from 'constants/features'; import { FeatureKeys } from 'constants/features';
import { LOCALSTORAGE } from 'constants/localStorage'; import { LOCALSTORAGE } from 'constants/localStorage';
import ROUTES from 'constants/routes'; import ROUTES from 'constants/routes';
import AppLayout from 'container/AppLayout'; import AppLayout from 'container/AppLayout';
import useAnalytics from 'hooks/analytics/useAnalytics';
import { KeyboardHotkeysProvider } from 'hooks/hotkeys/useKeyboardHotkeys'; import { KeyboardHotkeysProvider } from 'hooks/hotkeys/useKeyboardHotkeys';
import { useThemeConfig } from 'hooks/useDarkMode'; import { useThemeConfig } from 'hooks/useDarkMode';
import { useGetTenantLicense } from 'hooks/useGetTenantLicense'; import { useGetTenantLicense } from 'hooks/useGetTenantLicense';
@ -15,7 +15,6 @@ import { LICENSE_PLAN_KEY } from 'hooks/useLicense';
import { NotificationProvider } from 'hooks/useNotifications'; import { NotificationProvider } from 'hooks/useNotifications';
import { ResourceProvider } from 'hooks/useResourceAttribute'; import { ResourceProvider } from 'hooks/useResourceAttribute';
import history from 'lib/history'; import history from 'lib/history';
import { identity, pickBy } from 'lodash-es';
import posthog from 'posthog-js'; import posthog from 'posthog-js';
import AlertRuleProvider from 'providers/Alert'; import AlertRuleProvider from 'providers/Alert';
import { useAppContext } from 'providers/App/App'; import { useAppContext } from 'providers/App/App';
@ -51,8 +50,6 @@ function App(): JSX.Element {
} = useAppContext(); } = useAppContext();
const [routes, setRoutes] = useState<AppRoutes[]>(defaultRoutes); const [routes, setRoutes] = useState<AppRoutes[]>(defaultRoutes);
const { trackPageView } = useAnalytics();
const { hostname, pathname } = window.location; const { hostname, pathname } = window.location;
const { const {
@ -69,18 +66,21 @@ function App(): JSX.Element {
const { name, email, role } = user; const { name, email, role } = user;
const domain = extractDomain(email);
const hostNameParts = hostname.split('.');
const identifyPayload = { const identifyPayload = {
email, email,
name, name,
company_name: orgName, company_name: orgName,
role, tenant_id: hostNameParts[0],
data_region: hostNameParts[1],
tenant_url: hostname,
company_domain: domain,
source: 'signoz-ui', source: 'signoz-ui',
role,
}; };
const sanitizedIdentifyPayload = pickBy(identifyPayload, identity);
const domain = extractDomain(email);
const hostNameParts = hostname.split('.');
const groupTraits = { const groupTraits = {
name: orgName, name: orgName,
tenant_id: hostNameParts[0], tenant_id: hostNameParts[0],
@ -90,8 +90,13 @@ function App(): JSX.Element {
source: 'signoz-ui', source: 'signoz-ui',
}; };
window.analytics.identify(email, sanitizedIdentifyPayload); if (email) {
window.analytics.group(domain, groupTraits); logEvent('Email Identified', identifyPayload, 'identify');
}
if (domain) {
logEvent('Domain Identified', groupTraits, 'group');
}
posthog?.identify(email, { posthog?.identify(email, {
email, email,
@ -192,9 +197,7 @@ function App(): JSX.Element {
hide_default_launcher: false, hide_default_launcher: false,
}); });
} }
}, [pathname]);
trackPageView(pathname);
}, [pathname, trackPageView]);
useEffect(() => { useEffect(() => {
// feature flag shouldn't be loading and featureFlags or fetchError any one of this should be true indicating that req is complete // feature flag shouldn't be loading and featureFlags or fetchError any one of this should be true indicating that req is complete

View File

@ -7,11 +7,15 @@ import { EventSuccessPayloadProps } from 'types/api/events/types';
const logEvent = async ( const logEvent = async (
eventName: string, eventName: string,
attributes: Record<string, unknown>, attributes: Record<string, unknown>,
eventType?: 'track' | 'group' | 'identify',
rateLimited?: boolean,
): Promise<SuccessResponse<EventSuccessPayloadProps> | ErrorResponse> => { ): Promise<SuccessResponse<EventSuccessPayloadProps> | ErrorResponse> => {
try { try {
const response = await axios.post('/event', { const response = await axios.post('/event', {
eventName, eventName,
attributes, attributes,
eventType: eventType || 'track',
rateLimited: rateLimited || false, // TODO: Update this once we have a proper way to handle rate limiting
}); });
return { return {

View File

@ -392,11 +392,16 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
LOCALSTORAGE.DONT_SHOW_SLOW_API_WARNING, LOCALSTORAGE.DONT_SHOW_SLOW_API_WARNING,
); );
logEvent(`Slow API Warning`, { logEvent(
duration: `${data.duration}ms`, `Slow API Warning`,
url: data.url, {
threshold: data.threshold, durationMs: data.duration,
}); url: data.url,
thresholdMs: data.threshold,
},
'track',
true, // rate limited - controlled by Backend
);
const isDontShowSlowApiWarning = dontShowSlowApiWarning === 'true'; const isDontShowSlowApiWarning = dontShowSlowApiWarning === 'true';

View File

@ -19,10 +19,6 @@ jest.mock('hooks/useNotifications', () => ({
})), })),
})); }));
window.analytics = {
track: jest.fn(),
};
describe('Onboarding invite team member flow', () => { describe('Onboarding invite team member flow', () => {
it('initial render and get started page', async () => { it('initial render and get started page', async () => {
const { findByText } = render( const { findByText } = render(

View File

@ -1,40 +0,0 @@
import { useAppContext } from 'providers/App/App';
import { useCallback } from 'react';
import { extractDomain } from 'utils/app';
const useAnalytics = (): any => {
const { user } = useAppContext();
// Segment Page View - analytics.page([category], [name], [properties], [options], [callback]);
const trackPageView = useCallback(
(pageName: string): void => {
if (user && user.email) {
window.analytics.page(null, pageName, {
userId: user.email,
});
}
},
[user],
);
const trackEvent = (
eventName: string,
properties?: Record<string, unknown>,
): void => {
if (user && user.email) {
const context = {
context: {
groupId: extractDomain(user?.email),
},
};
const updatedProperties = { ...properties };
updatedProperties.userId = user.email;
window.analytics.track(eventName, properties, context);
}
};
return { trackPageView, trackEvent };
};
export default useAnalytics;

View File

@ -49,12 +49,10 @@
/> />
<meta data-react-helmet="true" name="docusaurus_locale" content="en" /> <meta data-react-helmet="true" name="docusaurus_locale" content="en" />
<meta data-react-helmet="true" name="docusaurus_tag" content="default" /> <meta data-react-helmet="true" name="docusaurus_tag" content="default" />
<meta name="robots" content="noindex"> <meta name="robots" content="noindex" />
<link data-react-helmet="true" rel="shortcut icon" href="/favicon.ico" /> <link data-react-helmet="true" rel="shortcut icon" href="/favicon.ico" />
<link rel="stylesheet" href="/css/uPlot.min.css" /> <link rel="stylesheet" href="/css/uPlot.min.css" />
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
@ -100,32 +98,16 @@
</script> </script>
<script> <script>
const CUSTOMERIO_ID = '<%= htmlWebpackPlugin.options.CUSTOMERIO_ID %>'; const CUSTOMERIO_ID = '<%= htmlWebpackPlugin.options.CUSTOMERIO_ID %>';
const CUSTOMERIO_SITE_ID = '<%= htmlWebpackPlugin.options.CUSTOMERIO_SITE_ID %>'; const CUSTOMERIO_SITE_ID =
!function(){var i="cioanalytics", analytics=(window[i]=window[i]||[]);if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware"];analytics.factory=function(e){return function(){var t=Array.prototype.slice.call(arguments);t.unshift(e);analytics.push(t);return analytics}};for(var e=0;e<analytics.methods.length;e++){var key=analytics.methods[e];analytics[key]=analytics.factory(key)}analytics.load=function(key,e){var t=document.createElement("script");t.type="text/javascript";t.async=!0;t.setAttribute('data-global-customerio-analytics-key', i);t.src="https://cdp.customer.io/v1/analytics-js/snippet/" + key + "/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(t,n);analytics._writeKey=key;analytics._loadOptions=e};analytics.SNIPPET_VERSION="4.15.3"; '<%= htmlWebpackPlugin.options.CUSTOMERIO_SITE_ID %>';
analytics.load(
CUSTOMERIO_ID,
{
"integrations": {
"Customer.io In-App Plugin": {
siteId: CUSTOMERIO_SITE_ID
}
}
}
);
analytics.page();
}}();
</script>
<script>
//Set your SEGMENT_ID
const SEGMENT_ID = '<%= htmlWebpackPlugin.options.SEGMENT_ID %>';
!(function () { !(function () {
var analytics = (window.analytics = window.analytics || []); var i = 'cioanalytics',
analytics = (window[i] = window[i] || []);
if (!analytics.initialize) if (!analytics.initialize)
if (analytics.invoked) if (analytics.invoked)
window.console && window.console &&
console.error && console.error &&
console.error('Segment snippet included twice.'); console.error('Snippet included twice.');
else { else {
analytics.invoked = !0; analytics.invoked = !0;
analytics.methods = [ analytics.methods = [
@ -152,35 +134,36 @@
]; ];
analytics.factory = function (e) { analytics.factory = function (e) {
return function () { return function () {
if (window.analytics.initialized) var t = Array.prototype.slice.call(arguments);
return window.analytics[e].apply(window.analytics, arguments); t.unshift(e);
var i = Array.prototype.slice.call(arguments); analytics.push(t);
i.unshift(e);
analytics.push(i);
return analytics; return analytics;
}; };
}; };
for (var i = 0; i < analytics.methods.length; i++) { for (var e = 0; e < analytics.methods.length; e++) {
var key = analytics.methods[i]; var key = analytics.methods[e];
analytics[key] = analytics.factory(key); analytics[key] = analytics.factory(key);
} }
analytics.load = function (key, i) { analytics.load = function (key, e) {
var t = document.createElement('script'); var t = document.createElement('script');
t.type = 'text/javascript'; t.type = 'text/javascript';
t.async = !0; t.async = !0;
t.setAttribute('data-global-customerio-analytics-key', i);
t.src = t.src =
'https://analytics-cdn.signoz.io/analytics.js/v1/' + 'https://cdp.customer.io/v1/analytics-js/snippet/' +
key + key +
'/analytics.min.js'; '/analytics.min.js';
var n = document.getElementsByTagName('script')[0]; var n = document.getElementsByTagName('script')[0];
n.parentNode.insertBefore(t, n); n.parentNode.insertBefore(t, n);
analytics._loadOptions = i; analytics._writeKey = key;
analytics._loadOptions = e;
}; };
analytics._writeKey = SEGMENT_ID; analytics.SNIPPET_VERSION = '4.15.3';
analytics.SNIPPET_VERSION = '4.16.1'; analytics.load(CUSTOMERIO_ID, {
analytics.load(SEGMENT_ID, {
integrations: { integrations: {
'Segment.io': { apiHost: 'analytics-api.signoz.io/v1' }, 'Customer.io In-App Plugin': {
siteId: CUSTOMERIO_SITE_ID,
},
}, },
}); });
analytics.page(); analytics.page();

View File

@ -21,7 +21,6 @@ const plugins = [
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
template: 'src/index.html.ejs', template: 'src/index.html.ejs',
INTERCOM_APP_ID: process.env.INTERCOM_APP_ID, INTERCOM_APP_ID: process.env.INTERCOM_APP_ID,
SEGMENT_ID: process.env.SEGMENT_ID,
CUSTOMERIO_SITE_ID: process.env.CUSTOMERIO_SITE_ID, CUSTOMERIO_SITE_ID: process.env.CUSTOMERIO_SITE_ID,
CUSTOMERIO_ID: process.env.CUSTOMERIO_ID, CUSTOMERIO_ID: process.env.CUSTOMERIO_ID,
POSTHOG_KEY: process.env.POSTHOG_KEY, POSTHOG_KEY: process.env.POSTHOG_KEY,
@ -41,7 +40,6 @@ const plugins = [
FRONTEND_API_ENDPOINT: process.env.FRONTEND_API_ENDPOINT, FRONTEND_API_ENDPOINT: process.env.FRONTEND_API_ENDPOINT,
WEBSOCKET_API_ENDPOINT: process.env.WEBSOCKET_API_ENDPOINT, WEBSOCKET_API_ENDPOINT: process.env.WEBSOCKET_API_ENDPOINT,
INTERCOM_APP_ID: process.env.INTERCOM_APP_ID, INTERCOM_APP_ID: process.env.INTERCOM_APP_ID,
SEGMENT_ID: process.env.SEGMENT_ID,
CUSTOMERIO_SITE_ID: process.env.CUSTOMERIO_SITE_ID, CUSTOMERIO_SITE_ID: process.env.CUSTOMERIO_SITE_ID,
CUSTOMERIO_ID: process.env.CUSTOMERIO_ID, CUSTOMERIO_ID: process.env.CUSTOMERIO_ID,
POSTHOG_KEY: process.env.POSTHOG_KEY, POSTHOG_KEY: process.env.POSTHOG_KEY,

View File

@ -26,7 +26,6 @@ const plugins = [
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
template: 'src/index.html.ejs', template: 'src/index.html.ejs',
INTERCOM_APP_ID: process.env.INTERCOM_APP_ID, INTERCOM_APP_ID: process.env.INTERCOM_APP_ID,
SEGMENT_ID: process.env.SEGMENT_ID,
CUSTOMERIO_SITE_ID: process.env.CUSTOMERIO_SITE_ID, CUSTOMERIO_SITE_ID: process.env.CUSTOMERIO_SITE_ID,
CUSTOMERIO_ID: process.env.CUSTOMERIO_ID, CUSTOMERIO_ID: process.env.CUSTOMERIO_ID,
POSTHOG_KEY: process.env.POSTHOG_KEY, POSTHOG_KEY: process.env.POSTHOG_KEY,
@ -51,7 +50,6 @@ const plugins = [
FRONTEND_API_ENDPOINT: process.env.FRONTEND_API_ENDPOINT, FRONTEND_API_ENDPOINT: process.env.FRONTEND_API_ENDPOINT,
WEBSOCKET_API_ENDPOINT: process.env.WEBSOCKET_API_ENDPOINT, WEBSOCKET_API_ENDPOINT: process.env.WEBSOCKET_API_ENDPOINT,
INTERCOM_APP_ID: process.env.INTERCOM_APP_ID, INTERCOM_APP_ID: process.env.INTERCOM_APP_ID,
SEGMENT_ID: process.env.SEGMENT_ID,
CUSTOMERIO_SITE_ID: process.env.CUSTOMERIO_SITE_ID, CUSTOMERIO_SITE_ID: process.env.CUSTOMERIO_SITE_ID,
CUSTOMERIO_ID: process.env.CUSTOMERIO_ID, CUSTOMERIO_ID: process.env.CUSTOMERIO_ID,
POSTHOG_KEY: process.env.POSTHOG_KEY, POSTHOG_KEY: process.env.POSTHOG_KEY,