Skip to content

Commit

Permalink
feat(page-meta): provide options to override automatically created pa…
Browse files Browse the repository at this point in the history
…geId's (#923)
  • Loading branch information
codecapitano authored Jan 30, 2025
1 parent 63c0612 commit 1b5cc70
Show file tree
Hide file tree
Showing 15 changed files with 294 additions and 77 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

- Feature (`@grafana/faro-web-sdk`): Provide APIs to send `service.name` override instructions to the
receiver (#893)
- Feature (`@grafana/faro-web-sdk`): Introduced `setPage(meta)` API to overwrite page metadata and
added an option to inject a custom `pageId` parser for generating custom `pageId`s continuously
(#923)
- Improvement (`@grafana/faro-web-sdk`): Send an event for `service.name` overrides (#903)
- Improvement (`@grafana/faro-*`) Add required Node engines to package.json ()

Expand Down
1 change: 1 addition & 0 deletions demo/src/client/faro/initialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createRoutesFromChildren, matchRoutes, Routes, useLocation, useNavigati

import {
initializeFaro as coreInit,
genShortID,
getWebInstrumentations,
ReactIntegration,
ReactRouterVersion,
Expand Down
26 changes: 25 additions & 1 deletion packages/core/src/api/meta/initialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { InternalLogger } from '../../internalLogger';
import type { Meta, Metas } from '../../metas';
import type { Transports } from '../../transports';
import type { UnpatchedConsole } from '../../unpatchedConsole';
import { isEmpty } from '../../utils/is';
import { isEmpty, isString } from '../../utils/is';

import type { MetaAPI } from './types';

Expand All @@ -19,6 +19,7 @@ export function initializeMetaAPI(
let metaSession: Partial<Meta> | undefined = undefined;
let metaUser: Partial<Meta> | undefined = undefined;
let metaView: Partial<Meta> | undefined = undefined;
let metaPage: Partial<Meta> | undefined = undefined;

const setUser: MetaAPI['setUser'] = (user) => {
if (metaUser) {
Expand Down Expand Up @@ -76,6 +77,27 @@ export function initializeMetaAPI(

const getView: MetaAPI['getView'] = () => metas.value.view;

const setPage: MetaAPI['setPage'] = (page) => {
const pageMeta = isString(page)
? {
...metaPage?.page,
id: page,
}
: page;

if (metaPage) {
metas.remove(metaPage);
}

metaPage = {
page: pageMeta,
};

metas.add(metaPage);
};

const getPage: MetaAPI['getPage'] = () => metas.value.page;

return {
setUser,
resetUser: setUser as MetaAPI['resetUser'],
Expand All @@ -84,5 +106,7 @@ export function initializeMetaAPI(
getSession,
setView,
getView,
setPage,
getPage,
};
}
34 changes: 34 additions & 0 deletions packages/core/src/api/meta/initilialize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,38 @@ describe('Meta API', () => {
expect(api.getSession()).toEqual({ overrides });
});
});

describe('setPage / getPage', () => {
it('updates the page meta when setPage(meta) is called', () => {
const { api } = initializeFaro(mockConfig());

const page = { url: 'http://example.com/my-page', id: 'my-page' };
api.setPage(page);
expect(api.getPage()).toEqual(page);

const newPage = { url: 'http://example.com/my-new-page', id: 'my-new-page' };
api.setPage(newPage);
expect(api.getPage()).toEqual(newPage);
});

it('updates the page id if the parameter of setPage is a string', () => {
const { api } = initializeFaro(mockConfig());

const initialPage = { url: 'http://example.com/my-page', id: 'my-page', attributes: { hello: 'world' } };
api.setPage(initialPage);
expect(api.getPage()).toStrictEqual(initialPage);

const newPageId = 'my-new-page-id';
api.setPage(newPageId);
expect(api.getPage()?.id).toEqual(newPageId);
});

it('gets the page meta when getPage(meta) is called', () => {
const { api } = initializeFaro(mockConfig());

const page = { url: 'http://example.com/my-page', id: 'my-page' };
api.setPage(page);
expect(api.getPage()).toEqual(page);
});
});
});
8 changes: 7 additions & 1 deletion packages/core/src/api/meta/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { MetaOverrides, MetaSession, MetaUser, MetaView } from '../../metas';
import type { MetaOverrides, MetaPage, MetaSession, MetaUser, MetaView } from '../../metas';

export interface MetaAPI {
setUser: (user?: MetaUser | undefined) => void;
Expand All @@ -18,4 +18,10 @@ export interface MetaAPI {
}
) => void;
getView: () => MetaView | undefined;
/**
* If a string is provided, it will be used as the page id.
* @returns
*/
setPage: (page?: MetaPage | string | undefined) => void;
getPage: () => MetaPage | undefined;
}
14 changes: 13 additions & 1 deletion packages/core/src/config/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { APIEvent, LogArgsSerializer, StacktraceParser } from '../api';
import type { Instrumentation } from '../instrumentations';
import type { InternalLoggerLevel } from '../internalLogger';
import type { Meta, MetaApp, MetaItem, MetaSession, MetaUser, MetaView } from '../metas';
import type { Meta, MetaApp, MetaItem, MetaPage, MetaSession, MetaUser, MetaView } from '../metas';
import type { BatchExecutorOptions, BeforeSendHook, Transport } from '../transports';
import type { UnpatchedConsole } from '../unpatchedConsole';
import type { LogLevel } from '../utils';
Expand Down Expand Up @@ -180,6 +180,18 @@ export interface Config<P = APIEvent> {
*/
consoleErrorAsLog?: boolean;
};

pageTracking?: {
/**
* The page meta for initial page settings
*/
page?: MetaPage;

/**
* Allows to provide a template for the page id
*/
generatePageId?: (location: Location) => string;
};
}

export type Patterns = Array<string | RegExp>;
2 changes: 0 additions & 2 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ export {
defaultGlobalObjectKey,
defaultInternalLoggerLevel,
defaultLogLevel,
defaultMetas,
ErrorsInstrumentation,
FetchTransport,
genShortID,
Expand Down Expand Up @@ -121,7 +120,6 @@ export {
LogLevel,
makeCoreConfig,
noop,
pageMeta,
parseStacktrace,
setInternalFaroOnGlobalObject,
TransportItemType,
Expand Down
11 changes: 1 addition & 10 deletions packages/web-sdk/src/config/makeCoreConfig.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { defaultLogArgsSerializer, isFunction } from '@grafana/faro-core';
import type { LogArgsSerializer } from '@grafana/faro-core';

import { defaultMetas } from '../metas/const';

import { makeCoreConfig } from './makeCoreConfig';

describe('defaultMetas', () => {
Expand All @@ -29,7 +27,7 @@ describe('defaultMetas', () => {
delete (global as any).k6;
});

it('does not include K6 Object properties if not set', () => {
it('does not include K6Meta in defaultMetas for non-k6 (field) sessions', () => {
(global as any).k6 = {};

const browserConfig = {
Expand All @@ -46,13 +44,6 @@ describe('defaultMetas', () => {

delete (global as any).k6;
});

it('does not include K6Meta in defaultMetas for non-k6 (field) sessions', () => {
expect(defaultMetas).toHaveLength(2);
expect(defaultMetas.map((item) => (isFunction(item) ? item() : item))).not.toContainEqual({
k6: { isK6Browser: true },
});
});
});

describe('config', () => {
Expand Down
111 changes: 67 additions & 44 deletions packages/web-sdk/src/config/makeCoreConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ import type { Config, MetaItem, Transport } from '@grafana/faro-core';
import { defaultEventDomain } from '../consts';
import { parseStacktrace } from '../instrumentations';
import { defaultSessionTrackingConfig } from '../instrumentations/session';
import { defaultMetas } from '../metas';
import { browserMeta } from '../metas';
import { k6Meta } from '../metas/k6';
import { createPageMeta } from '../metas/page';
import { FetchTransport } from '../transports';

import { getWebInstrumentations } from './getWebInstrumentations';
import type { BrowserConfig } from './types';

export function makeCoreConfig(browserConfig: BrowserConfig): Config | undefined {
export function makeCoreConfig(browserConfig: BrowserConfig): Config {
const transports: Transport[] = [];

const internalLogger = createInternalLogger(browserConfig.unpatchedConsole, browserConfig.internalLoggerLevel);
Expand All @@ -41,58 +42,80 @@ export function makeCoreConfig(browserConfig: BrowserConfig): Config | undefined
internalLogger.error('either "url" or "transports" must be defined');
}

function createMetas(): MetaItem[] {
const initialMetas = defaultMetas;

if (browserConfig.metas) {
initialMetas.push(...browserConfig.metas);
}

const isK6BrowserSession = isObject((window as any).k6);

if (isK6BrowserSession) {
return [...initialMetas, k6Meta];
}

return initialMetas;
}

const config: Config = {
app: browserConfig.app,
const {
app,
batching,
beforeSend,
consoleInstrumentation,
ignoreErrors,
sessionTracking,
trackResources,
trackWebVitalsAttribution,
user,
view,

// properties with default values
dedupe = true,
eventDomain = defaultEventDomain,
globalObjectKey = defaultGlobalObjectKey,
instrumentations = getWebInstrumentations(),
internalLoggerLevel = defaultInternalLoggerLevel,
isolate = false,
logArgsSerializer = defaultLogArgsSerializer,
metas = createDefaultMetas(browserConfig),
paused = false,
preventGlobalExposure = false,
unpatchedConsole = defaultUnpatchedConsole,
}: BrowserConfig = browserConfig;

return {
app,
batching: {
...defaultBatchingConfig,
...browserConfig.batching,
...batching,
},
dedupe: browserConfig.dedupe ?? true,
globalObjectKey: browserConfig.globalObjectKey || defaultGlobalObjectKey,
instrumentations: browserConfig.instrumentations ?? getWebInstrumentations(),
internalLoggerLevel: browserConfig.internalLoggerLevel ?? defaultInternalLoggerLevel,
isolate: browserConfig.isolate ?? false,
logArgsSerializer: browserConfig.logArgsSerializer ?? defaultLogArgsSerializer,
metas: createMetas(),
dedupe: dedupe,
globalObjectKey,
instrumentations,
internalLoggerLevel,
isolate,
logArgsSerializer,
metas,
parseStacktrace,
paused: browserConfig.paused ?? false,
preventGlobalExposure: browserConfig.preventGlobalExposure ?? false,
paused,
preventGlobalExposure,
transports,
unpatchedConsole: browserConfig.unpatchedConsole ?? defaultUnpatchedConsole,

beforeSend: browserConfig.beforeSend,
eventDomain: browserConfig.eventDomain ?? defaultEventDomain,
ignoreErrors: browserConfig.ignoreErrors,
unpatchedConsole,
beforeSend,
eventDomain,
ignoreErrors,
// ignore cloud collector urls by default. These are URLs ending with /collect or /collect/ followed by alphanumeric characters.
ignoreUrls: (browserConfig.ignoreUrls ?? []).concat([/\/collect(?:\/[\w]*)?$/]),

sessionTracking: {
...defaultSessionTrackingConfig,
...browserConfig.sessionTracking,
...sessionTracking,
},

user: browserConfig.user,
view: browserConfig.view,
trackResources: browserConfig.trackResources,
trackWebVitalsAttribution: browserConfig.trackWebVitalsAttribution,
consoleInstrumentation: browserConfig.consoleInstrumentation,
user,
view,
trackResources,
trackWebVitalsAttribution,
consoleInstrumentation,
};
}

function createDefaultMetas(browserConfig: BrowserConfig): MetaItem[] {
const { page, generatePageId } = browserConfig?.pageTracking ?? {};

const initialMetas: MetaItem[] = [
browserMeta,
createPageMeta({ generatePageId, initialPageMeta: page }),
...(browserConfig.metas ?? []),
];

const isK6BrowserSession = isObject((window as any).k6);
if (isK6BrowserSession) {
return [...initialMetas, k6Meta];
}

return config;
return initialMetas;
}
2 changes: 1 addition & 1 deletion packages/web-sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export {
} from './instrumentations';
export type { ConsoleInstrumentationOptions, ErrorEvent, ExtendedPromiseRejectionEvent } from './instrumentations';

export { browserMeta, createSession, defaultMetas, pageMeta, sdkMeta } from './metas';
export { browserMeta, createSession, sdkMeta } from './metas';

export { ConsoleTransport, FetchTransport } from './transports';
export type {
Expand Down
6 changes: 0 additions & 6 deletions packages/web-sdk/src/metas/const.ts

This file was deleted.

4 changes: 0 additions & 4 deletions packages/web-sdk/src/metas/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
export { browserMeta } from './browser';

export { defaultMetas } from './const';

export { pageMeta } from './page';

export { createSession } from './session';

export { sdkMeta } from './sdk';
2 changes: 1 addition & 1 deletion packages/web-sdk/src/metas/page/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { pageMeta } from './meta';
export { createPageMeta } from './meta';
Loading

0 comments on commit 1b5cc70

Please sign in to comment.