Skip to content

Commit

Permalink
feat: migrating rum to post network call
Browse files Browse the repository at this point in the history
  • Loading branch information
patrickhousley committed May 8, 2023
1 parent ba7d17c commit edc367e
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 71 deletions.
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/common/harvest/harvest.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class Harvest extends SharedContext {

var agentRuntime = getRuntime(this.sharedContext.agentIdentifier)

if (!payload.body) { // no payload body? nothing to send, just run onfinish stuff and return
if (!payload.body && !payload.qs) { // no payload body? nothing to send, just run onfinish stuff and return
if (cbFinished) {
cbFinished({ sent: false })
}
Expand All @@ -97,7 +97,7 @@ export class Harvest extends SharedContext {

if (!opts) opts = {}

var url = this.getScheme() + '://' + info.errorBeacon + '/' + endpoint + '/1/' + info.licenseKey + this.baseQueryString()
let url = `${this.getScheme()}://${info.errorBeacon}${endpoint !== 'rum' ? `/${endpoint}` : ''}/1/${info.licenseKey}${this.baseQueryString()}`
if (payload.qs) url += encodeObj(payload.qs, agentRuntime.maxBytes)

if (!submitMethod) {
Expand Down
85 changes: 38 additions & 47 deletions src/features/page_view_event/aggregate/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ import { handle } from '../../../common/event-emitter/handle'
import { FEATURE_NAMES } from '../../../loaders/features/features'
import { isiOS } from '../../../common/browser-version/ios-version'
import { onTTFB } from 'web-vitals'
import { mapOwn } from '../../../common/util/map-own'
import { param, fromArray } from '../../../common/url/encode'
import { addPT, addPN } from '../../../common/timing/nav-timing'
import { stringify } from '../../../common/util/stringify'
import { paintMetrics } from '../../../common/metrics/paint-metrics'
import { submitData } from '../../../common/util/submit-data'
import { getConfigurationValue, getInfo, getRuntime } from '../../../common/config/config'
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler'
import { Harvest } from '../../../common/harvest/harvest'
import * as CONSTANTS from '../constants'
import { getActivatedFeaturesFlags } from './initialized-features'
import { globalScope, isBrowserScope } from '../../../common/util/global-scope'
import { drain } from '../../../common/drain/drain'
import { FeatureBase } from '../../utils/feature-base'
import { activateFeatures } from '../../../common/util/feature-flags'
import { warn } from '../../../common/util/console'

const jsonp = 'NREUM.setToken'

Expand Down Expand Up @@ -55,10 +55,12 @@ export class Aggregate extends FeatureBase {

sendRum () {
const info = getInfo(this.agentIdentifier)
const agentRuntime = getRuntime(this.agentIdentifier)
const harvester = new Harvest(this)

if (!info.beacon) return
if (info.queueTime) this.aggregator.store('measures', 'qt', { value: info.queueTime })
if (info.applicationTime) this.aggregator.store('measures', 'ap', { value: info.applicationTime })
const agentRuntime = getRuntime(this.agentIdentifier)

// These 3 values should've been recorded after load and before this func runs. They are part of the minimum required for PageView events to be created.
// Following PR #428, which demands that all agents send RUM call, these need to be sent even outside of the main window context where PerformanceTiming
Expand All @@ -67,27 +69,26 @@ export class Aggregate extends FeatureBase {
this.aggregator.store('measures', 'fe', { value: isBrowserScope ? agentRuntime[CONSTANTS.FBTWL] : 0 })
this.aggregator.store('measures', 'dc', { value: isBrowserScope ? agentRuntime[CONSTANTS.FBTDC] : 0 })

var measuresMetrics = this.aggregator.get('measures')

var measuresQueryString = mapOwn(measuresMetrics, function (metricName, measure) {
return '&' + metricName + '=' + measure.params.value
}).join('')

// currently we only have one version of our protocol
// in the future we may add more
var protocol = '1'

var scheduler = new HarvestScheduler('page_view_event', {}, this)

var chunksForQueryString = [scheduler.harvest.baseQueryString()]

chunksForQueryString.push(measuresQueryString)
const queryParameters = {
tt: info.ttGuid,
us: info.user,
ac: info.account,
pr: info.product,
af: getActivatedFeaturesFlags(this.agentIdentifier).join(','),
...(
Object.entries(this.aggregator.get('measures') || {}).reduce((aggregator, [metricName, measure]) => {
aggregator[metricName] = measure.params?.value
return aggregator
}, {})
),
xx: info.extra,
ua: info.userAttributes,
at: info.atts
}

chunksForQueryString.push(param('tt', info.ttGuid))
chunksForQueryString.push(param('us', info.user))
chunksForQueryString.push(param('ac', info.account))
chunksForQueryString.push(param('pr', info.product))
chunksForQueryString.push(param('af', getActivatedFeaturesFlags(this.agentIdentifier).join(',')))
const body = {
custom: info.jsAttributes
}

if (globalScope.performance) {
if (typeof PerformanceNavigationTiming !== 'undefined') { // Navigation Timing level 2 API that replaced PerformanceTiming & PerformanceNavigation
Expand All @@ -96,13 +97,13 @@ export class Aggregate extends FeatureBase {
timing: addPT(agentRuntime.offset, navTimingEntry, {}),
navigation: addPN(navTimingEntry, {})
})
chunksForQueryString.push(param('perf', stringify(perf)))
queryParameters.perf = stringify(perf)
} else if (typeof PerformanceTiming !== 'undefined') { // Safari pre-15 did not support level 2 timing
const perf = ({
timing: addPT(agentRuntime.offset, globalScope.performance.timing, {}, true),
navigation: addPN(globalScope.performance.navigation, {})
})
chunksForQueryString.push(param('perf', stringify(perf)))
queryParameters.perf = stringify(perf)
}
}

Expand All @@ -112,32 +113,22 @@ export class Aggregate extends FeatureBase {
if (!entry.startTime || entry.startTime <= 0) return

if (entry.name === 'first-paint') {
chunksForQueryString.push(param('fp', String(Math.floor(entry.startTime))))
queryParameters.fp = String(Math.floor(entry.startTime))
} else if (entry.name === 'first-contentful-paint') {
chunksForQueryString.push(param('fcp', String(Math.floor(entry.startTime))))
queryParameters.fcp = String(Math.floor(entry.startTime))
}
paintMetrics[entry.name] = Math.floor(entry.startTime) // this is consumed by Spa module
})
} catch (e) {}

chunksForQueryString.push(param('xx', info.extra))
chunksForQueryString.push(param('ua', info.userAttributes))
chunksForQueryString.push(param('at', info.atts))

var customJsAttributes = stringify(info.jsAttributes)
chunksForQueryString.push(param('ja', customJsAttributes === '{}' ? null : customJsAttributes))

var queryString = fromArray(chunksForQueryString, agentRuntime.maxBytes)

// Capture bytes sent to RUM call endpoint (currently `1`) as a supportability metric. See metrics aggregator (on unload).
agentRuntime.bytesSent[protocol] = (agentRuntime.bytesSent[protocol] || 0) + queryString?.length || 0

const isValidJsonp = submitData.jsonp(
this.getScheme() + '://' + info.beacon + '/' + protocol + '/' + info.licenseKey + queryString,
jsonp
)
// Usually `drain` is invoked automatically after processing feature flags contained in the JSONP callback from
// ingest (see `activateFeatures`), so when JSONP cannot execute (as with module workers), we drain manually.
if (!isValidJsonp) drain(this.agentIdentifier, CONSTANTS.FEATURE_NAME)
harvester.send('rum', { qs: queryParameters, body }, { needResponse: true }, undefined, ({ responseText }) => {
try {
activateFeatures(JSON.parse(responseText), this.agentIdentifier)
drain(this.agentIdentifier, this.featureName)
} catch (err) {
handle('ierr', [err, performance.now(), true], undefined, this.featureName, this.ee)
warn('RUM call failed. Agent shutting down.', err)
}
})
}
}
1 change: 0 additions & 1 deletion src/loaders/configure/configure.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export function configure (agentIdentifier, opts = {}, loaderType, forceDrain) {
gosNREUMInitializedAgents(agentIdentifier, api, 'api')
gosNREUMInitializedAgents(agentIdentifier, exposed, 'exposed')
addToNREUM('activatedFeatures', activatedFeatures)
addToNREUM('setToken', (flags) => activateFeatures(flags, agentIdentifier))

return api
}
20 changes: 10 additions & 10 deletions tools/browsers-lists/browsers-supported.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
"chrome": [
{
"browserName": "chrome",
"platformName": "Windows 10",
"platform": "Windows 10",
"version": "103",
"browserVersion": "103"
"platformName": "Windows 11",
"platform": "Windows 11",
"version": "104",
"browserVersion": "104"
},
{
"browserName": "chrome",
"platformName": "Windows 10",
"platform": "Windows 10",
"version": "106",
"browserVersion": "106"
"version": "107",
"browserVersion": "107"
},
{
"browserName": "chrome",
Expand All @@ -34,15 +34,15 @@
"browserName": "MicrosoftEdge",
"platformName": "Windows 10",
"platform": "Windows 10",
"version": "103",
"browserVersion": "103"
"version": "104",
"browserVersion": "104"
},
{
"browserName": "MicrosoftEdge",
"platformName": "Windows 11",
"platform": "Windows 11",
"version": "106",
"browserVersion": "106"
"version": "107",
"browserVersion": "107"
},
{
"browserName": "MicrosoftEdge",
Expand Down
7 changes: 6 additions & 1 deletion tools/testing-server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,12 @@ class TestServer {

constructor (config) {
if (!config.logger) {
config.logger = console
const consoleLogger = {
...console,
fatal: console.error,
child: () => consoleLogger
}
config.logger = consoleLogger
}

this.#config = config
Expand Down
10 changes: 6 additions & 4 deletions tools/testing-server/plugins/bam-parser/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@ module.exports = fp(async function (fastify, testServer) {
'text/plain',
{ parseAs: 'string' },
(request, body, done) => {
if (!body || typeof body !== 'string' || body.trim().length === 0) return done(null, body)

if (request.url.match(beaconRequestsRegex)) {
if (body.startsWith('bel.')) {
try {
done(null, querypack.decode(body))
return done(null, querypack.decode(body))
} catch (error) {
done(error, body)
return done(error, body)
}
} else {
try {
done(null, JSON.parse(body))
return done(null, JSON.parse(body))
} catch (error) {
done(error, body)
return done(error, body)
}
}
}
Expand Down

0 comments on commit edc367e

Please sign in to comment.