mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-04-10 20:59:55 +00:00
Merge pull request #738 from resin-io/rate-limit-mixpanel
Add mixpanel rate limiting, and supervisor version reporting
This commit is contained in:
commit
dfe95157b2
@ -32,6 +32,7 @@
|
||||
"@types/express": "^4.11.1",
|
||||
"@types/knex": "^0.14.14",
|
||||
"@types/lodash": "^4.14.109",
|
||||
"@types/memoizee": "^0.4.2",
|
||||
"@types/mz": "0.0.32",
|
||||
"@types/node": "^10.3.1",
|
||||
"@types/rwlock": "^5.0.2",
|
||||
|
@ -1,9 +1,12 @@
|
||||
import * as Bluebird from 'bluebird';
|
||||
import mask = require('json-mask');
|
||||
import * as _ from 'lodash';
|
||||
import * as memoizee from 'memoizee';
|
||||
|
||||
import Mixpanel = require('mixpanel');
|
||||
|
||||
import supervisorVersion = require('./lib/supervisor-version');
|
||||
|
||||
export type EventTrackProperties = Dictionary<any>;
|
||||
|
||||
interface InitArgs {
|
||||
@ -13,6 +16,10 @@ interface InitArgs {
|
||||
mixpanelToken: string;
|
||||
}
|
||||
|
||||
// The minimum amount of time to wait between sending
|
||||
// events of the same type
|
||||
const eventDebounceTime = 60000;
|
||||
|
||||
const mixpanelMask = [
|
||||
'appId',
|
||||
'delay',
|
||||
@ -44,6 +51,7 @@ export class EventTracker {
|
||||
this.defaultProperties = {
|
||||
distinct_id: uuid,
|
||||
uuid,
|
||||
supervisorVersion,
|
||||
};
|
||||
if (offlineMode) {
|
||||
return;
|
||||
@ -78,9 +86,16 @@ export class EventTracker {
|
||||
}
|
||||
|
||||
properties = this.assignDefaultProperties(properties);
|
||||
this.client.track(event, properties);
|
||||
this.debouncedLogger(event)(properties);
|
||||
}
|
||||
|
||||
private debouncedLogger = memoizee((event: string) => {
|
||||
// Call this function at maximum once every minute
|
||||
return _.debounce((properties) => {
|
||||
this.client.track(event, properties);
|
||||
}, eventDebounceTime, { leading: true });
|
||||
}, { primitive: true });
|
||||
|
||||
private logEvent(...args: string[]) {
|
||||
console.log(...args);
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ m = require 'mochainon'
|
||||
{ expect } = m.chai
|
||||
{ stub } = m.sinon
|
||||
|
||||
supervisorVersion = require '../src/lib/supervisor-version'
|
||||
|
||||
{ EventTracker } = require '../src/event-tracker'
|
||||
describe 'EventTracker', ->
|
||||
before ->
|
||||
@ -48,7 +50,12 @@ describe 'EventTracker', ->
|
||||
it 'calls the mixpanel client track function with the event, properties and uuid as distinct_id', ->
|
||||
@eventTracker.track('Test event 2', { appId: 'someOtherValue' })
|
||||
expect(@eventTracker.logEvent).to.be.calledWith('Event:', 'Test event 2', JSON.stringify({ appId: 'someOtherValue' }))
|
||||
expect(@eventTracker.client.track).to.be.calledWith('Test event 2', { appId: 'someOtherValue', uuid: 'barbaz', distinct_id: 'barbaz' })
|
||||
expect(@eventTracker.client.track).to.be.calledWith('Test event 2', {
|
||||
appId: 'someOtherValue'
|
||||
uuid: 'barbaz'
|
||||
distinct_id: 'barbaz'
|
||||
supervisorVersion
|
||||
})
|
||||
|
||||
it 'can be passed an Error and it is added to the event properties', ->
|
||||
theError = new Error('something went wrong')
|
||||
@ -59,6 +66,7 @@ describe 'EventTracker', ->
|
||||
stack: theError.stack
|
||||
uuid: 'barbaz'
|
||||
distinct_id: 'barbaz'
|
||||
supervisorVersion
|
||||
})
|
||||
|
||||
it 'hides service environment variables, to avoid logging keys or secrets', ->
|
||||
@ -76,4 +84,41 @@ describe 'EventTracker', ->
|
||||
service: { appId: '1' }
|
||||
uuid: 'barbaz'
|
||||
distinct_id: 'barbaz'
|
||||
supervisorVersion
|
||||
})
|
||||
|
||||
describe 'Rate limiting', ->
|
||||
|
||||
it 'should rate limit events of the same type', ->
|
||||
@eventTracker.client.track.reset()
|
||||
|
||||
@eventTracker.track('test', { });
|
||||
@eventTracker.track('test', { });
|
||||
@eventTracker.track('test', { });
|
||||
@eventTracker.track('test', { });
|
||||
@eventTracker.track('test', { });
|
||||
|
||||
expect(@eventTracker.client.track).to.have.callCount(1)
|
||||
|
||||
it 'should rate limit events of the same type with different arguments', ->
|
||||
@eventTracker.client.track.reset()
|
||||
|
||||
@eventTracker.track('test2', { a: 1 });
|
||||
@eventTracker.track('test2', { b: 2 });
|
||||
@eventTracker.track('test2', { c: 3 });
|
||||
@eventTracker.track('test2', { d: 4 });
|
||||
@eventTracker.track('test2', { e: 5 });
|
||||
|
||||
expect(@eventTracker.client.track).to.have.callCount(1)
|
||||
|
||||
it 'should not rate limit events of different types', ->
|
||||
@eventTracker.client.track.reset()
|
||||
|
||||
@eventTracker.track('test3', { a: 1 });
|
||||
@eventTracker.track('test4', { b: 2 });
|
||||
@eventTracker.track('test5', { c: 3 });
|
||||
@eventTracker.track('test6', { d: 4 });
|
||||
@eventTracker.track('test7', { e: 5 });
|
||||
|
||||
expect(@eventTracker.client.track).to.have.callCount(5)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user