-
Notifications
You must be signed in to change notification settings - Fork 66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add resource and navigation event filtering #419
Conversation
ce95bc8
to
e44c803
Compare
CHANGELOG.md
Outdated
@@ -2,6 +2,29 @@ | |||
|
|||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. | |||
|
|||
## [1.14.0](https://github.com/aws-observability/aws-rum-web/compare/v1.12.0...v1.14.0) (2023-06-21) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: Use separate PRs to prepare a new release version.
The best practice is to use a separate review process for each unrelated change. This (1) makes it easier to review the change, (2) ensures issues with one change don't block the review/release process for another, and (3) makes it easy to revert changes.
docs/configuration.md
Outdated
@@ -138,6 +138,26 @@ telemetries: [ | |||
| recordAllRequests | boolean | `false` | By default, only HTTP failed requests (i.e., those with network errors or status codes which are not 2xx) are recorded. When this field is `true`, the http telemetry will record all requests, including those with successful 2xx status codes. <br/><br/>This field does **does not apply** to X-Ray traces, where all requests are recorded. | | |||
| addXRayTraceIdHeader | boolean | `false` | By default, the `X-Amzn-Trace-Id` header will not be added to the HTTP request. This means that the client-side trace and server-side trace will **not be linked** in X-Ray or the ServiceLens graph.<br/><br/> When this field is `true`, the `X-Amzn-Trace-Id` header will be added to HTTP requests (`XMLHttpRequest` or `fetch`). **Adding the header is dangerous and you must test your application before setting this field to `true` in a production environment.** The header could cause CORS to fail or invalidate the request's signature if the request is signed with sigv4. | |||
|
|||
## Resource |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: I feel like the Performance
configuration is the correct place to put this configuration option. This would (1) give it a similar pattern to the Errors
configuration, and (2) give users control over all PerformanceEntry .
Performance
Name | Type | Default | Description |
---|---|---|---|
eventLimit | Number | 10 |
The maximum number of resources to record ... |
ignore | Function | (entry: PerformanceEntry) => { ... } |
A function which accepts a PerformanceEntry and returns a boolean that determines if the PerformanceEntry should be ignored. By default, PerformanceResourceTiming entries from browser extensions are ignored. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That can work. ignore()
can be shared between NavigationPlugin
and ResourcePlugin
in perfromance config, since both use the PerformanceResourceTiming
interface. (PerformanceEntry doesn't contain many useful fields for users to ignore).
However, does that mean eventLimit
should also be shared and implemented in NavigationPlugin
and WebVitalsPlugin
? Currently, only ResourcePlugin
receives the performance config
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how to ignore PerformanceEntries that come from browser extensions at the moment. I have to do some digging
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PerformanceEntry doesn't contain many useful fields for users to ignore
PerformanceEntry has multiple subclasses, and is actively being extended. Rather than provide a configuration option for each subclass, why not provide a single one that can be overloaded?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, only ResourcePlugin receives the performance config
Yes the other plugins will need access to the config.
However, does that mean eventLimit should also be shared and implemented in NavigationPlugin and WebVitalsPlugin?
No, all navigation events and web vitals events should be recorded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PerformanceEntry doesn't contain many useful fields for users to ignore
PerformanceEntry has multiple subclasses, and is actively being extended. Rather than provide a configuration option for each subclass, why not provide a single one that can be overloaded?
My refactor stores ignore(performanceEntry) in performance config. And performanceEntry can be type cast as PerformanceResourceTiming
for resource events or PerformanceNavigationTiming
for navigation events.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how to ignore PerformanceEntries that come from browser extensions at the moment. I have to do some digging
This has been solved by just looking for a chrome-extension*
prefix
@@ -117,20 +120,22 @@ export class ResourcePlugin extends InternalPlugin { | |||
} | |||
}; | |||
|
|||
recordResourceEvent = (entryData: PerformanceResourceTiming): void => { | |||
private isPutRumEventCall(eventData: PerformanceResourceTiming) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I like these refactorings, but they should be submitted as a separate PR since they are unrelated to adding a filter for timing events.
Things like this are easy to review and should get approved quickly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kept it for now, but in the future I will put them in a separate PR. Or at the very least, keep the commits separate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not fix it now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed, along with other unrelated refactors
CHANGELOG.md
Outdated
### Features | ||
|
||
* add ignore callback to resource plugin config ([3fd4d7b](https://github.com/aws-observability/aws-rum-web/commit/3fd4d7b184645e21e66f0ab199d3823c7a4435ee)) | ||
* Create a session ID when cookies are disabled ([#314](https://github.com/aws-observability/aws-rum-web/issues/314)) ([6943587](https://github.com/aws-observability/aws-rum-web/commit/6943587259b8d7623742656199dc26b26b5bcd5d)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like some features are being duplicated from 1.13.0 and 1.14.0
Please double check what is included in this release that was not included 1.13.0
Eg - referrer change went out in 1.13.0
As mentioned above, separate PR is better for release commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the version bump
docs/configuration.md
Outdated
## Resource | ||
| Name | Type | Default | Description | | ||
| --- | --- | --- | --- | | ||
| ignore | Function(event: ResourceEvent) : boolean | `() => false` | A function which accepts a ResourceEvent and returns a boolean that determines if the [resource event](https://github.com/aws-observability/aws-rum-web/blob/main/src/event-schemas/resource-event.json) should be ignored. By default, no resources are ignored. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
name should be ignoreEvent
nit: For errors we have something similar and use ignore
. For consistency should we use the same name since it seems both are doing the similar operations.
Ref: https://github.com/aws-observability/aws-rum-web/blob/7258bb74d6376334d0e4501d3c15b875dcd41b36/docs/configuration.md#errors
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. Originally, I had planned to do ignore(PerformanceResourceTiming)
, and then changed my mind a forgot to fix the name
@@ -250,4 +247,24 @@ describe('ResourcePlugin tests', () => { | |||
}) | |||
); | |||
}); | |||
|
|||
test('resource plugin ignores resources based on a custom condition', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: write test description in format when <action> then <expected behavior>
(see above unit tests for reference).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored
Versions should be updated as a separate PR This reverts commit 7258bb7.
fda486c
to
8adc302
Compare
7982fdd
to
685a6a1
Compare
026d934
to
1992ee6
Compare
|
||
describe('performance-utils', () => { | ||
describe('defaultPerformanceIgnore', () => { | ||
test('when resource entry is PerformanceEntry and has non-http(s) URL schema then entry is ignored', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: PerformanceEntry can be considered an "abstract class".
According to its documentation, "The PerformanceEntry instances will always be one of the following subclasses...".
We don't need to test each type separately. It is sufficient to test the following cases.
- "when entry has a non-http URL schema then entry is ignored"
- "when entry has an http URL schema then entry is not ignored"
- "when entry has an https URL schema then entry is not ignored"
- "when entry is not type PerformanceResourceTiming then entry is not ignored"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reduced the unit tests to those four you have specified
const mockEntry = mockPerformanceEntry({ | ||
name: 'chrome-extension://localhost', | ||
entryType: 'resource' | ||
}); | ||
const result = defaultPerformanceIgnore(mockEntry); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and elsewhere.
const mockEntry = mockPerformanceEntry({ | |
name: 'chrome-extension://localhost', | |
entryType: 'resource' | |
}); | |
const result = defaultPerformanceIgnore(mockEntry); | |
const result = defaultPerformanceIgnore({ | |
entryType: 'resource', | |
name: 'chrome-extension://localhost' | |
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
refactored!
src/test-utils/mock-data.ts
Outdated
export const mockPerformanceEntry = (partialEntry?: any): PerformanceEntry => ({ | ||
name: 'localhost', | ||
entryType: 'resource', | ||
duration: 10, | ||
startTime: 0, | ||
...partialEntry | ||
}); | ||
|
||
export const mockPerformanceResourceTiming = ( | ||
partialEntry?: any | ||
): PerformanceResourceTiming => ({ | ||
...mockPerformanceEntry(), | ||
...partialEntry, | ||
entryType: 'resource' | ||
}); | ||
|
||
export const mockPerformanceNavigationTiming = ( | ||
partialEntry?: any | ||
): PerformanceNavigationTiming => ({ | ||
...mockPerformanceEntry(), | ||
...partialEntry, | ||
entryType: 'navigation' | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: We can omit these. The tests for performance-utils are already minimal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
deleted
High level comment: consider updating the description of PR accounting for these new changes in the revisions. |
eventLimit: number; | ||
ignore: (event: PerformanceEntry) => any; | ||
recordAllTypes: ResourceType[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: we need to update the performance config documentation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documentation for eventLimit
, recordAllTypes
and sampleTypes
has never existed, so there's no regression or omission with respect to this PR.
Let's close out this PR and track that separately.
@@ -72,6 +54,7 @@ export class ResourcePlugin extends InternalPlugin { | |||
const resourceObserver = new PerformanceObserver((list) => { | |||
list.getEntries() | |||
.filter((e) => e.entryType === RESOURCE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: is this entryType check redundant?
resourceObserver.observe({
entryTypes: [RESOURCE]
});
@@ -72,6 +54,7 @@ export class ResourcePlugin extends InternalPlugin { | |||
const resourceObserver = new PerformanceObserver((list) => { | |||
list.getEntries() | |||
.filter((e) => e.entryType === RESOURCE) | |||
.filter((e) => !this.config.ignore(e)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: is the stream...filter pattern for readability?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my perspective, yes, this is about improving readability.
updated |
@@ -194,3 +194,21 @@ const awsRum: AwsRum = new AwsRum( | |||
| Name | Type | Default | Description | | |||
| --- | --- | --- | --- | | |||
| eventLimit | Number | `10` | The maximum number of resources to record load timing. <br/><br/>There may be many similar resources on a page (e.g., images) and recording all resources may add expense without adding value. The web client records all HTML files and JavaScript files, while recording a sample of stylesheets, images and fonts. Increasing the event limit increases the maximum number of sampled resources. | | |||
| ignore | Function(event: PerformanceEntry) : any | `(entry: PerformanceEntry) => !/^https?:/.test(entry.name)` | A function which accepts a [PerformanceEntry](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEntry) and returns a value that coerces to true when the PerformanceEntry should be ignored.</br></br> By default, [PerformanceResourceTiming](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming) entries with URLs that do not have http(s) schemes are ignored. This causes resources loaded by browser extensions to be ignored. | | |||
|
|||
For example, the following telemetry config array causes the web client to ignore all resource entries. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: As thought exercise, any other common ways customers might use ignore? If yes, we can add examples along that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had some other examples, such as blocking a hostname or type casting entry
into other subclasses, but I was asked to remove them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we can consider in future iterations of doc updates/improvements based on customer experience with this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes absolutely
@@ -194,7 +194,7 @@ const awsRum: AwsRum = new AwsRum( | |||
| Name | Type | Default | Description | | |||
| --- | --- | --- | --- | | |||
| eventLimit | Number | `10` | The maximum number of resources to record load timing. <br/><br/>There may be many similar resources on a page (e.g., images) and recording all resources may add expense without adding value. The web client records all HTML files and JavaScript files, while recording a sample of stylesheets, images and fonts. Increasing the event limit increases the maximum number of sampled resources. | | |||
| ignore | Function(event: PerformanceEntry) : any | `(entry: PerformanceEntry) => !/^https?:/.test(entry.name)` | A function which accepts a [PerformanceEntry](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEntry) and returns a value that coerces to true when the PerformanceEntry should be ignored.</br></br> By default, [PerformanceResourceTiming](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming) entries with URLs that do not have http(s) schemes are ignored. This causes resources loaded by browser extensions to be ignored. | | |||
| ignore | Function(event: PerformanceEntry) : any | `(entry: PerformanceEntry) => entry.entryType === 'resource' && !/^https?:/.test(entry.name)` | A function which accepts a [PerformanceEntry](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEntry) and returns a value that coerces to true when the PerformanceEntry should be ignored.</br></br> By default, [PerformanceResourceTiming](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming) entries with URLs that do not have http(s) schemes are ignored. This causes resources loaded by browser extensions to be ignored. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch, thank you
Why (updated)
Users currently have no way to filter out unwanted performance events. One story is that customers are receiving a lot of noisy resource events from chrome extensions.
Changes
Users can filter resource events by supplying a
ignore(entry: PerformanceEntry)
to PerformanceConfig. This enables PerformanceObserver to ignore specified PerformanceResourceTiming entries, which are used to create RUM ResourceEvents.In addition,
ignore()
also configures the NavigationPlugin, which uses a PerformanceObserver to create NavigationEvents. Here, customers can look for PerformanceNavigationTiming entries and ignore them if need be.The default configuration is that only resource events with non-http URL schemas are ignored. This will ignore resource events from browser extensions, which typically follow non-http URL schemas (e.g. "chrome-extension://*").
Revisions
Revision 4:
Revision 3:
Revision 2:
ignore()
receives PerformanceEntryignore()
is defined in PerformanceConfig and shared between NavigationPlugin and ResourcePlugin. Note: only resource level 2 events are subject to ignoringBy submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.