Chore: Rudderstack upgrade to SDK v3 behind flag (#114126)
* add rudderstack version upgrade feature flag * add new rudderstack backend file gate new backend with feature flag * fix global type error
This commit is contained in:
@@ -1188,4 +1188,9 @@ export interface FeatureToggles {
|
||||
* Enable TTL plugin instance manager
|
||||
*/
|
||||
ttlPluginInstanceManager?: boolean;
|
||||
/**
|
||||
* Enables the new version of rudderstack
|
||||
* @default false
|
||||
*/
|
||||
rudderstackUpgrade?: boolean;
|
||||
}
|
||||
|
||||
@@ -2064,6 +2064,18 @@ var (
|
||||
FrontendOnly: true,
|
||||
Owner: grafanaPluginsPlatformSquad,
|
||||
},
|
||||
{
|
||||
Name: "rudderstackUpgrade",
|
||||
Description: "Enables the new version of rudderstack",
|
||||
FrontendOnly: true,
|
||||
Stage: FeatureStageExperimental,
|
||||
Owner: grafanaFrontendPlatformSquad,
|
||||
Expression: "false",
|
||||
RequiresRestart: false,
|
||||
AllowSelfServe: false,
|
||||
HideFromDocs: false,
|
||||
HideFromAdminPage: false,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
Generated
+1
@@ -265,3 +265,4 @@ kubernetesAnnotations,experimental,@grafana/grafana-backend-services-squad,false
|
||||
awsDatasourcesHttpProxy,experimental,@grafana/aws-datasources,false,false,false
|
||||
transformationsEmptyPlaceholder,preview,@grafana/datapro,false,false,true
|
||||
ttlPluginInstanceManager,experimental,@grafana/plugins-platform-backend,false,false,true
|
||||
rudderstackUpgrade,experimental,@grafana/grafana-frontend-platform,false,false,true
|
||||
|
||||
|
Generated
+4
@@ -1069,4 +1069,8 @@ const (
|
||||
// FlagTtlPluginInstanceManager
|
||||
// Enable TTL plugin instance manager
|
||||
FlagTtlPluginInstanceManager = "ttlPluginInstanceManager"
|
||||
|
||||
// FlagRudderstackUpgrade
|
||||
// Enables the new version of rudderstack
|
||||
FlagRudderstackUpgrade = "rudderstackUpgrade"
|
||||
)
|
||||
|
||||
+14
@@ -3662,6 +3662,20 @@
|
||||
"codeowner": "@grafana/identity-access-team"
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "rudderstackUpgrade",
|
||||
"resourceVersion": "1763481217872",
|
||||
"creationTimestamp": "2025-11-18T15:53:37Z"
|
||||
},
|
||||
"spec": {
|
||||
"description": "Enables the new version of rudderstack",
|
||||
"stage": "experimental",
|
||||
"codeowner": "@grafana/grafana-frontend-platform",
|
||||
"frontend": true,
|
||||
"expression": "false"
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "savedQueries",
|
||||
|
||||
@@ -21,7 +21,21 @@ interface RudderstackAPIOptions {
|
||||
|
||||
interface Rudderstack {
|
||||
identify: (identifier: string, traits: Properties, options?: RudderstackAPIOptions) => void;
|
||||
load: (writeKey: string, dataPlaneURL: string, options: { configUrl?: string; destSDKBaseURL?: string }) => void;
|
||||
// load type set to match Rudderstack v3, for global type compatibility with new version.
|
||||
load: (
|
||||
writeKey: string,
|
||||
dataPlaneURL: string,
|
||||
options: {
|
||||
configUrl?: string;
|
||||
destSDKBaseURL?: string;
|
||||
storage?: {
|
||||
encryption?: {
|
||||
version: 'V3' | 'legacy';
|
||||
};
|
||||
migrate?: boolean;
|
||||
};
|
||||
}
|
||||
) => void;
|
||||
page: () => void;
|
||||
track: (eventName: string, properties?: Properties) => void;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
import { BuildInfo } from '@grafana/data';
|
||||
import {
|
||||
EchoBackend,
|
||||
EchoEventType,
|
||||
isExperimentViewEvent,
|
||||
isInteractionEvent,
|
||||
isPageviewEvent,
|
||||
PageviewEchoEvent,
|
||||
} from '@grafana/runtime';
|
||||
|
||||
import { User } from '../../../context_srv';
|
||||
import { loadScript } from '../../utils';
|
||||
|
||||
type Properties = Record<string, string | boolean | number>;
|
||||
|
||||
interface RudderstackAPIOptions {
|
||||
Intercom?: {
|
||||
user_hash: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface Rudderstack {
|
||||
identify: (identifier: string, traits: Properties, options?: RudderstackAPIOptions) => void;
|
||||
load: (
|
||||
writeKey: string,
|
||||
dataPlaneURL: string,
|
||||
options: {
|
||||
configUrl?: string;
|
||||
destSDKBaseURL?: string;
|
||||
storage?: {
|
||||
encryption?: {
|
||||
version: 'V3' | 'legacy';
|
||||
};
|
||||
migrate?: boolean;
|
||||
};
|
||||
}
|
||||
) => void;
|
||||
page: () => void;
|
||||
track: (eventName: string, properties?: Properties) => void;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
// We say all methods are undefined because we can't be sure they're there
|
||||
// and we should be extra cautious
|
||||
rudderanalytics?: Partial<Rudderstack>;
|
||||
}
|
||||
}
|
||||
|
||||
export interface RudderstackBackendOptions {
|
||||
writeKey: string;
|
||||
dataPlaneUrl: string;
|
||||
buildInfo: BuildInfo;
|
||||
user?: User;
|
||||
sdkUrl?: string;
|
||||
configUrl?: string;
|
||||
integrationsUrl?: string;
|
||||
}
|
||||
|
||||
export class RudderstackBackend implements EchoBackend<PageviewEchoEvent, RudderstackBackendOptions> {
|
||||
supportedEvents = [EchoEventType.Pageview, EchoEventType.Interaction, EchoEventType.ExperimentView];
|
||||
|
||||
constructor(public options: RudderstackBackendOptions) {
|
||||
const url = options.sdkUrl || `https://cdn.rudderlabs.com/v3/modern/rsa.min.js`;
|
||||
loadScript(url);
|
||||
|
||||
// this preloadRudderstack functionality is mirror the loading snippet reference in the Rudderstack
|
||||
// docs here: https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/installation/#using-cdn
|
||||
// We don't need a bunch of what's in the snippet, and we can rely on browser support being modern,
|
||||
// so this is much more terse and only needs to handle the temp setup that pushes calls to the
|
||||
// rudderstack API into the temp array.
|
||||
const preloadRudderstack: unknown[] = [];
|
||||
|
||||
const methodNames = [
|
||||
'setDefaultInstanceKey',
|
||||
'load',
|
||||
'ready',
|
||||
'page',
|
||||
'track',
|
||||
'identify',
|
||||
'alias',
|
||||
'group',
|
||||
'reset',
|
||||
'setAnonymousId',
|
||||
'startSession',
|
||||
'endSession',
|
||||
'consent',
|
||||
'addCustomIntegration',
|
||||
];
|
||||
|
||||
methodNames.forEach((methodName) => {
|
||||
// using Object.assign gets around the types being "wrong".
|
||||
Object.assign(preloadRudderstack, {
|
||||
[methodName]: function () {
|
||||
preloadRudderstack.push([methodName].concat(Array.prototype.slice.call(arguments)));
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
Object.assign(window, { rudderanalytics: preloadRudderstack });
|
||||
|
||||
window.rudderanalytics?.load?.(options.writeKey, options.dataPlaneUrl, {
|
||||
configUrl: options.configUrl,
|
||||
destSDKBaseURL: options.integrationsUrl,
|
||||
// these storage settings allow backwards compat across subdomains with the older rudderstack
|
||||
// version. This would have to be changed to the new setting across all instances at once,
|
||||
// and wouldn't be able to be rolled back.
|
||||
storage: {
|
||||
encryption: {
|
||||
version: 'legacy',
|
||||
},
|
||||
migrate: false,
|
||||
},
|
||||
});
|
||||
|
||||
if (options.user) {
|
||||
const { identifier, intercomIdentifier } = options.user.analytics;
|
||||
const apiOptions: RudderstackAPIOptions = {};
|
||||
|
||||
if (intercomIdentifier) {
|
||||
apiOptions.Intercom = {
|
||||
user_hash: intercomIdentifier,
|
||||
};
|
||||
}
|
||||
|
||||
window.rudderanalytics?.identify?.(
|
||||
identifier,
|
||||
{
|
||||
email: options.user.email,
|
||||
orgId: options.user.orgId,
|
||||
language: options.user.language,
|
||||
version: options.buildInfo.version,
|
||||
edition: options.buildInfo.edition,
|
||||
},
|
||||
apiOptions
|
||||
);
|
||||
}
|
||||
|
||||
window.rudderanalytics?.page?.();
|
||||
}
|
||||
|
||||
addEvent = (e: PageviewEchoEvent) => {
|
||||
if (!window.rudderanalytics) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPageviewEvent(e)) {
|
||||
window.rudderanalytics.page?.();
|
||||
}
|
||||
|
||||
if (isInteractionEvent(e)) {
|
||||
window.rudderanalytics.track?.(e.payload.interactionName, e.payload.properties);
|
||||
}
|
||||
|
||||
if (isExperimentViewEvent(e)) {
|
||||
window.rudderanalytics.track?.('experiment_viewed', {
|
||||
experiment_id: e.payload.experimentId,
|
||||
experiment_group: e.payload.experimentGroup,
|
||||
experiment_variant: e.payload.experimentVariant,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Not using Echo buffering, addEvent above sends events to GA as soon as they appear
|
||||
flush = () => {};
|
||||
}
|
||||
@@ -146,7 +146,11 @@ async function initRudderstackBackend() {
|
||||
return;
|
||||
}
|
||||
|
||||
const { RudderstackBackend } = await import('./backends/analytics/RudderstackBackend');
|
||||
const modulePromise = config.featureToggles.rudderstackUpgrade
|
||||
? import('./backends/analytics/RudderstackV3Backend')
|
||||
: import('./backends/analytics/RudderstackBackend');
|
||||
|
||||
const { RudderstackBackend } = await modulePromise;
|
||||
registerEchoBackend(
|
||||
new RudderstackBackend({
|
||||
writeKey: config.rudderstackWriteKey,
|
||||
|
||||
Reference in New Issue
Block a user