var _ = require('./utility'); var MAX_EVENTS = 100; function Telemeter(options) { this.queue = []; this.options = _.merge(options); var maxTelemetryEvents = this.options.maxTelemetryEvents || MAX_EVENTS; this.maxQueueSize = Math.max(0, Math.min(maxTelemetryEvents, MAX_EVENTS)); } Telemeter.prototype.configure = function(options) { var oldOptions = this.options; this.options = _.merge(oldOptions, options); var maxTelemetryEvents = this.options.maxTelemetryEvents || MAX_EVENTS; var newMaxEvents = Math.max(0, Math.min(maxTelemetryEvents, MAX_EVENTS)); var deleteCount = 0; if (this.queue.length > newMaxEvents) { deleteCount = this.queue.length - newMaxEvents; } this.maxQueueSize = newMaxEvents; this.queue.splice(0, deleteCount); }; Telemeter.prototype.copyEvents = function() { var events = Array.prototype.slice.call(this.queue, 0); if (_.isFunction(this.options.filterTelemetry)) { try { var i = events.length; while (i--) { if (this.options.filterTelemetry(events[i])) { events.splice(i, 1); } } } catch (e) { this.options.filterTelemetry = null; } } return events; }; Telemeter.prototype.capture = function(type, metadata, level, rollbarUUID, timestamp) { var e = { level: getLevel(type, level), type: type, timestamp_ms: timestamp || _.now(), body: metadata, source: 'client' }; if (rollbarUUID) { e.uuid = rollbarUUID; } try { if (_.isFunction(this.options.filterTelemetry) && this.options.filterTelemetry(e)) { return false; } } catch (exc) { this.options.filterTelemetry = null; } this.push(e); return e; }; Telemeter.prototype.captureEvent = function(type, metadata, level, rollbarUUID) { return this.capture(type, metadata, level, rollbarUUID); }; Telemeter.prototype.captureError = function(err, level, rollbarUUID, timestamp) { var metadata = { message: err.message || String(err) }; if (err.stack) { metadata.stack = err.stack; } return this.capture('error', metadata, level, rollbarUUID, timestamp); }; Telemeter.prototype.captureLog = function(message, level, rollbarUUID, timestamp) { return this.capture('log', { message: message }, level, rollbarUUID, timestamp); }; Telemeter.prototype.captureNetwork = function(metadata, subtype, rollbarUUID, requestData) { subtype = subtype || 'xhr'; metadata.subtype = metadata.subtype || subtype; if (requestData) { metadata.request = requestData; } var level = this.levelFromStatus(metadata.status_code); return this.capture('network', metadata, level, rollbarUUID); }; Telemeter.prototype.levelFromStatus = function(statusCode) { if (statusCode >= 200 && statusCode < 400) { return 'info'; } if (statusCode === 0 || statusCode >= 400) { return 'error'; } return 'info'; }; Telemeter.prototype.captureDom = function(subtype, element, value, checked, rollbarUUID) { var metadata = { subtype: subtype, element: element }; if (value !== undefined) { metadata.value = value; } if (checked !== undefined) { metadata.checked = checked; } return this.capture('dom', metadata, 'info', rollbarUUID); }; Telemeter.prototype.captureNavigation = function(from, to, rollbarUUID) { return this.capture('navigation', {from: from, to: to}, 'info', rollbarUUID); }; Telemeter.prototype.captureDomContentLoaded = function(ts) { return this.capture('navigation', {subtype: 'DOMContentLoaded'}, 'info', undefined, ts && ts.getTime()); /** * If we decide to make this a dom event instead, then use the line below: return this.capture('dom', {subtype: 'DOMContentLoaded'}, 'info', undefined, ts && ts.getTime()); */ }; Telemeter.prototype.captureLoad = function(ts) { return this.capture('navigation', {subtype: 'load'}, 'info', undefined, ts && ts.getTime()); /** * If we decide to make this a dom event instead, then use the line below: return this.capture('dom', {subtype: 'load'}, 'info', undefined, ts && ts.getTime()); */ }; Telemeter.prototype.captureConnectivityChange = function(type, rollbarUUID) { return this.captureNetwork({change: type}, 'connectivity', rollbarUUID); }; // Only intended to be used internally by the notifier Telemeter.prototype._captureRollbarItem = function(item) { if (!this.options.includeItemsInTelemetry) { return; } if (item.err) { return this.captureError(item.err, item.level, item.uuid, item.timestamp); } if (item.message) { return this.captureLog(item.message, item.level, item.uuid, item.timestamp); } if (item.custom) { return this.capture('log', item.custom, item.level, item.uuid, item.timestamp); } }; Telemeter.prototype.push = function(e) { this.queue.push(e); if (this.queue.length > this.maxQueueSize) { this.queue.shift(); } }; function getLevel(type, level) { if (level) { return level; } var defaultLevel = { error: 'error', manual: 'info' }; return defaultLevel[type] || 'info'; } module.exports = Telemeter;