UNPKG

@grafana/faro-web-sdk

Version:

Faro instrumentations, metas, transports for web.

108 lines 7.02 kB
import { BaseInstrumentation, dateNow, EVENT_SESSION_EXTEND, EVENT_SESSION_RESUME, EVENT_SESSION_START, VERSION, } from '@grafana/faro-core'; import { createSession } from '../../metas'; import { getSessionManagerByConfig, isSampled } from './sessionManager'; import { PersistentSessionsManager } from './sessionManager/PersistentSessionsManager'; import { createUserSessionObject, isUserSessionValid } from './sessionManager/sessionManagerUtils'; export class SessionInstrumentation extends BaseInstrumentation { constructor() { super(...arguments); this.name = '@grafana/faro-web-sdk:instrumentation-session'; this.version = VERSION; } sendSessionStartEvent(meta) { var _a, _b; const session = meta.session; if (session && session.id !== ((_a = this.notifiedSession) === null || _a === void 0 ? void 0 : _a.id)) { if (this.notifiedSession && this.notifiedSession.id === ((_b = session.attributes) === null || _b === void 0 ? void 0 : _b['previousSession'])) { this.api.pushEvent(EVENT_SESSION_EXTEND, {}, undefined, { skipDedupe: true }); this.notifiedSession = session; return; } this.notifiedSession = session; // no need to add attributes and session id, they are included as part of meta // automatically this.api.pushEvent(EVENT_SESSION_START, {}, undefined, { skipDedupe: true }); } } createInitialSession(SessionManager, sessionsConfig) { var _a, _b, _c, _d, _e, _f; let storedUserSession = SessionManager.fetchUserSession(); if (sessionsConfig.persistent && sessionsConfig.maxSessionPersistenceTime && storedUserSession) { const now = dateNow(); const shouldClearPersistentSession = storedUserSession.lastActivity < now - sessionsConfig.maxSessionPersistenceTime; if (shouldClearPersistentSession) { PersistentSessionsManager.removeUserSession(); storedUserSession = null; } } let lifecycleType; let initialSession; if (isUserSessionValid(storedUserSession)) { const sessionId = storedUserSession === null || storedUserSession === void 0 ? void 0 : storedUserSession.sessionId; initialSession = createUserSessionObject({ sessionId, isSampled: storedUserSession.isSampled || false, started: storedUserSession === null || storedUserSession === void 0 ? void 0 : storedUserSession.started, }); const storedUserSessionMeta = storedUserSession === null || storedUserSession === void 0 ? void 0 : storedUserSession.sessionMeta; // For resumed sessions we want to merge the previous overrides with the configured ones. // If the same key is present in both, the new one will override the old one. const overrides = Object.assign(Object.assign({}, (_a = sessionsConfig.session) === null || _a === void 0 ? void 0 : _a.overrides), storedUserSessionMeta === null || storedUserSessionMeta === void 0 ? void 0 : storedUserSessionMeta.overrides); initialSession.sessionMeta = Object.assign(Object.assign({}, sessionsConfig.session), { id: sessionId, attributes: Object.assign(Object.assign(Object.assign({}, (_b = sessionsConfig.session) === null || _b === void 0 ? void 0 : _b.attributes), storedUserSessionMeta === null || storedUserSessionMeta === void 0 ? void 0 : storedUserSessionMeta.attributes), { // For valid resumed sessions we do not want to recalculate the sampling decision on each init phase. isSampled: initialSession.isSampled.toString() }), overrides }); lifecycleType = EVENT_SESSION_RESUME; } else { const sessionId = (_d = (_c = sessionsConfig.session) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : createSession().id; initialSession = createUserSessionObject({ sessionId, isSampled: isSampled(), }); const overrides = (_e = sessionsConfig.session) === null || _e === void 0 ? void 0 : _e.overrides; initialSession.sessionMeta = Object.assign({ id: sessionId, attributes: Object.assign({ isSampled: initialSession.isSampled.toString() }, (_f = sessionsConfig.session) === null || _f === void 0 ? void 0 : _f.attributes) }, (overrides ? { overrides } : {})); lifecycleType = EVENT_SESSION_START; } return { initialSession, lifecycleType }; } registerBeforeSendHook(SessionManager) { var _a; const { updateSession } = new SessionManager(); (_a = this.transports) === null || _a === void 0 ? void 0 : _a.addBeforeSendHooks((item) => { var _a, _b, _c; updateSession(); const attributes = (_a = item.meta.session) === null || _a === void 0 ? void 0 : _a.attributes; if (attributes && (attributes === null || attributes === void 0 ? void 0 : attributes['isSampled']) === 'true') { let newItem = JSON.parse(JSON.stringify(item)); const newAttributes = (_b = newItem.meta.session) === null || _b === void 0 ? void 0 : _b.attributes; newAttributes === null || newAttributes === void 0 ? true : delete newAttributes['isSampled']; if (Object.keys(newAttributes !== null && newAttributes !== void 0 ? newAttributes : {}).length === 0) { (_c = newItem.meta.session) === null || _c === void 0 ? true : delete _c.attributes; } return newItem; } return null; }); } initialize() { this.logDebug('init session instrumentation'); const sessionTrackingConfig = this.config.sessionTracking; if (sessionTrackingConfig === null || sessionTrackingConfig === void 0 ? void 0 : sessionTrackingConfig.enabled) { const SessionManager = getSessionManagerByConfig(sessionTrackingConfig); this.registerBeforeSendHook(SessionManager); const { initialSession, lifecycleType } = this.createInitialSession(SessionManager, sessionTrackingConfig); SessionManager.storeUserSession(initialSession); const initialSessionMeta = initialSession.sessionMeta; this.notifiedSession = initialSessionMeta; this.api.setSession(initialSessionMeta); if (lifecycleType === EVENT_SESSION_START) { this.api.pushEvent(EVENT_SESSION_START, {}, undefined, { skipDedupe: true }); } if (lifecycleType === EVENT_SESSION_RESUME) { this.api.pushEvent(EVENT_SESSION_RESUME, {}, undefined, { skipDedupe: true }); } } this.metas.addListener(this.sendSessionStartEvent.bind(this)); } } //# sourceMappingURL=instrumentation.js.map