UNPKG

@grafana/faro-web-sdk

Version:

Faro instrumentations, metas, transports for web.

113 lines 4.27 kB
import { Observable } from '@grafana/faro-core'; import { MESSAGE_TYPE_HTTP_REQUEST_END, MESSAGE_TYPE_HTTP_REQUEST_START } from './monitors/const'; export function isRequestStartMessage(msg) { return msg.type === MESSAGE_TYPE_HTTP_REQUEST_START; } export function isRequestEndMessage(msg) { return msg.type === MESSAGE_TYPE_HTTP_REQUEST_END; } /** * Tracks events in a time‑boxed activity window. When the window goes quiet for `inactivityMs`, * it enters a draining phase: new short events are ignored; only active operations are awaited * until they end or `drainTimeoutMs` elapses. */ export class ActivityWindowTracker extends Observable { constructor(eventsObservable, options) { var _a, _b, _c, _d; super(); this._tracking = false; this.eventsObservable = eventsObservable; this._options = { inactivityMs: (_a = options === null || options === void 0 ? void 0 : options.inactivityMs) !== null && _a !== void 0 ? _a : 100, drainTimeoutMs: (_b = options === null || options === void 0 ? void 0 : options.drainTimeoutMs) !== null && _b !== void 0 ? _b : 10 * 1000, isOperationStart: (_c = options === null || options === void 0 ? void 0 : options.isOperationStart) !== null && _c !== void 0 ? _c : (() => undefined), isOperationEnd: (_d = options === null || options === void 0 ? void 0 : options.isOperationEnd) !== null && _d !== void 0 ? _d : (() => undefined), }; this._initialize(); } _initialize() { this.eventsObservable .filter(() => { return this._tracking; }) .subscribe((event) => { var _a, _b, _c; this._lastEventTime = Date.now(); (_a = this._currentEvents) === null || _a === void 0 ? void 0 : _a.push(event); const startKey = this._options.isOperationStart(event); if (startKey) { (_b = this._activeOperations) === null || _b === void 0 ? void 0 : _b.set(startKey, true); } const endKey = this._options.isOperationEnd(event); if (endKey) { (_c = this._activeOperations) === null || _c === void 0 ? void 0 : _c.delete(endKey); } this._scheduleInactivityCheck(); }); } startTracking() { if (this._tracking) { return; } this._tracking = true; this._startTime = Date.now(); this._lastEventTime = Date.now(); this.notify({ message: 'tracking-started', }); this._currentEvents = []; this._activeOperations = new Map(); this._scheduleInactivityCheck(); } stopTracking() { this._tracking = false; this._clearTimer(this._inactivityTid); this._clearTimer(this._drainTid); let duration = 0; if (this.hasActiveOperations()) { duration = Date.now() - this._startTime; } else { duration = this._lastEventTime ? this._lastEventTime - this._startTime : 0; } this.notify({ message: 'tracking-ended', events: this._currentEvents, duration: duration, }); } _scheduleInactivityCheck() { this._inactivityTid = startTimeout(this._inactivityTid, () => { if (this.hasActiveOperations()) { this._startDrainTimeout(); } else { this.stopTracking(); } }, this._options.inactivityMs); } _startDrainTimeout() { this._drainTid = startTimeout(this._drainTid, () => { this.stopTracking(); }, this._options.drainTimeoutMs); } hasActiveOperations() { return !!this._activeOperations && this._activeOperations.size > 0; } _clearTimer(id) { if (id) { clearTimeout(id); } } } function startTimeout(timeoutId, cb, delay) { if (timeoutId) { clearTimeout(timeoutId); } //@ts-expect-error for some reason vscode is using the node types timeoutId = setTimeout(() => { cb(); }, delay); return timeoutId; } //# sourceMappingURL=activityWindowTracker.js.map