Skip to content

Commit

Permalink
Merge pull request #3 from gokatz/v2_release_skull
Browse files Browse the repository at this point in the history
add tweaks in measuring flow and few additional methods
  • Loading branch information
gokatz authored Jul 15, 2017
2 parents c980ddb + d812cbc commit 7dd0ad8
Show file tree
Hide file tree
Showing 11 changed files with 424 additions and 130 deletions.
3 changes: 2 additions & 1 deletion .ember-cli
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@

Setting `disableAnalytics` to true will prevent any data from being sent.
*/
"disableAnalytics": false
"disableAnalytics": false,
"port": 4301
}
14 changes: 14 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
root: true,
parserOptions: {
ecmaVersion: 2017,
sourceType: 'module'
},
extends: 'eslint:recommended',
env: {
browser: true
},
rules: {
"no-console": "off"
}
};
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
/libpeerconnection.log
npm-debug.log*
testem.log
*.DS_Store
32 changes: 0 additions & 32 deletions .jshintrc

This file was deleted.

40 changes: 26 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# ember-appmetrics
# ember-appmetrics 🐹

[![Build Status](https://travis-ci.org/gokatz/ember-appmetrics.svg?branch=master)](https://travis-ci.org/gokatz/ember-appmetrics)

The ember version of [appmetrics.js](https://github.com/ebidel/appmetrics.js). Used to measure various things in your Ember app with ever simple APIs.
Ember library used to measure various metrics in your Ember app with ultra simple APIs. Especially useful for [RUM](https://en.wikipedia.org/wiki/Real_user_monitoring) in Ember SPAs.

## Installation
## Installation 💻
For Ember CLI >= `0.2.3`:
```shell
ember install ember-appmetrics
Expand All @@ -17,14 +17,22 @@ ember install:addon ember-appmetrics
## Compatibility
This addon is tested against the latest stable Ember version.

## Usage
## Usage 🏹

Inject the metrics service like `'metrics: Ember.inject.service()'` into the class where you want to measure the performance or use initializers if you are going with one-time injection.

Addon provides three API to measure the performace of a given period.
- `start` : need to call this api with an event name as argument to mark the starting point
- `end` : need to call this api with an event name as argument to mark the ending point
- `measure` : will return the calculated time for the given event
Addon provides three API for measuring the performance of a given period.
- `start` : need to call this API with an event name as an argument to mark the starting point.
- `end` : need to call this API with an event name as an argument to mark the ending point and it returns the duration for the corresponding mark.
- `measure` : will return the latest calculated time for the given event. This API will be deprecated in the future release in the favor of `end` API as the `end` method itself return the duration.


- `getAllMetrics` :

1. will return an object containing all the previously measured metrics and its duration, if no arguments were passed.
2. will return an array containing all the duration for the given metric name if the metric name is given as arguments.

- `clearAllMetrics` : Will clear out all the performance marks and measures.

```js
this.get('metrics').start('accounts_page');
Expand All @@ -35,24 +43,24 @@ Addon provides three API to measure the performace of a given period.
});
```

## Browser support
## Browser support 🌏

Since fall back machanism of all level has been handled in addon itself, the only thing addon needs is that the browser must have Date API, which is supported in all major and minor browsers.
Since fall back mechanism of all level has been handled in the addon itself, the only thing addon need is that the browser must have Date API, which is supported in all major and minor browsers.

PS: In Safari, the User Timing API (performance.mark()) is not available, so the DevTools timeline will not be annotated with marks.

## Installation
## Installation 💻

* `git clone` this repository
* `npm install`
* `bower install`

## Running
## Running 👟👟

* `ember server`
* Visit your app at http://localhost:4200.
* Visit your app at http://localhost:4301.

## Running Tests
## Running Tests 💉

* `ember test`
* `ember test --server`
Expand All @@ -62,3 +70,7 @@ PS: In Safari, the User Timing API (performance.mark()) is not available, so the
* `ember build`

For more information on using ember-cli, visit [http://www.ember-cli.com/](http://www.ember-cli.com/).

## Contribution 👨‍👧‍👦

Missing something? Let's work together to get that done 😉
102 changes: 81 additions & 21 deletions addon/services/metrics.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,44 @@
import Ember from 'ember';

const { typeOf } = Ember;
const { typeOf, Service } = Ember;

export default Ember.Service.extend({
export default Service.extend({
isMarkSupportedBrowser: true,
isNowSupportedBrowser: true,

secondaryPerformanceObj: {},
metricsObj: {},

init() {

// detecting the browser's Compatibility over window.performance.mark and window.performance.now

if (!(window.performance && window.performance.mark)) {
console.log('Performance.mark is not supported in this browser. Hence falling back to performance.now()');
console.warn('Performance.mark is not supported in this browser. Hence falling back to performance.now()');
this.set('isMarkSupportedBrowser', false);

if (!(window.performance && window.performance.now)) {
console.log('Performance.now is also not supported. Hence falling back to javascript Date API');
console.warn('Performance.now is also not supported. Hence falling back to javascript Date API');
this.set('isNowSupportedBrowser', false);

}
}
},

start(eventName) {

if (typeOf(eventName) !== 'string') {
console.error('Expected type String for invoking `start`');
return -1;
}

let secondaryPerformanceObj = this.get('secondaryPerformanceObj');
secondaryPerformanceObj[eventName] = secondaryPerformanceObj[eventName] || {};
let eventObj = secondaryPerformanceObj[eventName];

if (typeOf(eventName) !== 'string') {
throw 'Expected type String for invoking `start`';
}

if (this.get('isNowSupportedBrowser')) {
if (this.get('isMarkSupportedBrowser')) {
performance.mark(`mark_${eventName}_start`);
performance.mark(`eam:mark_${eventName}_start`);
} else {
eventObj.start = window.performance.now();
}
Expand All @@ -44,48 +50,102 @@ export default Ember.Service.extend({
},

end(eventName) {
let secondaryPerformanceObj = this.get('secondaryPerformanceObj');

secondaryPerformanceObj[eventName] = secondaryPerformanceObj[eventName] || {};
let eventObj = secondaryPerformanceObj[eventName];

if (typeOf(eventName) !== 'string') {
throw 'Expected type String for invoking `end`';
console.error('Expected type String for invoking `end`');
return -1;
}

let secondaryPerformanceObj = this.get('secondaryPerformanceObj');
secondaryPerformanceObj[eventName] = secondaryPerformanceObj[eventName] || {}; // creating a new entry if not already present
let eventObj = secondaryPerformanceObj[eventName];

let metricObj = this.get('metricsObj');
metricObj[eventName] = metricObj[eventName] || []; // creating a new entry if not already present
let metricArray = metricObj[eventName];

if (this.get('isNowSupportedBrowser')) {
let startMark = `mark_${eventName}_start`;
let endMark = `mark_${eventName}_end`;
let startMark = `eam:mark_${eventName}_start`;
let endMark = `eam:mark_${eventName}_end`;

if (this.get('isMarkSupportedBrowser')) {
performance.mark(endMark);
performance.measure(eventName, startMark, endMark);
performance.measure(`eam:${eventName}`, startMark, endMark);
} else {
eventObj.end = window.performance.now();
}
} else {
eventObj.end = new Date().valueOf();
}
return;

/*
pushing to the `metricsObj` here, since pushing in measure method will leads to have duplicate entires when
the measure api is invoked by the consuming application
*/
let duration = this.measure(eventName);
metricArray.push(duration);
return duration;
},

measure(eventName) {
if (typeOf(eventName) !== 'string') {
console.error('Expected type String for invoking `measure`');
return -1;
}

let secondaryPerformanceObj = this.get('secondaryPerformanceObj');
let eventObj = secondaryPerformanceObj[eventName] || {};

let duration;

if (this.get('isMarkSupportedBrowser')) {
let perfEntries = performance.getEntriesByName(eventName);
// poping up the last entry pushed into teh array
let perfEntries = performance.getEntriesByName(`eam:${eventName}`);
// poping up the last entry pushed into the array
let entry = perfEntries[perfEntries.length - 1];
if (entry) {
duration = entry.duration;
}
} else {
duration = eventObj.end - eventObj.start;
eventObj.duration = duration;
}
return typeOf(duration) === 'number' ? duration : -1;
},

getAllMetrics(eventName) {
/*
getAllMetrics will return the entires of given event name.
if no eventName is given, it will return the entire metricsObj
*/

if (eventName) {
return this.get(`metricsObj.${eventName}`) || {};
}
return this.get('metricsObj') || {};
},

clearAllMetrics() {
if (this.get('isMarkSupportedBrowser')) {
let eventNames = Object.keys(this.get('metricsObj') || {});

eventNames.forEach((eventName) => {
this.clearMetric(eventName);
});
}
this.set('secondaryPerformanceObj', {});
this.set('metricsObj', {});
},

clearMetric(eventName) {
if (this.get('isMarkSupportedBrowser')) {
performance.clearMeasures(`eam:${eventName}`);
}
let secondaryPerformanceObj = this.get('secondaryPerformanceObj') || {};
delete secondaryPerformanceObj[eventName];

let metricsObj = this.get('metricsObj') || {};
delete metricsObj[eventName];

return duration || -1;
}

});
8 changes: 3 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ember-appmetrics",
"version": "0.1.0",
"description": "Ember library used to measure various things in your Ember app with ultra simple APIs.",
"version": "1.0.0",
"description": "Ember library used to measure various metrics in your Ember app with ultra simple APIs. Especially useful for RUM in Ember SPA.",
"keywords": [
"ember-addon"
],
Expand All @@ -22,20 +22,18 @@
},
"devDependencies": {
"broccoli-asset-rev": "^2.4.5",
"ember-ajax": "^2.4.1",
"ember-cli": "2.10.0",
"ember-cli-app-version": "^2.0.0",
"ember-cli-dependency-checker": "^1.3.0",
"ember-cli-eslint": "4.1.0",
"ember-cli-htmlbars": "^1.0.10",
"ember-cli-htmlbars-inline-precompile": "^0.3.3",
"ember-cli-inject-live-reload": "^1.4.1",
"ember-cli-jshint": "^2.0.1",
"ember-cli-qunit": "^3.0.1",
"ember-cli-release": "^0.2.9",
"ember-cli-sri": "^2.1.0",
"ember-cli-test-loader": "^1.1.0",
"ember-cli-uglify": "^1.2.0",
"ember-data": "^2.10.0",
"ember-disable-prototype-extensions": "^1.1.0",
"ember-export-application-global": "^1.0.5",
"ember-load-initializers": "^0.5.1",
Expand Down
8 changes: 8 additions & 0 deletions tests/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
env: {
embertest: true
},
rules: {
"no-console": "off"
}
};
Loading

0 comments on commit 7dd0ad8

Please sign in to comment.