@datadog/browser-rum-core
Advanced tools
Comparing version
@@ -6,4 +6,4 @@ "use strict"; | ||
buildMode: 'release', | ||
sdkVersion: '3.6.0', | ||
sdkVersion: '3.6.1', | ||
}; | ||
//# sourceMappingURL=buildEnv.js.map |
@@ -1,5 +0,6 @@ | ||
import { Configuration, InternalMonitoring } from '@datadog/browser-core'; | ||
import { Configuration, InternalMonitoring, Observable } from '@datadog/browser-core'; | ||
import { LifeCycle } from '../domain/lifeCycle'; | ||
import { RumSession } from '../domain/rumSession'; | ||
import { CommonContext } from '../rawRumEvent.types'; | ||
import { LocationChange } from '../browser/locationChangeObservable'; | ||
import { RecorderApi, RumInitConfiguration } from './rumPublicApi'; | ||
@@ -16,6 +17,10 @@ export declare function startRum(initConfiguration: RumInitConfiguration, configuration: Configuration, internalMonitoring: InternalMonitoring, getCommonContext: () => CommonContext, recorderApi: RecorderApi, initialViewName?: string): { | ||
}; | ||
export declare function startRumEventCollection(applicationId: string, lifeCycle: LifeCycle, configuration: Configuration, session: RumSession, getCommonContext: () => CommonContext): { | ||
export declare function startRumEventCollection(applicationId: string, lifeCycle: LifeCycle, configuration: Configuration, location: Location, session: RumSession, locationChangeObservable: Observable<LocationChange>, getCommonContext: () => CommonContext): { | ||
parentContexts: import("../domain/parentContexts").ParentContexts; | ||
foregroundContexts: import("../domain/foregroundContexts").ForegroundContexts; | ||
urlContexts: { | ||
findUrl: (startTime?: import("@datadog/browser-core").RelativeTime | undefined) => import("../rawRumEvent.types").UrlContext | undefined; | ||
stop: () => void; | ||
}; | ||
stop: () => void; | ||
}; |
@@ -20,2 +20,3 @@ "use strict"; | ||
var batch_1 = require("../transport/batch"); | ||
var urlContexts_1 = require("../domain/urlContexts"); | ||
var locationChangeObservable_1 = require("../browser/locationChangeObservable"); | ||
@@ -32,3 +33,3 @@ function startRum(initConfiguration, configuration, internalMonitoring, getCommonContext, recorderApi, initialViewName) { | ||
}); | ||
var _a = startRumEventCollection(initConfiguration.applicationId, lifeCycle, configuration, session, getCommonContext), parentContexts = _a.parentContexts, foregroundContexts = _a.foregroundContexts; | ||
var _a = startRumEventCollection(initConfiguration.applicationId, lifeCycle, configuration, location, session, locationChangeObservable, getCommonContext), parentContexts = _a.parentContexts, foregroundContexts = _a.foregroundContexts, urlContexts = _a.urlContexts; | ||
if (session.hasReplayPlan()) { | ||
@@ -43,3 +44,3 @@ longTaskCollection_1.startLongTaskCollection(lifeCycle); | ||
performanceCollection_1.startPerformanceCollection(lifeCycle, configuration); | ||
var internalContext = internalContext_1.startInternalContext(initConfiguration.applicationId, session, parentContexts); | ||
var internalContext = internalContext_1.startInternalContext(initConfiguration.applicationId, session, parentContexts, urlContexts); | ||
return { | ||
@@ -57,10 +58,12 @@ addAction: addAction, | ||
exports.startRum = startRum; | ||
function startRumEventCollection(applicationId, lifeCycle, configuration, session, getCommonContext) { | ||
function startRumEventCollection(applicationId, lifeCycle, configuration, location, session, locationChangeObservable, getCommonContext) { | ||
var parentContexts = parentContexts_1.startParentContexts(lifeCycle, session); | ||
var urlContexts = urlContexts_1.startUrlContexts(lifeCycle, locationChangeObservable, location); | ||
var foregroundContexts = foregroundContexts_1.startForegroundContexts(); | ||
var batch = batch_1.startRumBatch(configuration, lifeCycle); | ||
assembly_1.startRumAssembly(applicationId, configuration, lifeCycle, session, parentContexts, getCommonContext); | ||
assembly_1.startRumAssembly(applicationId, configuration, lifeCycle, session, parentContexts, urlContexts, getCommonContext); | ||
return { | ||
parentContexts: parentContexts, | ||
foregroundContexts: foregroundContexts, | ||
urlContexts: urlContexts, | ||
stop: function () { | ||
@@ -67,0 +70,0 @@ // prevent batch from previous tests to keep running and send unwanted requests |
@@ -6,2 +6,3 @@ import { Configuration } from '@datadog/browser-core'; | ||
import { RumSession } from './rumSession'; | ||
import { UrlContexts } from './urlContexts'; | ||
export interface BrowserWindow extends Window { | ||
@@ -11,2 +12,2 @@ _DATADOG_SYNTHETICS_PUBLIC_ID?: string; | ||
} | ||
export declare function startRumAssembly(applicationId: string, configuration: Configuration, lifeCycle: LifeCycle, session: RumSession, parentContexts: ParentContexts, getCommonContext: () => CommonContext): void; | ||
export declare function startRumAssembly(applicationId: string, configuration: Configuration, lifeCycle: LifeCycle, session: RumSession, parentContexts: ParentContexts, urlContexts: UrlContexts, getCommonContext: () => CommonContext): void; |
@@ -28,3 +28,3 @@ "use strict"; | ||
]); | ||
function startRumAssembly(applicationId, configuration, lifeCycle, session, parentContexts, getCommonContext) { | ||
function startRumAssembly(applicationId, configuration, lifeCycle, session, parentContexts, urlContexts, getCommonContext) { | ||
var _a; | ||
@@ -39,5 +39,7 @@ var reportError = function (error) { | ||
lifeCycle.subscribe(lifeCycle_1.LifeCycleEventType.RAW_RUM_EVENT_COLLECTED, function (_a) { | ||
var _b; | ||
var startTime = _a.startTime, rawRumEvent = _a.rawRumEvent, domainContext = _a.domainContext, savedCommonContext = _a.savedCommonContext, customerContext = _a.customerContext; | ||
var viewContext = parentContexts.findView(startTime); | ||
if (session.isTracked() && viewContext && viewContext.session.id === session.getId()) { | ||
var urlContext = urlContexts.findUrl(startTime); | ||
if (session.isTracked() && viewContext && urlContext && viewContext.session.id === session.getId()) { | ||
var actionContext = parentContexts.findAction(startTime); | ||
@@ -65,4 +67,4 @@ var commonContext = savedCommonContext || getCommonContext(); | ||
var serverRumEvent = (needToAssembleWithAction(rawRumEvent) | ||
? browser_core_1.combine(rumContext, viewContext, actionContext, rawRumEvent) | ||
: browser_core_1.combine(rumContext, viewContext, rawRumEvent)); | ||
? browser_core_1.combine(rumContext, urlContext, viewContext, actionContext, rawRumEvent) | ||
: browser_core_1.combine(rumContext, urlContext, viewContext, rawRumEvent)); | ||
serverRumEvent.context = browser_core_1.combine(commonContext.context, customerContext); | ||
@@ -93,2 +95,14 @@ if (!('has_replay' in serverRumEvent.session)) { | ||
} | ||
if (serverRumEvent.session.has_replay && ((_b = serverRumEvent._dd.session) === null || _b === void 0 ? void 0 : _b.plan) === rumSession_1.RumSessionPlan.LITE) { | ||
browser_core_1.addMonitoringMessage('lite session with replay', { | ||
debug: { | ||
eventType: serverRumEvent.type, | ||
viewId: serverRumEvent.view.id, | ||
sessionId: serverRumEvent.session.id, | ||
replayPlan: session.hasReplayPlan(), | ||
litePlan: session.hasLitePlan(), | ||
docVersion: serverRumEvent._dd.document_version, | ||
}, | ||
}); | ||
} | ||
lifeCycle.notify(lifeCycle_1.LifeCycleEventType.RUM_EVENT_COLLECTED, serverRumEvent); | ||
@@ -95,0 +109,0 @@ } |
import { RelativeTime } from '@datadog/browser-core'; | ||
export declare const CLEAR_OLD_CONTEXTS_INTERVAL: number; | ||
export declare class ContextHistory<Raw, Built> { | ||
private buildContext; | ||
export declare class ContextHistory<Context> { | ||
private expireDelay; | ||
@@ -10,6 +9,6 @@ private current; | ||
private clearOldContextsInterval; | ||
constructor(buildContext: (r: Raw) => Built, expireDelay: number); | ||
find(startTime?: RelativeTime): Built | undefined; | ||
setCurrent(current: Raw, startTime: RelativeTime): void; | ||
getCurrent(): Raw | undefined; | ||
constructor(expireDelay: number); | ||
find(startTime?: RelativeTime): Context | undefined; | ||
setCurrent(current: Context, startTime: RelativeTime): void; | ||
getCurrent(): Context | undefined; | ||
clearCurrent(): void; | ||
@@ -16,0 +15,0 @@ closeCurrent(endTime: RelativeTime): void; |
@@ -7,5 +7,4 @@ "use strict"; | ||
var ContextHistory = /** @class */ (function () { | ||
function ContextHistory(buildContext, expireDelay) { | ||
function ContextHistory(expireDelay) { | ||
var _this = this; | ||
this.buildContext = buildContext; | ||
this.expireDelay = expireDelay; | ||
@@ -16,8 +15,6 @@ this.previousContexts = []; | ||
ContextHistory.prototype.find = function (startTime) { | ||
if (startTime === undefined) { | ||
return this.current ? this.buildContext(this.current) : undefined; | ||
if (startTime === undefined || | ||
(this.current !== undefined && this.currentStart !== undefined && startTime >= this.currentStart)) { | ||
return this.current; | ||
} | ||
if (this.current !== undefined && this.currentStart !== undefined && startTime >= this.currentStart) { | ||
return this.buildContext(this.current); | ||
} | ||
for (var _i = 0, _a = this.previousContexts; _i < _a.length; _i++) { | ||
@@ -49,3 +46,3 @@ var previousContext = _a[_i]; | ||
endTime: endTime, | ||
context: this.buildContext(this.current), | ||
context: this.current, | ||
startTime: this.currentStart, | ||
@@ -52,0 +49,0 @@ }); |
import { InternalContext } from '../rawRumEvent.types'; | ||
import { ParentContexts } from './parentContexts'; | ||
import { RumSession } from './rumSession'; | ||
import { UrlContexts } from './urlContexts'; | ||
/** | ||
@@ -8,4 +9,4 @@ * Internal context keep returning v1 format | ||
*/ | ||
export declare function startInternalContext(applicationId: string, session: RumSession, parentContexts: ParentContexts): { | ||
export declare function startInternalContext(applicationId: string, session: RumSession, parentContexts: ParentContexts, urlContexts: UrlContexts): { | ||
get: (startTime?: number | undefined) => InternalContext | undefined; | ||
}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.startInternalContext = void 0; | ||
var tslib_1 = require("tslib"); | ||
/** | ||
@@ -8,7 +9,8 @@ * Internal context keep returning v1 format | ||
*/ | ||
function startInternalContext(applicationId, session, parentContexts) { | ||
function startInternalContext(applicationId, session, parentContexts, urlContexts) { | ||
return { | ||
get: function (startTime) { | ||
var viewContext = parentContexts.findView(startTime); | ||
if (session.isTracked() && viewContext && viewContext.session.id) { | ||
var urlContext = urlContexts.findUrl(startTime); | ||
if (session.isTracked() && viewContext && urlContext && viewContext.session.id) { | ||
var actionContext = parentContexts.findAction(startTime); | ||
@@ -23,3 +25,3 @@ return { | ||
: undefined, | ||
view: viewContext.view, | ||
view: tslib_1.__assign(tslib_1.__assign({}, viewContext.view), urlContext.view), | ||
}; | ||
@@ -26,0 +28,0 @@ } |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.startParentContexts = exports.ACTION_CONTEXT_TIME_OUT_DELAY = exports.VIEW_CONTEXT_TIME_OUT_DELAY = void 0; | ||
var tslib_1 = require("tslib"); | ||
var browser_core_1 = require("@datadog/browser-core"); | ||
@@ -11,6 +10,6 @@ var lifeCycle_1 = require("./lifeCycle"); | ||
function startParentContexts(lifeCycle, session) { | ||
var viewContextHistory = new contextHistory_1.ContextHistory(buildCurrentViewContext, exports.VIEW_CONTEXT_TIME_OUT_DELAY); | ||
var actionContextHistory = new contextHistory_1.ContextHistory(buildCurrentActionContext, exports.ACTION_CONTEXT_TIME_OUT_DELAY); | ||
var viewContextHistory = new contextHistory_1.ContextHistory(exports.VIEW_CONTEXT_TIME_OUT_DELAY); | ||
var actionContextHistory = new contextHistory_1.ContextHistory(exports.ACTION_CONTEXT_TIME_OUT_DELAY); | ||
lifeCycle.subscribe(lifeCycle_1.LifeCycleEventType.VIEW_CREATED, function (view) { | ||
viewContextHistory.setCurrent(tslib_1.__assign({ sessionId: session.getId() }, view), view.startClocks.relative); | ||
viewContextHistory.setCurrent(buildViewContext(view, session.getId()), view.startClocks.relative); | ||
}); | ||
@@ -21,4 +20,4 @@ lifeCycle.subscribe(lifeCycle_1.LifeCycleEventType.VIEW_UPDATED, function (view) { | ||
var current = viewContextHistory.getCurrent(); | ||
if (current && current.id === view.id) { | ||
viewContextHistory.setCurrent(tslib_1.__assign({ sessionId: current.sessionId }, view), view.startClocks.relative); | ||
if (current && current.view.id === view.id) { | ||
viewContextHistory.setCurrent(buildViewContext(view, current.session.id), view.startClocks.relative); | ||
} | ||
@@ -31,3 +30,3 @@ }); | ||
lifeCycle.subscribe(lifeCycle_1.LifeCycleEventType.AUTO_ACTION_CREATED, function (action) { | ||
actionContextHistory.setCurrent(action, action.startClocks.relative); | ||
actionContextHistory.setCurrent(buildActionContext(action), action.startClocks.relative); | ||
}); | ||
@@ -48,17 +47,15 @@ lifeCycle.subscribe(lifeCycle_1.LifeCycleEventType.AUTO_ACTION_COMPLETED, function (action) { | ||
}); | ||
function buildCurrentViewContext(current) { | ||
function buildViewContext(view, sessionId) { | ||
return { | ||
session: { | ||
id: current.sessionId, | ||
id: sessionId, | ||
}, | ||
view: { | ||
id: current.id, | ||
name: current.name, | ||
referrer: current.referrer, | ||
url: current.location.href, | ||
id: view.id, | ||
name: view.name, | ||
}, | ||
}; | ||
} | ||
function buildCurrentActionContext(current) { | ||
return { action: { id: current.id } }; | ||
function buildActionContext(action) { | ||
return { action: { id: action.id } }; | ||
} | ||
@@ -65,0 +62,0 @@ return { |
@@ -11,3 +11,2 @@ import { Duration, ClocksState, TimeStamp, Observable } from '@datadog/browser-core'; | ||
location: Readonly<Location>; | ||
referrer: string; | ||
timings: Timings; | ||
@@ -27,4 +26,2 @@ customTimings: ViewCustomTimings; | ||
name?: string; | ||
location: Location; | ||
referrer: string; | ||
startClocks: ClocksState; | ||
@@ -31,0 +28,0 @@ } |
@@ -16,7 +16,8 @@ "use strict"; | ||
var stopViewLifeCycle = startViewLifeCycle().stop; | ||
var stopViewCollectionMode = (areViewsTrackedAutomatically | ||
? startAutomaticViewCollection(locationChangeObservable) | ||
: startManualViewCollection(locationChangeObservable)).unsubscribe; | ||
var locationChangeSubscription; | ||
if (areViewsTrackedAutomatically) { | ||
locationChangeSubscription = renewViewOnLocationChange(locationChangeObservable); | ||
} | ||
function trackInitialView(name) { | ||
var initialView = newView(lifeCycle, domMutationObservable, location, rawRumEvent_types_1.ViewLoadingType.INITIAL_LOAD, document.referrer, browser_core_1.clocksOrigin(), name); | ||
var initialView = newView(lifeCycle, domMutationObservable, location, rawRumEvent_types_1.ViewLoadingType.INITIAL_LOAD, browser_core_1.clocksOrigin(), name); | ||
var stop = trackInitialViewTimings_1.trackInitialViewTimings(lifeCycle, function (timings) { | ||
@@ -29,3 +30,3 @@ initialView.updateTimings(timings); | ||
function trackViewChange(startClocks, name) { | ||
return newView(lifeCycle, domMutationObservable, location, rawRumEvent_types_1.ViewLoadingType.ROUTE_CHANGE, currentView.url, startClocks, name); | ||
return newView(lifeCycle, domMutationObservable, location, rawRumEvent_types_1.ViewLoadingType.ROUTE_CHANGE, startClocks, name); | ||
} | ||
@@ -54,7 +55,6 @@ function startViewLifeCycle() { | ||
} | ||
function startAutomaticViewCollection(locationChangeObservable) { | ||
function renewViewOnLocationChange(locationChangeObservable) { | ||
return locationChangeObservable.subscribe(function (_a) { | ||
var oldLocation = _a.oldLocation, newLocation = _a.newLocation; | ||
if (areDifferentLocation(oldLocation, newLocation)) { | ||
// Renew view on location changes | ||
currentView.end(); | ||
@@ -65,13 +65,4 @@ currentView.triggerUpdate(); | ||
} | ||
currentView.updateLocation(newLocation); | ||
currentView.triggerUpdate(); | ||
}); | ||
} | ||
function startManualViewCollection(locationChangeObservable) { | ||
return locationChangeObservable.subscribe(function (_a) { | ||
var newLocation = _a.newLocation; | ||
currentView.updateLocation(newLocation); | ||
currentView.triggerUpdate(); | ||
}); | ||
} | ||
return { | ||
@@ -89,3 +80,3 @@ addTiming: function (name, time) { | ||
stop: function () { | ||
stopViewCollectionMode(); | ||
locationChangeSubscription === null || locationChangeSubscription === void 0 ? void 0 : locationChangeSubscription.unsubscribe(); | ||
stopInitialViewTracking(); | ||
@@ -98,3 +89,3 @@ stopViewLifeCycle(); | ||
exports.trackViews = trackViews; | ||
function newView(lifeCycle, domMutationObservable, initialLocation, loadingType, referrer, startClocks, name) { | ||
function newView(lifeCycle, domMutationObservable, initialLocation, loadingType, startClocks, name) { | ||
if (startClocks === void 0) { startClocks = browser_core_1.clocksNow(); } | ||
@@ -108,3 +99,3 @@ // Setup initial values | ||
var location = tslib_1.__assign({}, initialLocation); | ||
lifeCycle.notify(lifeCycle_1.LifeCycleEventType.VIEW_CREATED, { id: id, name: name, startClocks: startClocks, location: location, referrer: referrer }); | ||
lifeCycle.notify(lifeCycle_1.LifeCycleEventType.VIEW_CREATED, { id: id, name: name, startClocks: startClocks }); | ||
// Update the view every time the measures are changing | ||
@@ -126,3 +117,2 @@ var _a = browser_core_1.throttle(browser_core_1.monitor(triggerViewUpdate), exports.THROTTLE_VIEW_UPDATE_PERIOD, { | ||
location: location, | ||
referrer: referrer, | ||
startClocks: startClocks, | ||
@@ -140,5 +130,2 @@ timings: timings, duration: browser_core_1.elapsed(startClocks.timeStamp, currentEnd), isActive: endClocks === undefined })); | ||
}, | ||
getLocation: function () { | ||
return location; | ||
}, | ||
triggerUpdate: function () { | ||
@@ -158,8 +145,2 @@ // cancel any pending view updates execution | ||
}, | ||
updateLocation: function (newLocation) { | ||
location = tslib_1.__assign({}, newLocation); | ||
}, | ||
get url() { | ||
return location.href; | ||
}, | ||
}; | ||
@@ -166,0 +147,0 @@ } |
@@ -173,4 +173,2 @@ import { Context, Duration, ErrorSource, ErrorHandling, ResourceType, ServerDuration, TimeStamp } from '@datadog/browser-core'; | ||
name?: string; | ||
url: string; | ||
referrer: string; | ||
}; | ||
@@ -183,2 +181,8 @@ } | ||
} | ||
export interface UrlContext extends Context { | ||
view: { | ||
url: string; | ||
referrer: string; | ||
}; | ||
} | ||
export interface InternalContext { | ||
@@ -185,0 +189,0 @@ application_id: string; |
export var buildEnv = { | ||
buildMode: 'release', | ||
sdkVersion: '3.6.0', | ||
sdkVersion: '3.6.1', | ||
}; | ||
//# sourceMappingURL=buildEnv.js.map |
@@ -1,5 +0,6 @@ | ||
import { Configuration, InternalMonitoring } from '@datadog/browser-core'; | ||
import { Configuration, InternalMonitoring, Observable } from '@datadog/browser-core'; | ||
import { LifeCycle } from '../domain/lifeCycle'; | ||
import { RumSession } from '../domain/rumSession'; | ||
import { CommonContext } from '../rawRumEvent.types'; | ||
import { LocationChange } from '../browser/locationChangeObservable'; | ||
import { RecorderApi, RumInitConfiguration } from './rumPublicApi'; | ||
@@ -16,6 +17,10 @@ export declare function startRum(initConfiguration: RumInitConfiguration, configuration: Configuration, internalMonitoring: InternalMonitoring, getCommonContext: () => CommonContext, recorderApi: RecorderApi, initialViewName?: string): { | ||
}; | ||
export declare function startRumEventCollection(applicationId: string, lifeCycle: LifeCycle, configuration: Configuration, session: RumSession, getCommonContext: () => CommonContext): { | ||
export declare function startRumEventCollection(applicationId: string, lifeCycle: LifeCycle, configuration: Configuration, location: Location, session: RumSession, locationChangeObservable: Observable<LocationChange>, getCommonContext: () => CommonContext): { | ||
parentContexts: import("../domain/parentContexts").ParentContexts; | ||
foregroundContexts: import("../domain/foregroundContexts").ForegroundContexts; | ||
urlContexts: { | ||
findUrl: (startTime?: import("@datadog/browser-core").RelativeTime | undefined) => import("../rawRumEvent.types").UrlContext | undefined; | ||
stop: () => void; | ||
}; | ||
stop: () => void; | ||
}; |
@@ -17,2 +17,3 @@ import { combine } from '@datadog/browser-core'; | ||
import { startRumBatch } from '../transport/batch'; | ||
import { startUrlContexts } from '../domain/urlContexts'; | ||
import { createLocationChangeObservable } from '../browser/locationChangeObservable'; | ||
@@ -29,3 +30,3 @@ export function startRum(initConfiguration, configuration, internalMonitoring, getCommonContext, recorderApi, initialViewName) { | ||
}); | ||
var _a = startRumEventCollection(initConfiguration.applicationId, lifeCycle, configuration, session, getCommonContext), parentContexts = _a.parentContexts, foregroundContexts = _a.foregroundContexts; | ||
var _a = startRumEventCollection(initConfiguration.applicationId, lifeCycle, configuration, location, session, locationChangeObservable, getCommonContext), parentContexts = _a.parentContexts, foregroundContexts = _a.foregroundContexts, urlContexts = _a.urlContexts; | ||
if (session.hasReplayPlan()) { | ||
@@ -40,3 +41,3 @@ startLongTaskCollection(lifeCycle); | ||
startPerformanceCollection(lifeCycle, configuration); | ||
var internalContext = startInternalContext(initConfiguration.applicationId, session, parentContexts); | ||
var internalContext = startInternalContext(initConfiguration.applicationId, session, parentContexts, urlContexts); | ||
return { | ||
@@ -53,10 +54,12 @@ addAction: addAction, | ||
} | ||
export function startRumEventCollection(applicationId, lifeCycle, configuration, session, getCommonContext) { | ||
export function startRumEventCollection(applicationId, lifeCycle, configuration, location, session, locationChangeObservable, getCommonContext) { | ||
var parentContexts = startParentContexts(lifeCycle, session); | ||
var urlContexts = startUrlContexts(lifeCycle, locationChangeObservable, location); | ||
var foregroundContexts = startForegroundContexts(); | ||
var batch = startRumBatch(configuration, lifeCycle); | ||
startRumAssembly(applicationId, configuration, lifeCycle, session, parentContexts, getCommonContext); | ||
startRumAssembly(applicationId, configuration, lifeCycle, session, parentContexts, urlContexts, getCommonContext); | ||
return { | ||
parentContexts: parentContexts, | ||
foregroundContexts: foregroundContexts, | ||
urlContexts: urlContexts, | ||
stop: function () { | ||
@@ -63,0 +66,0 @@ // prevent batch from previous tests to keep running and send unwanted requests |
@@ -6,2 +6,3 @@ import { Configuration } from '@datadog/browser-core'; | ||
import { RumSession } from './rumSession'; | ||
import { UrlContexts } from './urlContexts'; | ||
export interface BrowserWindow extends Window { | ||
@@ -11,2 +12,2 @@ _DATADOG_SYNTHETICS_PUBLIC_ID?: string; | ||
} | ||
export declare function startRumAssembly(applicationId: string, configuration: Configuration, lifeCycle: LifeCycle, session: RumSession, parentContexts: ParentContexts, getCommonContext: () => CommonContext): void; | ||
export declare function startRumAssembly(applicationId: string, configuration: Configuration, lifeCycle: LifeCycle, session: RumSession, parentContexts: ParentContexts, urlContexts: UrlContexts, getCommonContext: () => CommonContext): void; |
@@ -25,3 +25,3 @@ import { __spreadArrays } from "tslib"; | ||
]); | ||
export function startRumAssembly(applicationId, configuration, lifeCycle, session, parentContexts, getCommonContext) { | ||
export function startRumAssembly(applicationId, configuration, lifeCycle, session, parentContexts, urlContexts, getCommonContext) { | ||
var _a; | ||
@@ -36,5 +36,7 @@ var reportError = function (error) { | ||
lifeCycle.subscribe(LifeCycleEventType.RAW_RUM_EVENT_COLLECTED, function (_a) { | ||
var _b; | ||
var startTime = _a.startTime, rawRumEvent = _a.rawRumEvent, domainContext = _a.domainContext, savedCommonContext = _a.savedCommonContext, customerContext = _a.customerContext; | ||
var viewContext = parentContexts.findView(startTime); | ||
if (session.isTracked() && viewContext && viewContext.session.id === session.getId()) { | ||
var urlContext = urlContexts.findUrl(startTime); | ||
if (session.isTracked() && viewContext && urlContext && viewContext.session.id === session.getId()) { | ||
var actionContext = parentContexts.findAction(startTime); | ||
@@ -62,4 +64,4 @@ var commonContext = savedCommonContext || getCommonContext(); | ||
var serverRumEvent = (needToAssembleWithAction(rawRumEvent) | ||
? combine(rumContext, viewContext, actionContext, rawRumEvent) | ||
: combine(rumContext, viewContext, rawRumEvent)); | ||
? combine(rumContext, urlContext, viewContext, actionContext, rawRumEvent) | ||
: combine(rumContext, urlContext, viewContext, rawRumEvent)); | ||
serverRumEvent.context = combine(commonContext.context, customerContext); | ||
@@ -90,2 +92,14 @@ if (!('has_replay' in serverRumEvent.session)) { | ||
} | ||
if (serverRumEvent.session.has_replay && ((_b = serverRumEvent._dd.session) === null || _b === void 0 ? void 0 : _b.plan) === RumSessionPlan.LITE) { | ||
addMonitoringMessage('lite session with replay', { | ||
debug: { | ||
eventType: serverRumEvent.type, | ||
viewId: serverRumEvent.view.id, | ||
sessionId: serverRumEvent.session.id, | ||
replayPlan: session.hasReplayPlan(), | ||
litePlan: session.hasLitePlan(), | ||
docVersion: serverRumEvent._dd.document_version, | ||
}, | ||
}); | ||
} | ||
lifeCycle.notify(LifeCycleEventType.RUM_EVENT_COLLECTED, serverRumEvent); | ||
@@ -92,0 +106,0 @@ } |
import { RelativeTime } from '@datadog/browser-core'; | ||
export declare const CLEAR_OLD_CONTEXTS_INTERVAL: number; | ||
export declare class ContextHistory<Raw, Built> { | ||
private buildContext; | ||
export declare class ContextHistory<Context> { | ||
private expireDelay; | ||
@@ -10,6 +9,6 @@ private current; | ||
private clearOldContextsInterval; | ||
constructor(buildContext: (r: Raw) => Built, expireDelay: number); | ||
find(startTime?: RelativeTime): Built | undefined; | ||
setCurrent(current: Raw, startTime: RelativeTime): void; | ||
getCurrent(): Raw | undefined; | ||
constructor(expireDelay: number); | ||
find(startTime?: RelativeTime): Context | undefined; | ||
setCurrent(current: Context, startTime: RelativeTime): void; | ||
getCurrent(): Context | undefined; | ||
clearCurrent(): void; | ||
@@ -16,0 +15,0 @@ closeCurrent(endTime: RelativeTime): void; |
import { ONE_MINUTE, relativeNow } from '@datadog/browser-core'; | ||
export var CLEAR_OLD_CONTEXTS_INTERVAL = ONE_MINUTE; | ||
var ContextHistory = /** @class */ (function () { | ||
function ContextHistory(buildContext, expireDelay) { | ||
function ContextHistory(expireDelay) { | ||
var _this = this; | ||
this.buildContext = buildContext; | ||
this.expireDelay = expireDelay; | ||
@@ -12,8 +11,6 @@ this.previousContexts = []; | ||
ContextHistory.prototype.find = function (startTime) { | ||
if (startTime === undefined) { | ||
return this.current ? this.buildContext(this.current) : undefined; | ||
if (startTime === undefined || | ||
(this.current !== undefined && this.currentStart !== undefined && startTime >= this.currentStart)) { | ||
return this.current; | ||
} | ||
if (this.current !== undefined && this.currentStart !== undefined && startTime >= this.currentStart) { | ||
return this.buildContext(this.current); | ||
} | ||
for (var _i = 0, _a = this.previousContexts; _i < _a.length; _i++) { | ||
@@ -45,3 +42,3 @@ var previousContext = _a[_i]; | ||
endTime: endTime, | ||
context: this.buildContext(this.current), | ||
context: this.current, | ||
startTime: this.currentStart, | ||
@@ -48,0 +45,0 @@ }); |
import { InternalContext } from '../rawRumEvent.types'; | ||
import { ParentContexts } from './parentContexts'; | ||
import { RumSession } from './rumSession'; | ||
import { UrlContexts } from './urlContexts'; | ||
/** | ||
@@ -8,4 +9,4 @@ * Internal context keep returning v1 format | ||
*/ | ||
export declare function startInternalContext(applicationId: string, session: RumSession, parentContexts: ParentContexts): { | ||
export declare function startInternalContext(applicationId: string, session: RumSession, parentContexts: ParentContexts, urlContexts: UrlContexts): { | ||
get: (startTime?: number | undefined) => InternalContext | undefined; | ||
}; |
@@ -0,1 +1,2 @@ | ||
import { __assign } from "tslib"; | ||
/** | ||
@@ -5,7 +6,8 @@ * Internal context keep returning v1 format | ||
*/ | ||
export function startInternalContext(applicationId, session, parentContexts) { | ||
export function startInternalContext(applicationId, session, parentContexts, urlContexts) { | ||
return { | ||
get: function (startTime) { | ||
var viewContext = parentContexts.findView(startTime); | ||
if (session.isTracked() && viewContext && viewContext.session.id) { | ||
var urlContext = urlContexts.findUrl(startTime); | ||
if (session.isTracked() && viewContext && urlContext && viewContext.session.id) { | ||
var actionContext = parentContexts.findAction(startTime); | ||
@@ -20,3 +22,3 @@ return { | ||
: undefined, | ||
view: viewContext.view, | ||
view: __assign(__assign({}, viewContext.view), urlContext.view), | ||
}; | ||
@@ -23,0 +25,0 @@ } |
@@ -1,2 +0,1 @@ | ||
import { __assign } from "tslib"; | ||
import { ONE_MINUTE, SESSION_TIME_OUT_DELAY } from '@datadog/browser-core'; | ||
@@ -8,6 +7,6 @@ import { LifeCycleEventType } from './lifeCycle'; | ||
export function startParentContexts(lifeCycle, session) { | ||
var viewContextHistory = new ContextHistory(buildCurrentViewContext, VIEW_CONTEXT_TIME_OUT_DELAY); | ||
var actionContextHistory = new ContextHistory(buildCurrentActionContext, ACTION_CONTEXT_TIME_OUT_DELAY); | ||
var viewContextHistory = new ContextHistory(VIEW_CONTEXT_TIME_OUT_DELAY); | ||
var actionContextHistory = new ContextHistory(ACTION_CONTEXT_TIME_OUT_DELAY); | ||
lifeCycle.subscribe(LifeCycleEventType.VIEW_CREATED, function (view) { | ||
viewContextHistory.setCurrent(__assign({ sessionId: session.getId() }, view), view.startClocks.relative); | ||
viewContextHistory.setCurrent(buildViewContext(view, session.getId()), view.startClocks.relative); | ||
}); | ||
@@ -18,4 +17,4 @@ lifeCycle.subscribe(LifeCycleEventType.VIEW_UPDATED, function (view) { | ||
var current = viewContextHistory.getCurrent(); | ||
if (current && current.id === view.id) { | ||
viewContextHistory.setCurrent(__assign({ sessionId: current.sessionId }, view), view.startClocks.relative); | ||
if (current && current.view.id === view.id) { | ||
viewContextHistory.setCurrent(buildViewContext(view, current.session.id), view.startClocks.relative); | ||
} | ||
@@ -28,3 +27,3 @@ }); | ||
lifeCycle.subscribe(LifeCycleEventType.AUTO_ACTION_CREATED, function (action) { | ||
actionContextHistory.setCurrent(action, action.startClocks.relative); | ||
actionContextHistory.setCurrent(buildActionContext(action), action.startClocks.relative); | ||
}); | ||
@@ -45,17 +44,15 @@ lifeCycle.subscribe(LifeCycleEventType.AUTO_ACTION_COMPLETED, function (action) { | ||
}); | ||
function buildCurrentViewContext(current) { | ||
function buildViewContext(view, sessionId) { | ||
return { | ||
session: { | ||
id: current.sessionId, | ||
id: sessionId, | ||
}, | ||
view: { | ||
id: current.id, | ||
name: current.name, | ||
referrer: current.referrer, | ||
url: current.location.href, | ||
id: view.id, | ||
name: view.name, | ||
}, | ||
}; | ||
} | ||
function buildCurrentActionContext(current) { | ||
return { action: { id: current.id } }; | ||
function buildActionContext(action) { | ||
return { action: { id: action.id } }; | ||
} | ||
@@ -62,0 +59,0 @@ return { |
@@ -11,3 +11,2 @@ import { Duration, ClocksState, TimeStamp, Observable } from '@datadog/browser-core'; | ||
location: Readonly<Location>; | ||
referrer: string; | ||
timings: Timings; | ||
@@ -27,4 +26,2 @@ customTimings: ViewCustomTimings; | ||
name?: string; | ||
location: Location; | ||
referrer: string; | ||
startClocks: ClocksState; | ||
@@ -31,0 +28,0 @@ } |
@@ -13,7 +13,8 @@ import { __assign } from "tslib"; | ||
var stopViewLifeCycle = startViewLifeCycle().stop; | ||
var stopViewCollectionMode = (areViewsTrackedAutomatically | ||
? startAutomaticViewCollection(locationChangeObservable) | ||
: startManualViewCollection(locationChangeObservable)).unsubscribe; | ||
var locationChangeSubscription; | ||
if (areViewsTrackedAutomatically) { | ||
locationChangeSubscription = renewViewOnLocationChange(locationChangeObservable); | ||
} | ||
function trackInitialView(name) { | ||
var initialView = newView(lifeCycle, domMutationObservable, location, ViewLoadingType.INITIAL_LOAD, document.referrer, clocksOrigin(), name); | ||
var initialView = newView(lifeCycle, domMutationObservable, location, ViewLoadingType.INITIAL_LOAD, clocksOrigin(), name); | ||
var stop = trackInitialViewTimings(lifeCycle, function (timings) { | ||
@@ -26,3 +27,3 @@ initialView.updateTimings(timings); | ||
function trackViewChange(startClocks, name) { | ||
return newView(lifeCycle, domMutationObservable, location, ViewLoadingType.ROUTE_CHANGE, currentView.url, startClocks, name); | ||
return newView(lifeCycle, domMutationObservable, location, ViewLoadingType.ROUTE_CHANGE, startClocks, name); | ||
} | ||
@@ -51,7 +52,6 @@ function startViewLifeCycle() { | ||
} | ||
function startAutomaticViewCollection(locationChangeObservable) { | ||
function renewViewOnLocationChange(locationChangeObservable) { | ||
return locationChangeObservable.subscribe(function (_a) { | ||
var oldLocation = _a.oldLocation, newLocation = _a.newLocation; | ||
if (areDifferentLocation(oldLocation, newLocation)) { | ||
// Renew view on location changes | ||
currentView.end(); | ||
@@ -62,13 +62,4 @@ currentView.triggerUpdate(); | ||
} | ||
currentView.updateLocation(newLocation); | ||
currentView.triggerUpdate(); | ||
}); | ||
} | ||
function startManualViewCollection(locationChangeObservable) { | ||
return locationChangeObservable.subscribe(function (_a) { | ||
var newLocation = _a.newLocation; | ||
currentView.updateLocation(newLocation); | ||
currentView.triggerUpdate(); | ||
}); | ||
} | ||
return { | ||
@@ -86,3 +77,3 @@ addTiming: function (name, time) { | ||
stop: function () { | ||
stopViewCollectionMode(); | ||
locationChangeSubscription === null || locationChangeSubscription === void 0 ? void 0 : locationChangeSubscription.unsubscribe(); | ||
stopInitialViewTracking(); | ||
@@ -94,3 +85,3 @@ stopViewLifeCycle(); | ||
} | ||
function newView(lifeCycle, domMutationObservable, initialLocation, loadingType, referrer, startClocks, name) { | ||
function newView(lifeCycle, domMutationObservable, initialLocation, loadingType, startClocks, name) { | ||
if (startClocks === void 0) { startClocks = clocksNow(); } | ||
@@ -104,3 +95,3 @@ // Setup initial values | ||
var location = __assign({}, initialLocation); | ||
lifeCycle.notify(LifeCycleEventType.VIEW_CREATED, { id: id, name: name, startClocks: startClocks, location: location, referrer: referrer }); | ||
lifeCycle.notify(LifeCycleEventType.VIEW_CREATED, { id: id, name: name, startClocks: startClocks }); | ||
// Update the view every time the measures are changing | ||
@@ -122,3 +113,2 @@ var _a = throttle(monitor(triggerViewUpdate), THROTTLE_VIEW_UPDATE_PERIOD, { | ||
location: location, | ||
referrer: referrer, | ||
startClocks: startClocks, | ||
@@ -136,5 +126,2 @@ timings: timings, duration: elapsed(startClocks.timeStamp, currentEnd), isActive: endClocks === undefined })); | ||
}, | ||
getLocation: function () { | ||
return location; | ||
}, | ||
triggerUpdate: function () { | ||
@@ -154,8 +141,2 @@ // cancel any pending view updates execution | ||
}, | ||
updateLocation: function (newLocation) { | ||
location = __assign({}, newLocation); | ||
}, | ||
get url() { | ||
return location.href; | ||
}, | ||
}; | ||
@@ -162,0 +143,0 @@ } |
@@ -173,4 +173,2 @@ import { Context, Duration, ErrorSource, ErrorHandling, ResourceType, ServerDuration, TimeStamp } from '@datadog/browser-core'; | ||
name?: string; | ||
url: string; | ||
referrer: string; | ||
}; | ||
@@ -183,2 +181,8 @@ } | ||
} | ||
export interface UrlContext extends Context { | ||
view: { | ||
url: string; | ||
referrer: string; | ||
}; | ||
} | ||
export interface InternalContext { | ||
@@ -185,0 +189,0 @@ application_id: string; |
{ | ||
"name": "@datadog/browser-rum-core", | ||
"version": "3.6.0", | ||
"version": "3.6.1", | ||
"license": "Apache-2.0", | ||
@@ -15,3 +15,3 @@ "main": "cjs/index.js", | ||
"dependencies": { | ||
"@datadog/browser-core": "3.6.0", | ||
"@datadog/browser-core": "3.6.1", | ||
"tslib": "^1.10.0" | ||
@@ -27,3 +27,3 @@ }, | ||
}, | ||
"gitHead": "3b26b5fdc94b7bdb9ef843791c859075a52d48b7" | ||
"gitHead": "c2fde4b65f8e811a5f706a2455c2abf3292bfd0c" | ||
} |
@@ -1,2 +0,2 @@ | ||
import { RelativeTime, Configuration, Observable } from '@datadog/browser-core' | ||
import { RelativeTime, Configuration, Observable, noop, relativeNow } from '@datadog/browser-core' | ||
import { RumSession } from '@datadog/browser-rum-core' | ||
@@ -6,3 +6,3 @@ import { createRumSessionMock, RumSessionMock } from '../../test/mockRumSession' | ||
import { noopRecorderApi, setup, TestSetupBuilder } from '../../test/specHelper' | ||
import { RumPerformanceNavigationTiming } from '../browser/performanceCollection' | ||
import { RumPerformanceNavigationTiming, RumPerformanceEntry } from '../browser/performanceCollection' | ||
@@ -14,2 +14,3 @@ import { LifeCycle, LifeCycleEventType } from '../domain/lifeCycle' | ||
import { LocationChange } from '../browser/locationChangeObservable' | ||
import { startLongTaskCollection } from '../domain/rumEventsCollection/longTask/longTaskCollection' | ||
import { startRumEventCollection } from './startRum' | ||
@@ -38,3 +39,5 @@ | ||
configuration, | ||
location, | ||
session, | ||
locationChangeObservable, | ||
() => ({ | ||
@@ -54,2 +57,4 @@ context: {}, | ||
) | ||
startLongTaskCollection(lifeCycle) | ||
return { | ||
@@ -197,3 +202,3 @@ stop: () => { | ||
describe('rum view url', () => { | ||
describe('rum events url', () => { | ||
const FAKE_NAVIGATION_ENTRY: RumPerformanceNavigationTiming = { | ||
@@ -240,2 +245,30 @@ domComplete: 456 as RelativeTime, | ||
it('should attach the url corresponding to the start of the event', () => { | ||
const { lifeCycle, clock, changeLocation } = setupBuilder | ||
.withFakeClock() | ||
.withFakeLocation('http://foo.com/') | ||
.build() | ||
clock.tick(10) | ||
changeLocation('http://foo.com/?bar=bar') | ||
clock.tick(10) | ||
changeLocation('http://foo.com/?bar=qux') | ||
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, { | ||
entryType: 'longtask', | ||
startTime: relativeNow() - 5, | ||
toJSON: noop, | ||
duration: 5, | ||
} as RumPerformanceEntry) | ||
clock.tick(THROTTLE_VIEW_UPDATE_PERIOD) | ||
expect(serverRumEvents.length).toBe(3) | ||
const [firstViewUpdate, longTaskEvent, lastViewUpdate] = serverRumEvents | ||
expect(firstViewUpdate.view.url).toBe('http://foo.com/') | ||
expect(lastViewUpdate.view.url).toBe('http://foo.com/') | ||
expect(longTaskEvent.view.url).toBe('http://foo.com/?bar=bar') | ||
}) | ||
it('should keep the same URL when updating a view ended by a URL change', () => { | ||
@@ -242,0 +275,0 @@ const { changeLocation } = setupBuilder.withFakeLocation('http://foo.com/').build() |
@@ -1,2 +0,2 @@ | ||
import { combine, Configuration, InternalMonitoring } from '@datadog/browser-core' | ||
import { combine, Configuration, InternalMonitoring, Observable } from '@datadog/browser-core' | ||
import { createDOMMutationObservable } from '../browser/domMutationObservable' | ||
@@ -18,3 +18,4 @@ import { startPerformanceCollection } from '../browser/performanceCollection' | ||
import { startRumBatch } from '../transport/batch' | ||
import { createLocationChangeObservable } from '../browser/locationChangeObservable' | ||
import { startUrlContexts } from '../domain/urlContexts' | ||
import { createLocationChangeObservable, LocationChange } from '../browser/locationChangeObservable' | ||
import { RecorderApi, RumInitConfiguration } from './rumPublicApi' | ||
@@ -45,7 +46,9 @@ | ||
const { parentContexts, foregroundContexts } = startRumEventCollection( | ||
const { parentContexts, foregroundContexts, urlContexts } = startRumEventCollection( | ||
initConfiguration.applicationId, | ||
lifeCycle, | ||
configuration, | ||
location, | ||
session, | ||
locationChangeObservable, | ||
getCommonContext | ||
@@ -74,3 +77,3 @@ ) | ||
const internalContext = startInternalContext(initConfiguration.applicationId, session, parentContexts) | ||
const internalContext = startInternalContext(initConfiguration.applicationId, session, parentContexts, urlContexts) | ||
@@ -93,10 +96,13 @@ return { | ||
configuration: Configuration, | ||
location: Location, | ||
session: RumSession, | ||
locationChangeObservable: Observable<LocationChange>, | ||
getCommonContext: () => CommonContext | ||
) { | ||
const parentContexts = startParentContexts(lifeCycle, session) | ||
const urlContexts = startUrlContexts(lifeCycle, locationChangeObservable, location) | ||
const foregroundContexts = startForegroundContexts() | ||
const batch = startRumBatch(configuration, lifeCycle) | ||
startRumAssembly(applicationId, configuration, lifeCycle, session, parentContexts, getCommonContext) | ||
startRumAssembly(applicationId, configuration, lifeCycle, session, parentContexts, urlContexts, getCommonContext) | ||
@@ -106,2 +112,3 @@ return { | ||
foregroundContexts, | ||
urlContexts, | ||
stop: () => { | ||
@@ -108,0 +115,0 @@ // prevent batch from previous tests to keep running and send unwanted requests |
@@ -38,8 +38,6 @@ import { ErrorSource, ONE_MINUTE, RawError, RelativeTime, display } from '@datadog/browser-core' | ||
id: 'abcde', | ||
referrer: 'url', | ||
url: 'url', | ||
}, | ||
}), | ||
}) | ||
.beforeBuild(({ applicationId, configuration, lifeCycle, session, parentContexts }) => { | ||
.beforeBuild(({ applicationId, configuration, lifeCycle, session, parentContexts, urlContexts }) => { | ||
serverRumEvents = [] | ||
@@ -49,3 +47,11 @@ lifeCycle.subscribe(LifeCycleEventType.RUM_EVENT_COLLECTED, (serverRumEvent) => | ||
) | ||
startRumAssembly(applicationId, configuration, lifeCycle, session, parentContexts, () => commonContext) | ||
startRumAssembly( | ||
applicationId, | ||
configuration, | ||
lifeCycle, | ||
session, | ||
parentContexts, | ||
urlContexts, | ||
() => commonContext | ||
) | ||
}) | ||
@@ -436,7 +442,3 @@ }) | ||
}) | ||
expect(serverRumEvents[0].view).toEqual({ | ||
id: 'abcde', | ||
referrer: 'url', | ||
url: 'url', | ||
}) | ||
expect(serverRumEvents[0].view.id).toBe('abcde') | ||
expect(serverRumEvents[0].session.id).toBe('1234') | ||
@@ -446,2 +448,13 @@ }) | ||
describe('url context', () => { | ||
it('should be merged with event attributes', () => { | ||
const { lifeCycle, fakeLocation } = setupBuilder.build() | ||
notifyRawRumEvent(lifeCycle, { | ||
rawRumEvent: createRawRumEvent(RumEventType.ACTION), | ||
}) | ||
expect(serverRumEvents[0].view.url).toBe(fakeLocation.href!) | ||
expect(serverRumEvents[0].view.referrer).toBe(document.referrer) | ||
}) | ||
}) | ||
describe('event generation condition', () => { | ||
@@ -448,0 +461,0 @@ it('when tracked, it should generate event', () => { |
@@ -32,2 +32,3 @@ import { | ||
import { RumSession, RumSessionPlan } from './rumSession' | ||
import { UrlContexts } from './urlContexts' | ||
@@ -69,2 +70,3 @@ export interface BrowserWindow extends Window { | ||
parentContexts: ParentContexts, | ||
urlContexts: UrlContexts, | ||
getCommonContext: () => CommonContext | ||
@@ -85,3 +87,4 @@ ) { | ||
const viewContext = parentContexts.findView(startTime) | ||
if (session.isTracked() && viewContext && viewContext.session.id === session.getId()) { | ||
const urlContext = urlContexts.findUrl(startTime) | ||
if (session.isTracked() && viewContext && urlContext && viewContext.session.id === session.getId()) { | ||
const actionContext = parentContexts.findAction(startTime) | ||
@@ -109,4 +112,4 @@ const commonContext = savedCommonContext || getCommonContext() | ||
const serverRumEvent = (needToAssembleWithAction(rawRumEvent) | ||
? combine(rumContext, viewContext, actionContext, rawRumEvent) | ||
: combine(rumContext, viewContext, rawRumEvent)) as RumEvent & Context | ||
? combine(rumContext, urlContext, viewContext, actionContext, rawRumEvent) | ||
: combine(rumContext, urlContext, viewContext, rawRumEvent)) as RumEvent & Context | ||
@@ -138,2 +141,14 @@ serverRumEvent.context = combine(commonContext.context, customerContext) | ||
} | ||
if (serverRumEvent.session.has_replay && serverRumEvent._dd.session?.plan === RumSessionPlan.LITE) { | ||
addMonitoringMessage('lite session with replay', { | ||
debug: { | ||
eventType: serverRumEvent.type, | ||
viewId: serverRumEvent.view.id, | ||
sessionId: serverRumEvent.session.id, | ||
replayPlan: session.hasReplayPlan(), | ||
litePlan: session.hasLitePlan(), | ||
docVersion: serverRumEvent._dd.document_version as number | undefined, | ||
}, | ||
}) | ||
} | ||
lifeCycle.notify(LifeCycleEventType.RUM_EVENT_COLLECTED, serverRumEvent) | ||
@@ -140,0 +155,0 @@ } |
@@ -8,3 +8,3 @@ import { RelativeTime, ONE_MINUTE } from '@datadog/browser-core' | ||
describe('contextHistory', () => { | ||
let contextHistory: ContextHistory<{ value: string }, { value: string }> | ||
let contextHistory: ContextHistory<{ value: string }> | ||
let clock: Clock | ||
@@ -14,3 +14,3 @@ | ||
clock = mockClock() | ||
contextHistory = new ContextHistory((raw) => ({ value: raw.value }), EXPIRE_DELAY) | ||
contextHistory = new ContextHistory(EXPIRE_DELAY) | ||
}) | ||
@@ -17,0 +17,0 @@ |
@@ -11,9 +11,9 @@ import { ONE_MINUTE, RelativeTime, relativeNow } from '@datadog/browser-core' | ||
export class ContextHistory<Raw, Built> { | ||
private current: Raw | undefined | ||
export class ContextHistory<Context> { | ||
private current: Context | undefined | ||
private currentStart: RelativeTime | undefined | ||
private previousContexts: Array<PreviousContext<Built>> = [] | ||
private previousContexts: Array<PreviousContext<Context>> = [] | ||
private clearOldContextsInterval: number | ||
constructor(private buildContext: (r: Raw) => Built, private expireDelay: number) { | ||
constructor(private expireDelay: number) { | ||
this.clearOldContextsInterval = setInterval(() => this.clearOldContexts(), CLEAR_OLD_CONTEXTS_INTERVAL) | ||
@@ -23,8 +23,8 @@ } | ||
find(startTime?: RelativeTime) { | ||
if (startTime === undefined) { | ||
return this.current ? this.buildContext(this.current) : undefined | ||
if ( | ||
startTime === undefined || | ||
(this.current !== undefined && this.currentStart !== undefined && startTime >= this.currentStart) | ||
) { | ||
return this.current | ||
} | ||
if (this.current !== undefined && this.currentStart !== undefined && startTime >= this.currentStart) { | ||
return this.buildContext(this.current) | ||
} | ||
for (const previousContext of this.previousContexts) { | ||
@@ -41,3 +41,3 @@ if (startTime > previousContext.endTime) { | ||
setCurrent(current: Raw, startTime: RelativeTime) { | ||
setCurrent(current: Context, startTime: RelativeTime) { | ||
this.current = current | ||
@@ -60,3 +60,3 @@ this.currentStart = startTime | ||
endTime, | ||
context: this.buildContext(this.current), | ||
context: this.current, | ||
startTime: this.currentStart, | ||
@@ -63,0 +63,0 @@ }) |
import { createRumSessionMock } from 'packages/rum-core/test/mockRumSession' | ||
import { RelativeTime } from '@datadog/browser-core' | ||
import { setup, TestSetupBuilder } from '../../test/specHelper' | ||
import { startInternalContext } from './internalContext' | ||
import { ParentContexts } from './parentContexts' | ||
import { UrlContexts } from './urlContexts' | ||
@@ -9,2 +11,3 @@ describe('internal context', () => { | ||
let parentContextsStub: Partial<ParentContexts> | ||
let findUrlSpy: jasmine.Spy<UrlContexts['findUrl']> | ||
let internalContext: ReturnType<typeof startInternalContext> | ||
@@ -25,4 +28,2 @@ | ||
id: 'abcde', | ||
referrer: 'referrer', | ||
url: 'url', | ||
}, | ||
@@ -33,4 +34,5 @@ }), | ||
.withParentContexts(parentContextsStub) | ||
.beforeBuild(({ applicationId, session, parentContexts }) => { | ||
internalContext = startInternalContext(applicationId, session, parentContexts) | ||
.beforeBuild(({ applicationId, session, parentContexts, urlContexts }) => { | ||
findUrlSpy = spyOn(urlContexts, 'findUrl').and.callThrough() | ||
internalContext = startInternalContext(applicationId, session, parentContexts, urlContexts) | ||
}) | ||
@@ -44,3 +46,3 @@ }) | ||
it('should return current internal context', () => { | ||
setupBuilder.build() | ||
const { fakeLocation } = setupBuilder.build() | ||
@@ -55,4 +57,4 @@ expect(internalContext.get()).toEqual({ | ||
id: 'abcde', | ||
referrer: 'referrer', | ||
url: 'url', | ||
referrer: document.referrer, | ||
url: fakeLocation.href!, | ||
}, | ||
@@ -74,3 +76,4 @@ }) | ||
expect(parentContextsStub.findAction).toHaveBeenCalledWith(123) | ||
expect(findUrlSpy).toHaveBeenCalledWith(123 as RelativeTime) | ||
}) | ||
}) |
@@ -5,2 +5,3 @@ import { RelativeTime } from '@datadog/browser-core' | ||
import { RumSession } from './rumSession' | ||
import { UrlContexts } from './urlContexts' | ||
@@ -11,7 +12,13 @@ /** | ||
*/ | ||
export function startInternalContext(applicationId: string, session: RumSession, parentContexts: ParentContexts) { | ||
export function startInternalContext( | ||
applicationId: string, | ||
session: RumSession, | ||
parentContexts: ParentContexts, | ||
urlContexts: UrlContexts | ||
) { | ||
return { | ||
get: (startTime?: number): InternalContext | undefined => { | ||
const viewContext = parentContexts.findView(startTime as RelativeTime) | ||
if (session.isTracked() && viewContext && viewContext.session.id) { | ||
const urlContext = urlContexts.findUrl(startTime as RelativeTime) | ||
if (session.isTracked() && viewContext && urlContext && viewContext.session.id) { | ||
const actionContext = parentContexts.findAction(startTime as RelativeTime) | ||
@@ -26,3 +33,6 @@ return { | ||
: undefined, | ||
view: viewContext.view, | ||
view: { | ||
...viewContext.view, | ||
...urlContext.view, | ||
}, | ||
} | ||
@@ -29,0 +39,0 @@ } |
@@ -21,6 +21,4 @@ import { RelativeTime, relativeToClocks } from '@datadog/browser-core' | ||
return { | ||
location, | ||
startClocks, | ||
id: FAKE_ID, | ||
referrer: 'http://foo.com', | ||
...partialViewCreatedEvent, | ||
@@ -117,13 +115,2 @@ } | ||
it('should return the current url with the current view', () => { | ||
const { lifeCycle, fakeLocation, changeLocation } = setupBuilder.build() | ||
lifeCycle.notify(LifeCycleEventType.VIEW_CREATED, buildViewCreatedEvent({ location: fakeLocation as Location })) | ||
expect(parentContexts.findView()!.view.url).toBe('http://fake-url.com/') | ||
changeLocation('/foo') | ||
expect(parentContexts.findView()!.view.url).toBe('http://fake-url.com/foo') | ||
}) | ||
it('should return the view name with the view', () => { | ||
@@ -130,0 +117,0 @@ const { lifeCycle } = setupBuilder.build() |
@@ -19,20 +19,8 @@ import { ONE_MINUTE, RelativeTime, SESSION_TIME_OUT_DELAY } from '@datadog/browser-core' | ||
export function startParentContexts(lifeCycle: LifeCycle, session: RumSession): ParentContexts { | ||
const viewContextHistory = new ContextHistory<ViewCreatedEvent & { sessionId?: string }, ViewContext>( | ||
buildCurrentViewContext, | ||
VIEW_CONTEXT_TIME_OUT_DELAY | ||
) | ||
const viewContextHistory = new ContextHistory<ViewContext>(VIEW_CONTEXT_TIME_OUT_DELAY) | ||
const actionContextHistory = new ContextHistory<AutoActionCreatedEvent, ActionContext>( | ||
buildCurrentActionContext, | ||
ACTION_CONTEXT_TIME_OUT_DELAY | ||
) | ||
const actionContextHistory = new ContextHistory<ActionContext>(ACTION_CONTEXT_TIME_OUT_DELAY) | ||
lifeCycle.subscribe(LifeCycleEventType.VIEW_CREATED, (view) => { | ||
viewContextHistory.setCurrent( | ||
{ | ||
sessionId: session.getId(), | ||
...view, | ||
}, | ||
view.startClocks.relative | ||
) | ||
viewContextHistory.setCurrent(buildViewContext(view, session.getId()), view.startClocks.relative) | ||
}) | ||
@@ -44,10 +32,4 @@ | ||
const current = viewContextHistory.getCurrent() | ||
if (current && current.id === view.id) { | ||
viewContextHistory.setCurrent( | ||
{ | ||
sessionId: current.sessionId, | ||
...view, | ||
}, | ||
view.startClocks.relative | ||
) | ||
if (current && current.view.id === view.id) { | ||
viewContextHistory.setCurrent(buildViewContext(view, current.session.id), view.startClocks.relative) | ||
} | ||
@@ -61,3 +43,3 @@ }) | ||
lifeCycle.subscribe(LifeCycleEventType.AUTO_ACTION_CREATED, (action) => { | ||
actionContextHistory.setCurrent(action, action.startClocks.relative) | ||
actionContextHistory.setCurrent(buildActionContext(action), action.startClocks.relative) | ||
}) | ||
@@ -82,12 +64,10 @@ | ||
function buildCurrentViewContext(current: ViewCreatedEvent & { sessionId?: string }) { | ||
function buildViewContext(view: ViewCreatedEvent, sessionId: string | undefined) { | ||
return { | ||
session: { | ||
id: current.sessionId, | ||
id: sessionId, | ||
}, | ||
view: { | ||
id: current.id, | ||
name: current.name, | ||
referrer: current.referrer, | ||
url: current.location.href, | ||
id: view.id, | ||
name: view.name, | ||
}, | ||
@@ -97,4 +77,4 @@ } | ||
function buildCurrentActionContext(current: AutoActionCreatedEvent) { | ||
return { action: { id: current.id } } | ||
function buildActionContext(action: AutoActionCreatedEvent) { | ||
return { action: { id: action.id } } | ||
} | ||
@@ -101,0 +81,0 @@ |
@@ -83,5 +83,3 @@ import { Context, DOM_EVENT, ClocksState, Observable } from '@datadog/browser-core' | ||
lifeCycle.notify(LifeCycleEventType.VIEW_CREATED, { | ||
location, | ||
id: 'fake', | ||
referrer: 'http://foo.com', | ||
startClocks: (jasmine.any(Object) as unknown) as ClocksState, | ||
@@ -88,0 +86,0 @@ }) |
@@ -48,22 +48,7 @@ import { Duration, RelativeTime, timeStampNow, display, relativeToClocks } from '@datadog/browser-core' | ||
describe('location changes', () => { | ||
it('should update view location on search change', () => { | ||
const { changeLocation } = setupBuilder.build() | ||
const { getViewCreateCount, getViewCreate, getViewUpdate, getViewUpdateCount } = viewTest | ||
changeLocation('/foo?bar=qux') | ||
expect(getViewCreateCount()).toBe(1) | ||
expect(getViewCreate(0).location.href).toMatch(/\/foo$/) | ||
const lastUpdate = getViewUpdate(getViewUpdateCount() - 1) | ||
expect(lastUpdate.location.href).toMatch(/\/foo\?bar=qux$/) | ||
expect(lastUpdate.id).toBe(getViewCreate(0).id) | ||
}) | ||
it('should create new view on path change', () => { | ||
const { changeLocation } = setupBuilder.build() | ||
const { getViewCreateCount, getViewCreate } = viewTest | ||
const { getViewCreateCount } = viewTest | ||
expect(getViewCreateCount()).toBe(1) | ||
expect(getViewCreate(0).location.href).toMatch(/\/foo$/) | ||
@@ -73,3 +58,2 @@ changeLocation('/bar') | ||
expect(getViewCreateCount()).toBe(2) | ||
expect(getViewCreate(1).location.href).toMatch(/\/bar$/) | ||
}) | ||
@@ -79,6 +63,5 @@ | ||
const { changeLocation } = setupBuilder.build() | ||
const { getViewCreateCount, getViewCreate } = viewTest | ||
const { getViewCreateCount } = viewTest | ||
expect(getViewCreateCount()).toBe(1) | ||
expect(getViewCreate(0).location.href).toMatch(/\/foo$/) | ||
@@ -88,3 +71,2 @@ changeLocation('/foo#bar') | ||
expect(getViewCreateCount()).toBe(2) | ||
expect(getViewCreate(1).location.href).toMatch(/\/foo#bar$/) | ||
}) | ||
@@ -122,122 +104,4 @@ | ||
}) | ||
describe('view referrer', () => { | ||
it('should set the document referrer as referrer for the initial view', () => { | ||
setupBuilder.build() | ||
const { getViewCreate } = viewTest | ||
expect(getViewCreate(0).referrer).toEqual(document.referrer) | ||
}) | ||
it('should set the previous view URL as referrer when a route change occurs', () => { | ||
const { changeLocation } = setupBuilder.build() | ||
const { getViewCreate } = viewTest | ||
changeLocation('/bar') | ||
expect(getViewCreate(1).referrer).toEqual(jasmine.stringMatching(/\/foo$/)) | ||
}) | ||
it('should set the previous view URL as referrer when a the session is renewed', () => { | ||
const { lifeCycle } = setupBuilder.build() | ||
const { getViewCreate } = viewTest | ||
lifeCycle.notify(LifeCycleEventType.SESSION_RENEWED) | ||
expect(getViewCreate(1).referrer).toEqual(jasmine.stringMatching(/\/foo$/)) | ||
}) | ||
it('should use the most up-to-date URL of the previous view as a referrer', () => { | ||
const { changeLocation } = setupBuilder.build() | ||
const { getViewCreate } = viewTest | ||
changeLocation('/foo?a=b') | ||
changeLocation('/bar') | ||
expect(getViewCreate(1).referrer).toEqual(jasmine.stringMatching(/\/foo\?a=b$/)) | ||
}) | ||
}) | ||
}) | ||
describe('track views manually', () => { | ||
let setupBuilder: TestSetupBuilder | ||
let viewTest: ViewTest | ||
beforeEach(() => { | ||
setupBuilder = setup() | ||
.withFakeLocation('/foo') | ||
.withConfiguration({ trackViewsManually: true }) | ||
.beforeBuild((buildContext) => { | ||
viewTest = setupViewTest(buildContext) | ||
return viewTest | ||
}) | ||
}) | ||
afterEach(() => { | ||
setupBuilder.cleanup() | ||
}) | ||
describe('location changes', () => { | ||
it('should update view location on search change', () => { | ||
const { changeLocation } = setupBuilder.build() | ||
const { getViewCreateCount, getViewCreate, getViewUpdate, getViewUpdateCount } = viewTest | ||
changeLocation('/foo?bar=qux') | ||
expect(getViewCreateCount()).toBe(1) | ||
expect(getViewCreate(0).location.href).toMatch(/\/foo$/) | ||
const lastUpdate = getViewUpdate(getViewUpdateCount() - 1) | ||
expect(lastUpdate.location.href).toMatch(/\/foo\?bar=qux$/) | ||
expect(lastUpdate.id).toBe(getViewCreate(0).id) | ||
}) | ||
it('should update view location on path change', () => { | ||
const { changeLocation } = setupBuilder.build() | ||
const { getViewCreateCount, getViewCreate, getViewUpdate, getViewUpdateCount } = viewTest | ||
changeLocation('/bar') | ||
expect(getViewCreateCount()).toBe(1) | ||
expect(getViewCreate(0).location.href).toMatch(/\/foo$/) | ||
const lastUpdate = getViewUpdate(getViewUpdateCount() - 1) | ||
expect(lastUpdate.location.href).toMatch(/\/bar$/) | ||
expect(lastUpdate.id).toBe(getViewCreate(0).id) | ||
}) | ||
}) | ||
describe('view referrer', () => { | ||
it('should set the document referrer as referrer for the initial view', () => { | ||
setupBuilder.build() | ||
const { getViewCreate } = viewTest | ||
expect(getViewCreate(0).referrer).toEqual(document.referrer) | ||
}) | ||
it('should set the previous view URL as referrer when starting a new view', () => { | ||
const { changeLocation } = setupBuilder.build() | ||
const { getViewUpdate, getViewUpdateCount, startView } = viewTest | ||
startView() | ||
changeLocation('/bar') | ||
const lastUpdate = getViewUpdate(getViewUpdateCount() - 1) | ||
expect(lastUpdate.referrer).toEqual(jasmine.stringMatching(/\/foo$/)) | ||
expect(lastUpdate.location.href).toEqual(jasmine.stringMatching(/\/bar$/)) | ||
}) | ||
it('should use the most up-to-date URL of the previous view as a referrer', () => { | ||
const { changeLocation } = setupBuilder.build() | ||
const { getViewCreate, startView } = viewTest | ||
changeLocation('/foo?a=b') | ||
changeLocation('/bar') | ||
startView() | ||
expect(getViewCreate(1).referrer).toEqual(jasmine.stringMatching(/\/bar$/)) | ||
}) | ||
}) | ||
}) | ||
describe('initial view', () => { | ||
@@ -244,0 +108,0 @@ let setupBuilder: TestSetupBuilder |
@@ -15,2 +15,3 @@ import { | ||
Observable, | ||
Subscription, | ||
} from '@datadog/browser-core' | ||
@@ -29,3 +30,2 @@ import { ViewLoadingType, ViewCustomTimings } from '../../../rawRumEvent.types' | ||
location: Readonly<Location> | ||
referrer: string | ||
timings: Timings | ||
@@ -46,4 +46,2 @@ customTimings: ViewCustomTimings | ||
name?: string | ||
location: Location | ||
referrer: string | ||
startClocks: ClocksState | ||
@@ -71,6 +69,8 @@ } | ||
const { stop: stopViewLifeCycle } = startViewLifeCycle() | ||
const { unsubscribe: stopViewCollectionMode } = areViewsTrackedAutomatically | ||
? startAutomaticViewCollection(locationChangeObservable) | ||
: startManualViewCollection(locationChangeObservable) | ||
let locationChangeSubscription: Subscription | ||
if (areViewsTrackedAutomatically) { | ||
locationChangeSubscription = renewViewOnLocationChange(locationChangeObservable) | ||
} | ||
function trackInitialView(name?: string) { | ||
@@ -82,3 +82,2 @@ const initialView = newView( | ||
ViewLoadingType.INITIAL_LOAD, | ||
document.referrer, | ||
clocksOrigin(), | ||
@@ -95,11 +94,3 @@ name | ||
function trackViewChange(startClocks?: ClocksState, name?: string) { | ||
return newView( | ||
lifeCycle, | ||
domMutationObservable, | ||
location, | ||
ViewLoadingType.ROUTE_CHANGE, | ||
currentView.url, | ||
startClocks, | ||
name | ||
) | ||
return newView(lifeCycle, domMutationObservable, location, ViewLoadingType.ROUTE_CHANGE, startClocks, name) | ||
} | ||
@@ -136,6 +127,5 @@ | ||
function startAutomaticViewCollection(locationChangeObservable: Observable<LocationChange>) { | ||
function renewViewOnLocationChange(locationChangeObservable: Observable<LocationChange>) { | ||
return locationChangeObservable.subscribe(({ oldLocation, newLocation }) => { | ||
if (areDifferentLocation(oldLocation, newLocation)) { | ||
// Renew view on location changes | ||
currentView.end() | ||
@@ -146,14 +136,5 @@ currentView.triggerUpdate() | ||
} | ||
currentView.updateLocation(newLocation) | ||
currentView.triggerUpdate() | ||
}) | ||
} | ||
function startManualViewCollection(locationChangeObservable: Observable<LocationChange>) { | ||
return locationChangeObservable.subscribe(({ newLocation }) => { | ||
currentView.updateLocation(newLocation) | ||
currentView.triggerUpdate() | ||
}) | ||
} | ||
return { | ||
@@ -170,3 +151,3 @@ addTiming: (name: string, time = timeStampNow()) => { | ||
stop: () => { | ||
stopViewCollectionMode() | ||
locationChangeSubscription?.unsubscribe() | ||
stopInitialViewTracking() | ||
@@ -184,3 +165,2 @@ stopViewLifeCycle() | ||
loadingType: ViewLoadingType, | ||
referrer: string, | ||
startClocks: ClocksState = clocksNow(), | ||
@@ -195,5 +175,5 @@ name?: string | ||
let endClocks: ClocksState | undefined | ||
let location = { ...initialLocation } | ||
const location = { ...initialLocation } | ||
lifeCycle.notify(LifeCycleEventType.VIEW_CREATED, { id, name, startClocks, location, referrer }) | ||
lifeCycle.notify(LifeCycleEventType.VIEW_CREATED, { id, name, startClocks }) | ||
@@ -230,3 +210,2 @@ // Update the view every time the measures are changing | ||
location, | ||
referrer, | ||
startClocks, | ||
@@ -247,5 +226,2 @@ timings, | ||
}, | ||
getLocation() { | ||
return location | ||
}, | ||
triggerUpdate() { | ||
@@ -265,8 +241,2 @@ // cancel any pending view updates execution | ||
}, | ||
updateLocation(newLocation: Location) { | ||
location = { ...newLocation } | ||
}, | ||
get url() { | ||
return location.href | ||
}, | ||
} | ||
@@ -273,0 +243,0 @@ } |
@@ -29,3 +29,2 @@ import { Duration, RelativeTime, ServerDuration, TimeStamp } from '@datadog/browser-core' | ||
location: {} as Location, | ||
referrer: '', | ||
startClocks: { relative: 1234 as RelativeTime, timeStamp: 123456789 as TimeStamp }, | ||
@@ -32,0 +31,0 @@ timings: { |
@@ -202,4 +202,2 @@ import { | ||
name?: string | ||
url: string | ||
referrer: string | ||
} | ||
@@ -214,2 +212,9 @@ } | ||
export interface UrlContext extends Context { | ||
view: { | ||
url: string | ||
referrer: string | ||
} | ||
} | ||
export interface InternalContext { | ||
@@ -216,0 +221,0 @@ application_id: string |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
970697
1.56%292
2.82%19865
1.31%+ Added
- Removed
Updated