diff --git a/src/internal-plugins/home/lib/component/unsafe-component.jsx b/src/internal-plugins/home/lib/component/unsafe-component.jsx index 5af9622f2da..563b56f28bd 100644 --- a/src/internal-plugins/home/lib/component/unsafe-component.jsx +++ b/src/internal-plugins/home/lib/component/unsafe-component.jsx @@ -19,8 +19,8 @@ class UnsafeComponent extends React.Component { unmountInjected() { try { - const node = React.findDOMNode(this); - React.unmountComponentAtNode(node); + const node = ReactDOM.findDOMNode(this); + ReactDOM.unmountComponentAtNode(node); } catch (error) { /* eslint no-console:0 */ console.log(error); diff --git a/src/internal-plugins/home/lib/store/index.js b/src/internal-plugins/home/lib/store/index.js index 815a9784cb0..4d1cfa49f36 100644 --- a/src/internal-plugins/home/lib/store/index.js +++ b/src/internal-plugins/home/lib/store/index.js @@ -30,7 +30,11 @@ const HomeStore = Reflux.createStore({ errorMessage: '', namespace: '', uiStatus: UI_STATES.INITIAL, - isConnected: false + isConnected: false, + isAtlas: false, + authentication: 'NONE', + ssl: 'NONE', + sshTunnel: 'NONE' }; }, @@ -50,6 +54,10 @@ const HomeStore = Reflux.createStore({ this.setState({ isConnected: true, + isAtlas: /mongodb\.net/i.test(connection.hostname), + authentication: connection.authentication, + ssl: connection.ssl, + sshTunnel: connection.ssh_tunnel, uiStatus: UI_STATES.LOADING }); }, diff --git a/src/internal-plugins/metrics/lib/features.js b/src/internal-plugins/metrics/lib/features.js index 1357b29a4e7..44c850d505e 100644 --- a/src/internal-plugins/metrics/lib/features.js +++ b/src/internal-plugins/metrics/lib/features.js @@ -20,7 +20,7 @@ const features = [ const featureResources = _.object(_.map(features, function(feature) { const Klass = FeatureResource.extend({ id: feature, - eventTrackers: ['ga', 'intercom', 'stitch'] + eventTrackers: ['stitch'] }); return [feature, new Klass()]; })); @@ -28,7 +28,7 @@ const featureResources = _.object(_.map(features, function(feature) { // Geo Data uses `detected` as action const GeoDataResource = FeatureResource.extend({ id: 'Geo Data', - eventTrackers: ['ga', 'intercom', 'stitch'], + eventTrackers: ['stitch'], detected: function(metadata, callback) { this._send_event(metadata, callback); } @@ -37,7 +37,7 @@ const GeoDataResource = FeatureResource.extend({ // Collection uses `fetched` as action const CollectionResource = FeatureResource.extend({ id: 'Collection', - eventTrackers: ['ga', 'intercom', 'stitch'], + eventTrackers: ['stitch'], fetched: function(metadata, callback) { this._send_event(metadata, callback); } @@ -55,21 +55,117 @@ const DeploymentResource = FeatureResource.extend({ // Schema resource uses `sampled` as action const SchemaResource = BaseResource.extend({ id: 'Schema', - eventTrackers: ['ga', 'intercom', 'stitch'], + eventTrackers: ['stitch'], sampled: function(metadata, callback) { this._send_event(metadata, callback); } }); -// Index resource uses `detected` as action +// Index resource uses `fetched` as action const IndexesResource = BaseResource.extend({ id: 'Indexes', - eventTrackers: ['ga', 'intercom', 'stitch'], + eventTrackers: ['stitch'], + fetched: function(metadata, callback) { + this._send_event(metadata, callback); + } +}); + +// Collection Stats uses 'fetched' as action +const CollectionStatsResource = BaseResource.extend({ + id: 'Collection Stats', + eventTrackers: ['stitch'], + fetched: function(metadata, callback) { + this._send_event(metadata, callback); + } +}); + +// Topology resources uses 'detected' as action +const TopologyResource = BaseResource.extend({ + id: 'Topology', + eventTrackers: ['stitch'], detected: function(metadata, callback) { this._send_event(metadata, callback); } }); +// Query resources uses 'applied' as action +const QueryResource = BaseResource.extend({ + id: 'Query', + eventTrackers: ['stitch'], + applied: function(metadata, callback) { + this._send_event(metadata, callback); + } +}); + +// Application resources uses 'connected' as action +const ApplicationResource = BaseResource.extend({ + id: 'Application', + eventTrackers: ['stitch'], + connected: function(metadata, callback) { + this._send_event(metadata, callback); + } +}); + +// ValidationRules resources uses 'fetched' as action +const ValidationRulesResource = BaseResource.extend({ + id: 'Validation Rules', + eventTrackers: ['stitch'], + fetched: function(metadata, callback) { + this._send_event(metadata, callback); + } +}); + +// Explain resources uses 'fetched' as action +const ExplainResource = BaseResource.extend({ + id: 'Explain', + eventTrackers: ['stitch'], + fetched: function(metadata, callback) { + this._send_event(metadata, callback); + } +}); + +// Document resources uses 'inserted', 'updated', and 'deleted' as actions +const DocumentResource = BaseResource.extend({ + id: 'Document', + eventTrackers: ['stitch'], + inserted: function(metadata, callback) { + this._send_event(metadata, callback); + }, + updated: function(metadata, callback) { + this._send_event(metadata, callback); + }, + deleted: function(metadata, callback) { + this._send_event(metadata, callback); + } +}); + +// Documents resources uses 'loaded' as action +const DocumentsResource = BaseResource.extend({ + id: 'Documents', + eventTrackers: ['stitch'], + loaded: function(metadata, callback) { + this._send_event(metadata, callback); + } +}); + +// DocumentsListView resources uses 'paginated' as action +const DocumentsListViewResource = BaseResource.extend({ + id: 'Documents List View', + eventTrackers: ['stitch'], + paginated: function(metadata, callback) { + this._send_event(metadata, callback); + } +}); + +// DocumentsTableView resources uses 'paginated' as action +const DocumentsTableViewResource = BaseResource.extend({ + id: 'Documents Table View', + eventTrackers: ['stitch'], + paginated: function(metadata, callback) { + this._send_event(metadata, callback); + } +}); + const AutoUpdateResource = BaseResource.extend({ id: 'Auto Update', eventTrackers: ['ga', 'intercom', 'stitch'], @@ -99,6 +195,16 @@ featureResources.Collection = new CollectionResource(); featureResources.Deployment = new DeploymentResource(); featureResources.Schema = new SchemaResource(); featureResources.Indexes = new IndexesResource(); +featureResources['Collection Stats'] = new CollectionStatsResource(); +featureResources.Topology = new TopologyResource(); +featureResources.Query = new QueryResource(); +featureResources.Application = new ApplicationResource(); +featureResources['Validation Rules'] = new ValidationRulesResource(); +featureResources.Explain = new ExplainResource(); +featureResources.Document = new DocumentResource(); +featureResources.Documents = new DocumentsResource(); +featureResources.DocumentsListView = new DocumentsListViewResource(); +featureResources.DocumentsTableView = new DocumentsTableViewResource(); debug('feature resources', featureResources); diff --git a/src/internal-plugins/metrics/lib/rules.js b/src/internal-plugins/metrics/lib/rules.js index 67c851c9fa4..a656448f2d9 100644 --- a/src/internal-plugins/metrics/lib/rules.js +++ b/src/internal-plugins/metrics/lib/rules.js @@ -34,7 +34,13 @@ module.exports = [ 'server architecture': state.instance.host.arch, 'server cpu cores': state.instance.host.cpu_cores, 'server cpu frequency (mhz)': state.instance.host.cpu_frequency / 1000 / 1000, - 'server memory size (gb)': state.instance.host.memory_bits / 1024 / 1024 / 1024 + 'server memory (gb)': state.instance.host.memory_bits / 1024 / 1024 / 1024, + 'server os': state.instance.host.os, + 'server arch': state.instance.host.arch, + 'server os family': state.instance.host.os_family, + 'server machine model': state.instance.host.machine_model, + 'server kernel version': state.instance.host.kernel_version, + 'server kernel version string': state.instance.host.kernel_version_string }) }, { @@ -49,6 +55,136 @@ module.exports = [ 'schema depth': schemaStats.depth(state.schema), 'schema branching factors': schemaStats.branch(state.schema) }) + }, + { + store: 'DeploymentAwareness.Store', + resource: 'Topology', + action: 'detected', + condition: () => true, + metadata: (state) => ({ + 'topology type': state.topologyType, + 'server count': state.servers.length, + 'server types': state.servers.map(server => server.type) + }) + }, + { + store: 'CollectionStats.Store', + resource: 'Collection Stats', + action: 'fetched', + condition: () => true, + metadata: (state) => ({ + 'document count': state.documentCount, + 'total document size kb': state.totalDocumentSize, + 'avg document size kb': state.avgDocumentSize, + 'index count': state.indexCount, + 'total index size kb': state.totalIndexSize, + 'avg index size kb': state.avgIndexSize + }) + }, + { + store: 'Indexes.LoadIndexesStore', + resource: 'Indexes', + action: 'fetched', + condition: () => true, + multi: true, + metadata: (state) => ({ + 'index type': state.type, + 'usage count': state.usageCount, + 'cardinality': state.cardinality, + 'properties': state.properties + }) + }, + { + store: 'Query.QueryStore', + resource: 'Query', + action: 'applied', + condition: (state) => state.queryState === 'apply', + metadata: (state) => ({ + 'filter': state.filter, + 'project': state.project, + 'sort': state.sort, + 'skip': state.skip, + 'limit': state.limit + }) + }, + { + store: 'Home.HomeStore', + resource: 'Application', + action: 'connected', + condition: (state) => state.isConnected === true, + metadata: (state) => ({ + 'is atlas': state.isAtlas, + 'authentication method': state.authentication, + 'ssl method': state.ssl, + 'ssh tunnel method': state.sshTunnel + }) + }, + { + store: 'Validation.Store', + resource: 'Validation Rules', + action: 'fetched', + condition: () => true, + metadata: (state) => ({ + 'rule count': state.validationRules.length, + 'validation level': state.validationLevel, + 'validation action': state.validationAction + }) + }, + { + store: 'Explain.Store', + resource: 'Explain', + action: 'fetched', + condition: () => true, + metadata: (state) => ({ + 'view mode': state.viewType, + 'execution time ms': state.executionTimeMillis, + 'in memory sort': state.inMemorySort, + 'is collection scan': state.isCollectionScan, + 'is covered': state.isCovered, + 'is multi key': state.isMultiKey, + 'is sharded': state.isSharded, + 'index type': state.indexType, + 'index': state.index, + 'number of docs returned': state.nReturned, + 'number of shards': state.numShards, + 'total docs examined': state.totalDocsExamined, + 'total keys examined': state.totalKeysExamined, + 'index used': state.usedIndex + }) + }, + { + store: 'CRUD.InsertDocumentStore', + resource: 'Document', + action: 'inserted', + condition: () => true, + metadata: () => ({}) + }, + { + store: 'CRUD.RemoveDocumentStore', + resource: 'Document', + action: 'deleted', + condition: () => true, + metadata: () => ({}) + }, + { + store: 'CRUD.ResetDocumentListStore', + resource: 'Documents', + action: 'loaded', + condition: () => true, + metadata: () => ({}) + }, + { + store: 'CRUD.LoadMoreDocumentsStore', + resource: 'Documents List View', + action: 'paginated', + condition: () => true, + metadata: () => ({}) + }, + { + store: 'CRUD.PageChangedStore', + resource: 'Documents Table View', + action: 'paginated', + condition: () => true, + metadata: () => ({}) } - ]; diff --git a/src/internal-plugins/metrics/lib/store.js b/src/internal-plugins/metrics/lib/store.js index 25d290740a7..eb2cd218a05 100644 --- a/src/internal-plugins/metrics/lib/store.js +++ b/src/internal-plugins/metrics/lib/store.js @@ -27,7 +27,14 @@ const MetricsStore = Reflux.createStore({ store.listen((state) => { // only track an event if the rule condition evaluates to true if (rule.condition(state)) { - metrics.track(rule.resource, rule.action, rule.metadata(state)); + // Some stores trigger with arrays of data. + if (rule.multi) { + state.forEach((s) => { + metrics.track(rule.resource, rule.action, rule.metadata(s)); + }); + } else { + metrics.track(rule.resource, rule.action, rule.metadata(state)); + } } }); });