Skip to content

Commit

Permalink
fix(rum): listen to all page clicks (#1219)
Browse files Browse the repository at this point in the history
* fix(rum): listen to all page clicks
  • Loading branch information
devcorpio authored May 12, 2022
1 parent a1a708a commit 6746baf
Show file tree
Hide file tree
Showing 26 changed files with 410 additions and 650 deletions.
4 changes: 3 additions & 1 deletion docs/configuration.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,16 @@ The valid options are:
* `page-load`
* `history`
* `eventtarget`
* `click`
* `xmlhttprequest`
* `fetch`
* `error`

NOTE: To disable all `http-request` transactions, add both `fetch` and `xmlhttprequest`.
to this config.

NOTE: To disable `user-interaction` transactions, add `eventtarget` to this config.
NOTE: To disable `user-interaction` transactions, add `eventtarget` or `click` to this config.
The option `eventtarget` is deprecated and will be removed in the future releases.

[float]
[[environment]]
Expand Down
8 changes: 7 additions & 1 deletion packages/rum-core/src/common/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ const QUEUE_ADD_TRANSACTION = 'queue:add_transaction'
const XMLHTTPREQUEST = 'xmlhttprequest'
const FETCH = 'fetch'
const HISTORY = 'history'
const EVENT_TARGET = 'eventtarget'
const EVENT_TARGET = 'eventtarget' //@deprecated, it will be removed in the first 6.x release
const CLICK = 'click'
const ERROR = 'error'

/**
Expand Down Expand Up @@ -157,6 +158,8 @@ const CONFIG_SERVICE = 'ConfigService'
const LOGGING_SERVICE = 'LoggingService'
const TRANSACTION_SERVICE = 'TransactionService'
const APM_SERVER = 'ApmServer'
const PERFORMANCE_MONITORING = 'PerformanceMonitoring'
const ERROR_LOGGING = 'ErrorLogging'

/**
* Truncated spans are associated with this type information
Expand Down Expand Up @@ -201,6 +204,7 @@ export {
FETCH,
HISTORY,
EVENT_TARGET,
CLICK,
ERROR,
BEFORE_EVENT,
AFTER_EVENT,
Expand All @@ -223,6 +227,8 @@ export {
LOGGING_SERVICE,
TRANSACTION_SERVICE,
APM_SERVER,
PERFORMANCE_MONITORING,
ERROR_LOGGING,
TRUNCATED_TYPE,
FIRST_INPUT,
LAYOUT_SHIFT,
Expand Down
6 changes: 4 additions & 2 deletions packages/rum-core/src/common/instrument.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ import {
HISTORY,
PAGE_LOAD,
ERROR,
EVENT_TARGET
EVENT_TARGET,
CLICK
} from './constants'

export function getInstrumentationFlags(instrument, disabledInstrumentations) {
Expand All @@ -42,7 +43,8 @@ export function getInstrumentationFlags(instrument, disabledInstrumentations) {
[HISTORY]: false,
[PAGE_LOAD]: false,
[ERROR]: false,
[EVENT_TARGET]: false
[EVENT_TARGET]: false,
[CLICK]: false
}

if (!instrument) {
Expand Down
29 changes: 29 additions & 0 deletions packages/rum-core/src/common/observers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* MIT License
*
* Copyright (c) 2017-present, Elasticsearch BV
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/

import { observePageVisibility } from './page-visibility'
import { observePageClicks } from './page-clicks'

export { observePageVisibility, observePageClicks }
98 changes: 98 additions & 0 deletions packages/rum-core/src/common/observers/page-clicks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/**
* MIT License
*
* Copyright (c) 2017-present, Elasticsearch BV
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/

import { USER_INTERACTION } from '../constants'

export function observePageClicks(transactionService) {
const clickHandler = event => {
// Real user clicks interactions will always be related to an Element.
// And since the goal is to maximise the capture of such interactions
// events synthetically dispatched through Window (window.dispatch) and Document (document.dispatch)
// will not be handled.
if (event.target instanceof Element) {
createUserInteractionTransaction(transactionService, event.target)
}
}

const eventName = 'click'
const useCapture = true
window.addEventListener(eventName, clickHandler, useCapture)

return () => {
window.removeEventListener(eventName, clickHandler, useCapture)
}
}

function createUserInteractionTransaction(transactionService, target) {
const { transactionName, context } = getTransactionMetadata(target)

/**
* We reduce the reusability threshold to make sure
* we only capture async activities (e.g. network)
* related to this interaction.
*/
const tr = transactionService.startTransaction(
`Click - ${transactionName}`,
USER_INTERACTION,
{
managed: true,
canReuse: true,
reuseThreshold: 300
}
)

if (tr && context) {
tr.addContext(context)
}
}

function getTransactionMetadata(target) {
const metadata = {
transactionName: null,
context: null
}

const tagName = target.tagName.toLowerCase()

// use custom html attribute 'data-transaction-name' - otherwise fall back to "tagname" + "name"-Attribute
let transactionName = tagName
if (!!target.dataset.transactionName) {
transactionName = target.dataset.transactionName
} else {
const name = target.getAttribute('name')
if (!!name) {
transactionName = `${tagName}["${name}"]`
}
}

metadata.transactionName = transactionName

let classes = target.getAttribute('class')
if (classes) {
metadata.context = { custom: { classes } }
}

return metadata
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
*
*/

import { QUEUE_ADD_TRANSACTION, QUEUE_FLUSH } from './constants'
import { state } from '../state'
import { now } from './utils'
import { QUEUE_ADD_TRANSACTION, QUEUE_FLUSH } from '../constants'
import { state } from '../../state'
import { now } from '../utils'

/**
* @param configService
Expand Down
Loading

0 comments on commit 6746baf

Please sign in to comment.