README
Atlassian browser-metrics
browser-metrics vs browser-metrics-plugin
This project is a bare-bones JavaScript library, but if you're working on a product (e.g. JIRA / Confluence / Bitbucket / Bamboo), you're going to want to use browser-metrics-plugin which bundles this library inside an Atlassian Plugin, and provides some better integration with the Atlassian Platform.
Installation
Bower
Add the following to your bower.json
:
"dependencies": {
"browser-metrics": "ssh://git@bitbucket.org/atlassian/browser-metrics.git#v4.0.0"
}
There are two files that need to be executed in the browser:
dist/probe.js
(must be loaded synchronously)dist/collector.js
(may be loaded asynchronously)
Assuming you serve these files from /static/
, you'd add the following HTML to your page:
<script type="text/javascript" src="/static/probe.js"></script>
<script type="text/javascript" src="/static/collector.js" async></script>
Usage
browser-metrics allows subscribers to receive beacons that report on transitions that have been instrumented in the application:
var metrics = window["browser-metrics"];
metrics.start({
key: "jira.issue.view",
isInitial: true,
threshold: 1000
});
// some time later…
metrics.end({key: "jira.issue.view"});
// some where else
metrics.subscribe(function (beacon) {
console.log(beacon); // {report: {readyForUser: …, …}}
});
A note for IE support
If you need to support Internet Explorer, make sure your page contains:
<meta http-equiv="X-UA-Compatible" content="IE=edge;" />
API
The fundamental idea in browser-metrics is to measure the duration of a transition where the application is changing from one state to another. A "transition" is a general term that may refer to:
- Navigating from one page to another.
- Opening a dropdown menu.
- Submitting a form.
browser-metrics is designed to be able to measure classic "full page" navigating, in addition to modern "single page app" aka JavaScript transitions.
The API requires developers to explicitly declare the start and end of a transition.
→ .start().end()
The typical use of the browser-metrics API is to call .start()
when the transition begins, and later call .end()
after the transition has completed.
var metrics = window["browser-metrics"];
metrics.start({
key: "jira.issue.split-view",
isInitial: …,
threshold: 1000
});
// Some time later...
metrics.end({key: "jira.issue.split-view"});
Calls to .end()
with a key that does not correspond to the most recent call to .start()
are ignored.
options .start()
The following options can be
key
(string
, required)A dotted-path style string that's used as the atlassian-analytics event name.
The string must match the following syntax:
<product>.<page>
e.g.
jira.view-issue
. Don't put any.
in<product>
, or the post-processing we do will not work (we split on the first.
).isInitial
(boolean
, optional)If specified, indicates whether the transition is a "full page load". If not specified, this will be determined automatically based on whether or not
DOMContentLoaded
has fired.browser-metrics takes special care to record the browser's navigation timing in its report, however it only does this for full page loads. To avoid needing to specify
isInitial
, a convenience feature is supported which will implicitly causeisInitial: true
if.start()
is called before or during theDOMContentLoaded
event. e.g.// before DOMContentLoaded var metrics = window["browser-metrics"]; if (document.readyState !== "complete") { metrics.start({key: "jira.issue-view"}); // isInitial=true } // or during DOMContentLoaded document.addEventListener("DOMContentLoaded", function() { metrics.start({key: "jira.issue-view"}); // isInitial=true }); // but not after DOMContentLoaded document.addEventListener("DOMContentLoaded", function() { setTimeout(function () { metrics.start({key: "jira.issue-view"}); // isInitial=false }, 0); });
Be careful when using
jQuery.ready()
, as it executes the callback immediately ifDOMContentLoaded
has already fired. This means you may unintentionally getisInitial: false
when you expectedisInitial: true
.In practice it's probably better to explicitly specify
isInitial
to reduce ambiguity.threshold
(integer
, optional, default:1000
)Declares the target (in milliseconds) duration for the transition. The performance of the transition is considered good if it completes within this threshold.
This option allows for apdex to be calculated on the transition.
Note: The default value
1000
is used for backwards compatibility with code that written before this option was introduced. Prior to this option's existence, "page loads" were the only type of transitions being measured, and the threshold for those was 1 seconds.ready
(any
, optional, use with caution)Note: This is only supported on browsers where
MutationObserver
andPromise
are available. On unsupported browsers this option is ignored, and measurements are not made.A description of DOM elements that must exist in the DOM for the page to be considered "done". Using this option avoids needing to manually call
.end()
. This is supposed to be a "friendly" API that is easy to adopt to existing codebases where "the page is loaded" JavaScript hooks don't exist.If you care only about a single element, pass a single CSS selector.
If multiple elements need to be present, pass an array of selectors. After all selectors have matched, the page is considered loaded:
metrics.start({ key: "jira.issue.split-view", ready: [ ".content-thing", "#another-thing > .something" ] });
Performance needs to be considered here -- as you add more selectors, more overhead is added to DOM mutation. To improve performance, keep the number of selectors to a minimum, and keep each selector simple (avoid child/descendant selectors).
The semantics of when an element is "present" fall into two scenarios:
- If the selector immediately matches one or more elements in the DOM, that selector is considered to be satisfied.
- If the selector doesn't immediately match any elements in the DOM, as soon as an element in the DOM matches the selector it is considered satisfied. This can either happen by it being inserted directly or as part of a subtree, or being exposed via an attribute change to an ancestor.
If you are interested in some task which is in progress currently and will be resolved at some point in time, you can use "hasNone" condition along with selector. The idea is to insert an element with certain CSS selector inside parent container so it will be a flag of that work for this container is still in progress (i.e. content not fully loaded):
metrics.start({ key: "jira.issue.split-view", ready: [ { selector: ".parent-content-thing", hasNone: ".loading" // <-- presence of this element inside "selector" indicates work is in progress }, "#another-thing > .something" ] });
It means that in order to submit event timings we have to wait until there won't be any elements inside parent container (which is discovered using "selector") matching "hasNone".
By default the
ready
options only makes guarantees about DOM state (as opposed to the CSSOM and render tree). This means that there's no guarantee that the DOM has actually been painted, and under certain scenarios can give wildly inaccuratereadyForUser
values.A
requirePaint
option is available forready
to require a paint, which avoids this problem:metrics.start({ key: "jira.issue.split-view", ready: { rules: [ { selector: ".parent-content-thing", hasNone: ".loading" // <-- presence of this element inside "selector" indicates work is in progress }, "#another-thing > .something" ], requirePaint: true } });
reporters
(function
, optional)Reporters that will get called when transition report is created. Reporters defined via
reporters
option are used only for single transition and are always executed in the end. They are useful in two cases:- appending additional information to a transition report, for example some application state that may influence measurement;
- overwriting data supplied by global reporters.
Reporters declared with this option should conform to the Reporter contract described in Reporters section below.
.find(conditions, callback)
Note: This is only supported on browsers where MutationObserver
and Promise
are available. On unsupported
browsers it does nothing.
.find()
is a utility method that finds elements in DOM. This is what .start({ready: ...})
uses underneath.
It is useful for gathering timings of element availability:
metrics.find([
".issue-key"
]).then(function() {
window.performacne && window.performance.mark('issue.visible');
});
Method returns a Promise, which is resolved after elements described by conditions
are found. It will also execute
callback
passed as a second argument.
Conditions can be defined in two forms:
- Single selector - Promise is resolved when any element matches it
- Array of selectors - Promise is resolved when all elements are matched
As with the ready
parameter of .start()
method, additional hasNone
parameter can be used. It means that Promise is
resolved when there won't be any elements inside parent container (which is discovered using "selector") matching "hasNone".
metrics.find([
{
selector: '.parent-issue-container',
hasNone: '.loading' // // <-- presence of this element inside "selector" indicates work is in progress
},
'.some-other-selector'
]).then(function() {
window.performacne && window.performance.mark('issue.loaded');
});
Push-state style navigation
Using the API you can also record push-state style navigation events:
var metrics = window["browser-metrics"];
$.on("a.rapid-board", "click", function (event) {
metrics.start({key: "jira.rapid-board"});
// bind to some app event that announces when a navigation is done, and call metrics.end({key: "jira.rapid-board"})
// <some single-page-app style navigation>
event.preventDefault();
});
Reporters
It's possible to include extra information for transition reports by writing a custom reporter. A simple use-case is including backend performance metrics for initial transitions (full page loads):
var metrics = window["browser-metrics"];
metrics.addReporter(function backendPerformanceReporter(transition) {
var report = {};
if (transition.isInitial) {
report.backendRender = get_backend_render_time();
}
return report;
});
This example adds a backendRender
property to the report
object in the beacon for initial transitions.
Reporters are passed a Transition
object that describes the transition that has just taken place, and must return
a report. The exact API is as follows:
/**
* @typedef {Object} Transition
* @property {boolean} transition.isInitial True if the transition event was part of a full page load.
* @property {string} transition.key An identifier for the transition.
* @property {number} transition.end The number of milliseconds since UNIX epoch when the transition finished
* (either `.end()` was explicitly called or `.start({ready: ...})` was satisfied).
* @property {number} transition.start The number of milliseconds since UNIX epoch when `.start()` was called.
* @property {number} transition.threshold The maximum "tolerable" duration for the transition (in
* milliseconds).
*/
/**
* @param {Transition} transition A description of the transition event that has just occurred.
* @returns {Promise<object>|jQuery.Promise<object>|object} A hash of keys/values to contribute to the final analytics event.
*/
function Reporter(transition) { ... }
Be aware that there are limits on the size of analytics events. If you're concerned you may exceed these limits, chat to your nearest performance engineer.
A reporter returning a rejected promise is equivalent to it returning {}
, i.e. the reporter simply does not contribute
to the report.
Report fields
apdex
The apdex score for the transition.
This field is a convenience that precomputes the apdex based on the threshold
and readyForUser
fields. This field
is included in every transition. As the apdex is for a single transition, the value is either 0
, 0.5
, 1
.
Added in v1.61.1
Example
{
apdex: 0.5
}
connectStart
The value of window.performance.timing.connectStart
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
connectStart: 1
}
connectEnd
The value of window.performance.timing.connectEnd
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
connectEnd: 1
}
domainLookupEnd
The value of window.performance.timing.domainLookupEnd
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
domainLookupEnd: 1
}
domainLookupStart
The value of window.performance.timing.domainLookupStart
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
domainLookupStart: 1
}
domContentLoadedEventStart
The value of window.performance.timing.domContentLoadedEventStart
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
domContentLoadedEventStart: 1
}
domContentLoadedEventEnd
The value of window.performance.timing.domContentLoadedEventEnd
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
domContentLoadedEventEnd: 1
}
domComplete
The value of window.performance.timing.domComplete
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
domComplete: 1
}
domLoading
The value of window.performance.timing.domLoading
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
domLoading: 1
}
domInteractive
The value of window.performance.timing.domInteractive
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
domInteractive: 1
}
fetchStart
The value of window.performance.timing.fetchStart
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
fetchStart: 1
}
firstPaint
The time, relative to navigationStart
, that the first paint of the page occurred. Depending on the browser different APIs are used:
- Chrome --
window.chrome.loadTimes().firstPaintTime
- Internet Explorer --
window.performance.timing.msFirstPaint
For other browsers firstPaint
is not reported.
It's interesting to note in (at least) Chrome firstPaint
does not have a value unless the tab is focused (i.e. switched to).
This means that firstPaint
may not always be present in browser-metrics reports.
Consider a scenario where a page is loaded in a background tab. It's possible for window.performance.timing.loadEventEnd
to become non-zero (which is the earliest an initial report can finish)
before the tab is ever presented to the user. Assuming no other reporters hold up the report, firstPaint
will not be captured.
Example
{
firstPaint: 674
}
isInitial
If true
, indicates the transition was a full page load. Otherwise the value false
is used.
Example
{
isInitial: true
}
journeyId
A value that shared across multiple reports that come from transitions that occur within the same "page session". The
definition of "page session" is dependent on the browser, as per their semantics of window.sessionStorage
.
The intent behind this field is to provide a mechanism for tracking the path that a user takes through the application.
Example
{
journeyId: "c8b37285-776b-4a70-94f3-41db9971775e"
}
key
A text key that identifies the transition. This value is pulled verbatim from the .start()
API value.
Example
{
key: "jira.issue.view"
}
loadEventStart
The value of window.performance.timing.loadEventStart
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
loadEventStart: 1
}
loadEventEnd
The value of window.performance.timing.loadEventEnd
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
loadEventEnd: 1
}
navigationType
A number between 0 and 255 that's taken directly from window.performance.navigation.type
.
On browsers that don't support this API, this field is not included in the report.
Example
{
navigationType: 0
}
readyForUser
The number of milliseconds that it took for the transition to complete. For full page load transitions this value is
relative to window.performance.timing.navigationStart
, otherwise it's relative to when .start()
was called.
A transition can become "complete" in two ways:
- The
.stop()
method is called. - The
ready
option to.start()
is used, and becomes satisfied.
Example
{
readyForUser: 428
}
redirectCount
The number of HTTP redirects that occurred before finally loading the page. If the value is 0
, this field is omitted
from the report. This field is only ever present for full page load transitions, and is taken from the
window.performance.navigation.redirectCount
API.
Example
{
redirectCount: 1
}
redirectEnd
The value of window.performance.timing.redirectEnd
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
redirectEnd: 1
}
redirectStart
The value of window.performance.timing.redirectStart
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
redirectStart: 1
}
requestStart
The value of window.performance.timing.requestStart
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
requestStart: 1
}
resourceTiming
This field contains performance timings for each resource (excluding images) which finished downloading during the period of the transition, specifically:
resourceEntry.responseEnd >= transition.start
&& resourceEntry.responseEnd <= transition.end
&& resourceEntry.startTime >= transition.start
The start time for the resource is not intentionally not considered, as it would make some interactions hard to measure. For example consider a situation where a link hover initiates an AJAX request to be made, but the transition is only measured from a click.
Example
{
resourceTiming: [
{
connectEnd: 172.3399999900721
connectStart: 172.3399999900721
domainLookupEnd: 172.3399999900721
domainLookupStart: 172.3399999900721
duration: 766.0440000181552
fetchStart: 172.3399999900721
initiatorType: "link"
name: "http://localhost:8090/jira/s/cf68c932ec46dcad7a69c4c6a6ccaa49-CDN/en_AU-pi800d/71000/b6b48b2829824b869586ac216d119363/5.7.31/_/download/resources/com.atlassian.auiplugin:aui-reset/aui-reset.css"
redirectEnd: 0
redirectStart: 0
requestStart: 900.1189999980852
responseEnd: 938.3840000082273
responseStart: 933.8010000064969
secureConnectionStart: 0
startTime: 172.3399999900721
}
]
}
resourceLoadedEnd
This field contains the number of milliseconds it took for the last synchronous resource to finish loading prior to
domContentLoadedEventStart
. This field may also have the values:
0
— all resources were cached (the value is 0 because in some browsers it's reported this way e.g. Chrome) it's possible that in other browsers this will be a non-zero value even when the resource was cached.null
— no external resources were required in the transition (prior to v5.0.40
was reported in this scenario).
This field is only included if:
- The transition is a full page load.
- The browser supports the Resource Timing API.
Added in v2.0.0
Example
{
resourceLoadedEnd: 428
}
resourceLoadedStart
This field contains the number of milliseconds it took for the first synchronous resource to start loading prior to
domContentLoadedEventStart
. This field may also have the values:
0
— all resources were cached (the value is 0 because in some browsers it's reported this way e.g. Chrome) it's possible that in other browsers this will be a non-zero value even when the resource was cached.null
— no external resources were required in the transition.
This field is only included if:
- The transition is a full page load.
- The browser supports the Resource Timing API.
Added in v5.3.0
Example
{
resourceLoadedStart: 328
}
responseEnd
The value of window.performance.timing.responseEnd
relative to window.performance.timing.navigationStart
. If the
value is 0
this field is omitted.
Example
{
responseEnd: 3
}
responseStart
The value of window.performance.timing.responseStart
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
responseStart: 3
}
secureConnectionStart
The value of window.performance.timing.secureConnectionStart
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
secureConnectionStart: 3
}
threshold
Declares the target (in milliseconds) duration for the transition. The performance of the transition is considered
good if it completes within this threshold. This value is taken from the option passed to .start()
.
The original motivation for this value was to facilitate the calculation of apdex (where we assume that good=threshold
and tolerable=4*threshold
. If we decide to incorporate other index calculations in the future, they can be based off
of this threshold
value too (but with a different weighting function than apdex).
Added in v1.61.1
Example
{
threshold: 1000
}
unloadEventEnd
The value of window.performance.timing.unloadEventEnd
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
unloadEventEnd: 1
}
unloadEventStart
The value of window.performance.timing.unloadEventStart
relative to window.performance.timing.navigationStart
. If
the value is 0
this field is omitted.
Example
{
unloadEventStart: 3
}
userAgent
The user agent string of the browser, as seen from window.navigator.userAgent
.
Example
{
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36"
}
userTiming
User timing API marks and measures that occurred during the transition. Note that not all browsers
support performance.mark()
(e.g. IE10) so you should probably write performance.mark && performance.mark("foo")
to avoid breaking
hard on legacy browsers.
Example
{
marks: [
{
name: "my_mark",
time: 111.11
},
{
name: "my_mark",
time: 222.22
},
{
name: "my_mark_2",
time: 333.33
}
],
measures: [
{
name: "my_measure",
startTime: 444.44
duration: 22
},
{
name: "my_measure",
startTime: 555.55
duration: 33
},
{
name: "my_measure_2",
startTime: 666.66
duration: 44
}
]
}
Development
In the past lots of developers have had problems setting up a dev environment for browser-metrics, because of the many
dependencies needed for building and testing. As a solution the project has moved to using Docker for development, so
there are scripts in ./bin/
that proxy to useful commands.
Alternatively if you want a little more control, drop into a shell in the docker container:
$ ./bin/shell
Dependencies
You need to have docker installed then:
$ ./bin/install
This builds the docker container, and installs NPM, Bower and TSD dependencies.
If docker complains saying Cannot connect to the Docker daemon. Is the docker daemon running on this host?
execute following in console:
docker-machine create --driver virtualbox default
eval "$(docker-machine env default)"
After first docker-machine create
you can do just docker-machine start
calls if system keeps complaining after you quit terminal:
docker-machine start default
eval "$(docker-machine env default)"
Tests
To run all the tests run:
$ ./bin/test
In the event they fail, you'll probably want a little more control over how they're run, so try:
$ ./bin/shell
# ./node_modules/.bin/karma start
This will start karma on port 9876, so make sure you have that port forwarded to your docker machine. Then load up http://localhost:9876 in a browser. The 'debug' button will run the tests in the local window's JS context, so you can debug with standard browser tools.
dist/
)
Packaging (building $ ./bin/build
This will build three files:
dist/probe.js
dist/collector.js
dist/browser-metrics.d.ts
(TypeScript definition)
Builds
https://engservices-bamboo.internal.atlassian.com/browse/BM-BM
Releasing
There's a Bamboo plan to do a release, but first you need to make sure that you've committed all the code changes that occur from:
$ ./bin/test
$ ./bin/build
$ ./bin/npm shrinkwrap
If your working directory is now dirty, you'll need to ensure those changes are correct and commit them before running the plan.
To run the plan:
- Browse to https://engservices-bamboo.internal.atlassian.com/browse/BM-BMR
- Choose Run → Run customised…
- Click "Override a variable"
- Make sure "version" is selected
- Change the value
unset
to the version you want (e.g.5.0.4
) - CLick "Run" (Plan will bump version for you, no need to change it manually in
package.json
)
Demo
To facilitate testing browser-metrics, there's a demo that can be run. It's a simple express.js app:
./bin/demo
Then browse to http://localhost:3000 (make sure you have port 3000 forwarded).
Issues
Found an issue? Raise it on https://jdog.jira-dev.com/browse/BM
Change log
6.1.1
- Check for
window.performance
before executing code that requires it.
6.1.0
- Add
requirePaint
option that can be used withready
. - Fix
resourceTiming
to exclude resources that did not start within the transition.
6.0.0
Removed
requireUpdate
option from.start({ready: …})
.Fix bug in apdex calculation to adhere to the specification:
readyForUser < threshold = 1
→readyForUser <= threshold = 1
threshold <= readyForUser < (threshold × 4) = 0.5
→threshold < readyForUser <= (threshold × 4) = 1
5.3.0
- Add
resourceLoadedStart
attribute that reports the earlieststartTime
of resources. This complementsresourceLoadedEnd
and allows us to improve the per-quantile-breakdown chunks by no longer assuming that resources start downloading atdomLoading
(which is a terrible assumption).
5.2.0
- Added
.find()
API method that allows looking for specific elements in the DOM tree - reporters can now be specified per transition as a
reporters
start()
option
5.1.0
hasNone
forready
condition, which waits for absence of element(s) matching provided CSS selector(s) inside parent container (i.e.selector
).
5.0.5
- made
firstPaint
reporter work properly in iframe environment i.e. - it returns empty report, since browser doesn't providefirstPaint
value in iframes.
5.0.4
resourceLoadedEnd
reporter no longer reports the value0
if no resources were found, and instead reportsnull
, resolves BM-91.- The development environment now uses Docker, which should the issues that a lot of developers have been having with setting up browser-metrics for local development.
- A Bamboo CI test plan has been setup.
5.0.3
- Make
collector.js
use the bundled version of es6-promise, rather than looking for one onwindow
. This fixes a bug in browsers that do not supportwindow.Promise
.
5.0.2
- Switch
collector.js
andprobe.js
to be unminified versions, but addcollector-min.js
andprobe-min.js
which are minified.
5.0.1
- Immediately attempt to drain the resource timing buffer on load, in case it's already full.
5.0.0
- The resourceTiming reporter now includes resources that merely finished within a transition. Previously resources were also required to start within the transition. [backwards incompatible]
4.0.3
- Add support for IE10 / IE11 / MSEdge / Firefox / Opera for the resourceTiming reporter. This was done by not requiring
the
window.performance.addEventListener
to exist, and rather falling back towindow.performnace.onresourcetimingbufferfull
and assuming that exists. - Add a new test page to the demo, and added it (and the other existing page) to the navigation.
- Fix bug for resourceTiming where some values may be
null
rather than0
(affected IE 11).
4.0.2
- Fixed broken 4.0.1 release.
4.0.1
- Make
.addReporter()
API have higher priority than other APIs to ensure that reporters are added first. Note that this only has an effect prior tocollector.js
execution.
4.0.0
BM-31 — Remove ability to disable browser-metrics via WRM data provider (
com.atlassian.plugins.browser.metrics.browser-metrics-plugin:browser-metrics.feature-data-provider-legacy
). [backwards incompatible]BM-85 — Remove legacy browser-metrics. [backwards incompatible]
The term "navigation" as-in
NavigationEvent
has been changed totransition
. The intent is to have a general term that encompasses both "full page loads" and "other navigations". The problem with the term "navigation" is that it has an existing definition in the context of the Web which one might say is "when the URL changes". A "transition" is a much more generic term.Transition
objects have.start
and.end
attributes which are now relative to thenavigationStart
mark. Previously they were relative to UNIX epoch. [backwards incompatible]For initial transitions,
transition.start
is now0
, indicating that the transition started atnavigationStart
. [backwards incompatible]Removed the standalone demo that used herment, as browser-metrics is now agnostic to to all transport mechanisms.
Consolidated the other demos into a single express.js app.
Switched from Grunt to gulp.
Removed AMD style usage from documentation, instead promoting the
window["browser-metrics"]
global variable as it's compatible with async scripts.Remove compression from the
resourceTiming
reporter, it is the responsibility of the consumer of browser-metrics to to appropriate compression. This was done as part of making the "data transport" not the responsibility of browser-metrics. It opens the door to allowing reports to be sanitised to be compliant with privacy policies (e.g. URLs may contain sensitive data). [backwards incompatible]Numbers in reports are no longer rounded. Historically numbers have been rounded as a "lossy compression" mechanism to decrease the size of beacons. This is no longer the responsibilty of browser-metrics, and as such has been removed. This affects
firstPaint
,readyForUser
,resourceTiming
.The report contributed by the
resourceTiming
reporter has been renamed fromresourceTimings
toresourceTiming
. [backwards incompatible]The new API
.subscribe(function (beacon) { … })
has been added as a way of exfiltrating beacons from browser-metrics.A large portion of tests have been migrated to jsverify rather than chance.js. This was done to improve test coverage by running each test 100 times with different values. The previous behaviour was to run each test once.
The
resourceTiming
reporter now collects resource timings for non-initial transitions, in addition to initial.Integration with Atlassian Analytics has been removed, it is not the responsibility of the consumer to manage data transport/beaconing of data via the
.subscribe()
API method. [backwards incompatible]browser-metrics is no longer a single
browser-metrics.js
file, but is now two separate files: [backwards incompatible]probe.js
-- a small script that must be loaded synchronously and provideswindow["browser-metrics"]
APIs.collector.js
-- a larger script that may be loaded asynchronously, and effectively implements the behaviour of theprobe.js
APIs.
Removed bundling of es6-promise and MutationObserver polyfill from
probe.js
, but still bundling es6-promise incollector.js
. The.start({ready: …})
API is a no-op unless MutationObserver and Promise APIs are available in the browser. [backwards incompatible].start({ready: …})
API is no longer deprecated, but rather usage is discouraged and a warning in the documentation has been added.User Timing API marks and measures are both included in transition reports. This means that the
performance.mark(<name>)
andperformance.measure(<name> <mark1Name>, <mark2Name>)
can be used to detail important points in time for a transition.
3.3.0
- Added
resourceTimings
reporter - Removed
resourceDurations
reporter
3.2.0
- BM-79 — Only report
firstPaint
for initial transitions. - BM-42 —
redirectCount
reporter reports0
when no redirects occurred, rather than being omitted from the report. - Use express.js for the almondjs demo and add redirect examples.
3.1.1
- Add support for YUI compressor by avoiding the
.catch()
es6-promise method. - Add missing 3.1.0 version change log.
3.1.0
- Added
firstPaint
reporter for Chrome and IE
3.0.0
- Reporters that return a rejected promise no longer cause the entire report to be discarded, instead it's equilavent to
the reporter returning an empty report, i.e.
{}
. (backwards incompatible) - Fix bug in
resourceDurations
andresourceLoadedEnd
so that asynchronous scripts are no longer considered to be blocking DOMContentLoaded.
2.0.0
- Remove
resourceCount
andslowResourceCount
in favour of the more general purposeresourceDurations
.
1.62.1
- Round the
resourceLoadedEnd
value to an integer.
1.62.0
- Add the
resourceTiming
reporter that addsresourceLoadedEnd
,resourceCount
, andslowResourceCount
attributes.
1.61.0
- Add
threshold
option to.start({...})
. - Add
apdex
reporter. - Add
threshold
reporter.
1.60.1
- Actually reports don't support any value type, they need to be string, boolean, or number.
1.60.0
- Allow any value types in reports (just a TypeScript definition change).
- Simplify the way Karma is configured.