Skip to content
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

Implement Anonymous Usage Tracking #384

Merged
merged 2 commits into from
Aug 16, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion dist/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,25 @@ var _package2 = _interopRequireDefault(_package);

var _utils = require('./utils');

var _track_usage = require('./track_usage');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var logger = console;

_commander2.default.version(_package2.default.version).option('-p, --port [number]', 'Port to run Storybook (Required)', parseInt).option('-h, --host [string]', 'Host to run Storybook').option('-s, --static-dir <dir-names>', 'Directory where to load static files from', _utils.parseList).option('-c, --config-dir [dir-name]', 'Directory where to load Storybook configurations from').parse(process.argv);
_commander2.default.version(_package2.default.version).option('-p, --port [number]', 'Port to run Storybook (Required)', parseInt).option('-h, --host [string]', 'Host to run Storybook').option('-s, --static-dir <dir-names>', 'Directory where to load static files from', _utils.parseList).option('-c, --config-dir [dir-name]', 'Directory where to load Storybook configurations from').option('--dont-track', 'Do not send anonymous usage stats').option('--do-track', 'Send anonymous usage stats').parse(process.argv);

if (_commander2.default.dontTrack) {
(0, _track_usage.dontTrack)();
logger.info('Storybook would not send anonymous usage stats anymore.');
process.exit(0);
}

if (_commander2.default.doTrack) {
(0, _track_usage.dontTrack)(false);
logger.info('Storybook would send anonymous usage to getstorybooks.io.');
process.exit(0);
}

if (!_commander2.default.port) {
logger.error('Error: port to run Storybook is required!\n');
Expand Down Expand Up @@ -71,5 +85,6 @@ app.listen.apply(app, listenAddr.concat([function (error) {
} else {
var address = 'http://' + (_commander2.default.host || 'localhost') + ':' + _commander2.default.port + '/';
logger.info('\nReact Storybook started on => ' + address + '\n');
(0, _track_usage.track)();
}
}]));
118 changes: 118 additions & 0 deletions dist/server/track_usage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getStore = getStore;
exports.track = track;
exports.dontTrack = dontTrack;

var _configstore = require('configstore');

var _configstore2 = _interopRequireDefault(_configstore);

var _uuid = require('uuid');

var _uuid2 = _interopRequireDefault(_uuid);

var _request = require('request');

var _request2 = _interopRequireDefault(_request);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var logger = console; // ### WHAT?
//
// We will track anonymous usage of how you use storybook.
// We don't want any personal information.
// We just need to collect following information
//
// * How many time a user runs start-storybook a day
//
// We will send a ping to our server when you run storybook with above information.

// ### WHY?
//
// We are maintaining React Storybook and we want to improve it.
// We also working on storybooks.io which is storybook related service.
// In order to get a real picture about the storybook usage,
// we need to get some real usage stats, not the amount of NPM downloads.
// This is why we do this.

// ### CAN I STOP THIS?
//
// You(or your company) may have certain policies.
// If so, you can stop sending these metrics. Simply run:
// start-storybook --dont-track

// ### HELP US?
//
// Maintaining a open source project is hard.
// It's even harder for a startup like us (Kadira)
// Help us to make storybook better by sending these few metrics.
// Based on these metrics, we could improve storybook and build a profitable
// service around it. With that, we could continue to maintain and
// improve Storybook.

function getStore() {
var key = 'react-storybook-usage';
var store = new _configstore2.default(key);
return store;
}

function track() {
var store = getStore();

// Just a hash to aggregate metrics. Don't use any personal info.
var userId = store.get('userId');
if (!userId) {
userId = _uuid2.default.v4();
store.set('userId', userId);
}

if (store.get('dontTrack')) {
// Here we'll try to send a one last ping saying you are asked to don't track.
// We used this to identify the ratio of dontTrack.
if (!store.get('notifiedDontTrack')) {
// We don't wanna worry about the success or failure of this.
_request2.default.post('https://ping.getstorybook.io/react-storybook-dont-track', {
json: { userId: userId }
}, function () {});
store.set('notifiedDontTrack', true);
}
return;
}

// We need to clear this in case user decided to track again.
store.set('notifiedDontTrack', null);

var pkg = require('../../package.json');

// We don't wanna worry about the success or failure of this.
_request2.default.post('https://ping.getstorybook.io/react-storybook-usage', {
json: {
userId: userId,
version: pkg.version
}
}, function () {});

if (!store.get('startTrackingOn')) {
store.set('startTrackingOn', Date.now());
}

var pingsSent = store.get('pingsSent') || 0;
store.set('pingsSent', pingsSent + 1);

if (pingsSent < 5) {
logger.log(' We will collect some anonymous usage stats of how you use storybook.');
logger.log(' See why?: https://getstorybook.io/tracking');
logger.log();
}
}

function dontTrack() {
var state = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0];

var store = getStore();
store.set('dontTrack', Boolean(state));
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"case-sensitive-paths-webpack-plugin": "^1.1.2",
"cjson": "^0.4.0",
"commander": "^2.9.0",
"configstore": "^2.0.0",
"css-loader": "0.23.1",
"es6-shim": "^0.35.1",
"express": "^4.13.3",
Expand All @@ -58,11 +59,12 @@
"react-modal": "^1.2.0",
"redbox-react": "^1.2.2",
"redux": "^3.5.2",
"request": "^2.74.0",
"shelljs": "^0.6.0",
"stack-source-map": "^1.0.5",
"style-loader": "0.13.1",
"url-loader": "^0.5.7",
"uuid": "^2.0.1",
"uuid": "^2.0.2",
"webpack": "^1.13.1",
"webpack-dev-middleware": "^1.6.0",
"webpack-hot-middleware": "^2.10.0"
Expand Down
17 changes: 17 additions & 0 deletions src/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import fs from 'fs';
import storybook from './middleware';
import packageJson from '../../package.json';
import { parseList } from './utils';
import { track, dontTrack } from './track_usage';

const logger = console;

Expand All @@ -16,8 +17,23 @@ program
.option('-h, --host [string]', 'Host to run Storybook')
.option('-s, --static-dir <dir-names>', 'Directory where to load static files from', parseList)
.option('-c, --config-dir [dir-name]', 'Directory where to load Storybook configurations from')
.option('--dont-track', 'Do not send anonymous usage stats')
.option('--do-track', 'Send anonymous usage stats')
.parse(process.argv);


if (program.dontTrack) {
dontTrack();
logger.info('Storybook would not send anonymous usage stats anymore.');
process.exit(0);
}

if (program.doTrack) {
dontTrack(false);
logger.info('Storybook would send anonymous usage to getstorybooks.io.');
process.exit(0);
}

if (!program.port) {
logger.error('Error: port to run Storybook is required!\n');
program.help();
Expand Down Expand Up @@ -56,5 +72,6 @@ app.listen(...listenAddr, function (error) {
} else {
const address = `http://${program.host || 'localhost'}:${program.port}/`;
logger.info(`\nReact Storybook started on => ${address}\n`);
track();
}
});
99 changes: 99 additions & 0 deletions src/server/track_usage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// ### WHAT?
//
// We will track anonymous usage of how you use storybook.
// We don't want any personal information.
// We just need to collect following information
//
// * How many time a user runs start-storybook a day
//
// We will send a ping to our server when you run storybook with above information.

// ### WHY?
//
// We are maintaining React Storybook and we want to improve it.
// We also working on storybooks.io which is storybook related service.
// In order to get a real picture about the storybook usage,
// we need to get some real usage stats, not the amount of NPM downloads.
// This is why we do this.

// ### CAN I STOP THIS?
//
// You(or your company) may have certain policies.
// If so, you can stop sending these metrics. Simply run:
// start-storybook --dont-track

// ### HELP US?
//
// Maintaining a open source project is hard.
// It's even harder for a startup like us (Kadira)
// Help us to make storybook better by sending these few metrics.
// Based on these metrics, we could improve storybook and build a profitable
// service around it. With that, we could continue to maintain and
// improve Storybook.

import ConfigStore from 'configstore';
import UUID from 'uuid';
import request from 'request';

const logger = console;

export function getStore() {
const key = 'react-storybook-usage';
const store = new ConfigStore(key);
return store;
}

export function track() {
const store = getStore();

// Just a hash to aggregate metrics. Don't use any personal info.
let userId = store.get('userId');
if (!userId) {
userId = UUID.v4();
store.set('userId', userId);
}

if (store.get('dontTrack')) {
// Here we'll try to send a one last ping saying you are asked to don't track.
// We used this to identify the ratio of dontTrack.
if (!store.get('notifiedDontTrack')) {
// We don't wanna worry about the success or failure of this.
request.post('https://ping.getstorybook.io/react-storybook-dont-track', {
json: { userId },
}, () => {});
store.set('notifiedDontTrack', true);
}
return;
}

// We need to clear this in case user decided to track again.
store.set('notifiedDontTrack', null);

const pkg = require('../../package.json');

// We don't wanna worry about the success or failure of this.
request.post('https://ping.getstorybook.io/react-storybook-usage', {
json: {
userId,
version: pkg.version,
},
}, () => {});

if (!store.get('startTrackingOn')) {
store.set('startTrackingOn', Date.now());
}

const pingsSent = store.get('pingsSent') || 0;
store.set('pingsSent', pingsSent + 1);

if (pingsSent < 5) {
logger.log(' We will collect some anonymous usage stats of how you use storybook.');
logger.log(' See why?: https://getstorybook.io/tracking');
logger.log();
}
}

export function dontTrack(state = true) {
const store = getStore();
store.set('dontTrack', Boolean(state));
}