Skip to content

Commit

Permalink
[Maps][Telemetry] Migrate Maps telemetry to NP (elastic#55055)
Browse files Browse the repository at this point in the history
* Move maps telemetry to NP. Some clean-up, some ts conversion

* Update naming & org to be more in-line with guidelines

* Get TELEMETRY_TYPE from constants

* Ignore ts error importing from js file

* Set original array type passed into the function to array of ILayerTypeCount. Set return type on reduce function

* Remove unneeded 'any' types where used. Add in interfaces for map & index pattern saved objects

* Review feedback. Add layer, source, map saved object types and use

* Review feedback. Updates based on type check

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
Aaron Caldwell and elasticmachine committed Feb 19, 2020
1 parent 7759c74 commit 6b96036
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 66 deletions.
17 changes: 17 additions & 0 deletions x-pack/legacy/plugins/maps/common/descriptor_types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { IFieldType } from '../../../../../src/plugins/data/common/index_patterns/fields';

export interface ISourceDescriptor {
id: string;
type: string;
}

export interface ILayerDescriptor {
sourceDescriptor: ISourceDescriptor;
id: string;
}
10 changes: 7 additions & 3 deletions x-pack/legacy/plugins/maps/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import mappings from './mappings.json';
import { i18n } from '@kbn/i18n';
import { resolve } from 'path';
import { migrations } from './migrations';
import { initTelemetryCollection } from './server/maps_telemetry';
import { getAppTitle } from './common/i18n_getters';
import { MapPlugin } from './server/plugin';
import { APP_ID, APP_ICON, createMapPath, MAP_SAVED_OBJECT_TYPE } from './common/constants';
Expand Down Expand Up @@ -92,19 +91,23 @@ export function maps(kibana) {

init(server) {
const mapsEnabled = server.config().get('xpack.maps.enabled');
const { usageCollection } = server.newPlatform.setup.plugins;
if (!mapsEnabled) {
server.log(['info', 'maps'], 'Maps app disabled by configuration');
return;
}
initTelemetryCollection(usageCollection, server);

// Init saved objects client deps
const callCluster = server.plugins.elasticsearch.getCluster('admin').callWithInternalUser;
const { SavedObjectsClient, getSavedObjectsRepository } = server.savedObjects;
const internalRepository = getSavedObjectsRepository(callCluster);

const coreSetup = server.newPlatform.setup.core;
const newPlatformPlugins = server.newPlatform.setup.plugins;
const pluginsSetup = {
featuresPlugin: newPlatformPlugins.features,
licensing: newPlatformPlugins.licensing,
home: newPlatformPlugins.home,
usageCollection: newPlatformPlugins.usageCollection,
};

// legacy dependencies
Expand All @@ -118,6 +121,7 @@ export function maps(kibana) {
elasticsearch: server.plugins.elasticsearch,
},
savedObjects: {
savedObjectsClient: new SavedObjectsClient(internalRepository),
getSavedObjectsRepository: server.savedObjects.getSavedObjectsRepository,
},
injectUiAppVars: server.injectUiAppVars,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
// @ts-ignore
import { SavedObjectsClientContract } from 'src/core/server';
import { getMapsTelemetry } from '../maps_telemetry';
// @ts-ignore
import { TELEMETRY_TYPE } from '../../../common/constants';

export function registerMapsUsageCollector(
usageCollection: UsageCollectionSetup,
savedObjectsClient: SavedObjectsClientContract,
config: Function
): void {
if (!usageCollection) {
return;
}

const mapsUsageCollector = usageCollection.makeUsageCollector({
type: TELEMETRY_TYPE,
isReady: () => true,
fetch: async () => await getMapsTelemetry(savedObjectsClient, config),
});

usageCollection.registerCollector(mapsUsageCollector);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,28 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { initTelemetryCollection } from './maps_usage_collector';
import { registerMapsUsageCollector } from './register';

describe('buildCollectorObj#fetch', () => {
let makeUsageCollectorStub;
let savedObjectsClient;
let registerStub;
let usageCollection;
let config;

beforeEach(() => {
makeUsageCollectorStub = jest.fn();
savedObjectsClient = jest.fn();
registerStub = jest.fn();
config = jest.fn();
usageCollection = {
makeUsageCollector: makeUsageCollectorStub,
registerCollector: registerStub,
};
});

test('makes and registers maps usage collector', async () => {
const serverPlaceholder = {};
initTelemetryCollection(usageCollection, serverPlaceholder);
registerMapsUsageCollector(usageCollection, savedObjectsClient, config);

expect(registerStub).toHaveBeenCalledTimes(1);
expect(makeUsageCollectorStub).toHaveBeenCalledTimes(1);
Expand Down
7 changes: 0 additions & 7 deletions x-pack/legacy/plugins/maps/server/maps_telemetry/index.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,73 @@
*/

import _ from 'lodash';
import {
SavedObjectsClientContract,
SavedObjectAttributes,
SavedObjectAttribute,
} from 'src/core/server';
import { IFieldType, IIndexPattern } from 'src/plugins/data/public';
import {
EMS_FILE,
ES_GEO_FIELD_TYPE,
MAP_SAVED_OBJECT_TYPE,
TELEMETRY_TYPE,
// @ts-ignore
} from '../../common/constants';
import { ILayerDescriptor } from '../../common/descriptor_types';

interface IStats {
[key: string]: {
min: number;
max: number;
avg: number;
};
}

function getSavedObjectsClient(server) {
const { SavedObjectsClient, getSavedObjectsRepository } = server.savedObjects;
const callCluster = server.plugins.elasticsearch.getCluster('admin').callWithInternalUser;
const internalRepository = getSavedObjectsRepository(callCluster);
return new SavedObjectsClient(internalRepository);
interface ILayerTypeCount {
[key: string]: number;
}

interface IMapSavedObject {
[key: string]: any;
fields: IFieldType[];
title: string;
id?: string;
type?: string;
timeFieldName?: string;
fieldFormatMap?: Record<
string,
{
id: string;
params: unknown;
}
>;
attributes?: {
title?: string;
description?: string;
mapStateJSON?: string;
layerListJSON?: string;
uiStateJSON?: string;
bounds?: {
type?: string;
coordinates?: [];
};
};
}

function getUniqueLayerCounts(layerCountsList, mapsCount) {
function getUniqueLayerCounts(layerCountsList: ILayerTypeCount[], mapsCount: number) {
const uniqueLayerTypes = _.uniq(_.flatten(layerCountsList.map(lTypes => Object.keys(lTypes))));

return uniqueLayerTypes.reduce((accu, type) => {
const typeCounts = layerCountsList.reduce((accu, tCounts) => {
tCounts[type] && accu.push(tCounts[type]);
return accu;
}, []);
return uniqueLayerTypes.reduce((accu: IStats, type: string) => {
const typeCounts = layerCountsList.reduce(
(tCountsAccu: number[], tCounts: ILayerTypeCount): number[] => {
if (tCounts[type]) {
tCountsAccu.push(tCounts[type]);
}
return tCountsAccu;
},
[]
);
const typeCountsSum = _.sum(typeCounts);
accu[type] = {
min: typeCounts.length ? _.min(typeCounts) : 0,
Expand All @@ -37,25 +82,35 @@ function getUniqueLayerCounts(layerCountsList, mapsCount) {
}, {});
}

function getIndexPatternsWithGeoFieldCount(indexPatterns) {
function getIndexPatternsWithGeoFieldCount(indexPatterns: IIndexPattern[]) {
const fieldLists = indexPatterns.map(indexPattern => JSON.parse(indexPattern.attributes.fields));
const fieldListsWithGeoFields = fieldLists.filter(fields => {
return fields.some(
field =>
const fieldListsWithGeoFields = fieldLists.filter(fields =>
fields.some(
(field: IFieldType) =>
field.type === ES_GEO_FIELD_TYPE.GEO_POINT || field.type === ES_GEO_FIELD_TYPE.GEO_SHAPE
);
});
)
);
return fieldListsWithGeoFields.length;
}

export function buildMapsTelemetry({ mapSavedObjects, indexPatternSavedObjects, settings }) {
export function buildMapsTelemetry({
mapSavedObjects,
indexPatternSavedObjects,
settings,
}: {
mapSavedObjects: IMapSavedObject[];
indexPatternSavedObjects: IIndexPattern[];
settings: SavedObjectAttribute;
}): SavedObjectAttributes {
const layerLists = mapSavedObjects.map(savedMapObject =>
JSON.parse(savedMapObject.attributes.layerListJSON)
savedMapObject.attributes && savedMapObject.attributes.layerListJSON
? JSON.parse(savedMapObject.attributes.layerListJSON)
: []
);
const mapsCount = layerLists.length;

const dataSourcesCount = layerLists.map(lList => {
const sourceIdList = lList.map(layer => layer.sourceDescriptor.id);
const sourceIdList = lList.map((layer: ILayerDescriptor) => layer.sourceDescriptor.id);
return _.uniq(sourceIdList).length;
});

Expand All @@ -65,7 +120,7 @@ export function buildMapsTelemetry({ mapSavedObjects, indexPatternSavedObjects,
// Count of EMS Vector layers used
const emsLayersCount = layerLists.map(lList =>
_(lList)
.countBy(layer => {
.countBy((layer: ILayerDescriptor) => {
const isEmsFile = _.get(layer, 'sourceDescriptor.type') === EMS_FILE;
return isEmsFile && _.get(layer, 'sourceDescriptor.id');
})
Expand Down Expand Up @@ -110,23 +165,26 @@ export function buildMapsTelemetry({ mapSavedObjects, indexPatternSavedObjects,
},
};
}

async function getMapSavedObjects(savedObjectsClient) {
async function getMapSavedObjects(savedObjectsClient: SavedObjectsClientContract) {
const mapsSavedObjects = await savedObjectsClient.find({ type: MAP_SAVED_OBJECT_TYPE });
return _.get(mapsSavedObjects, 'saved_objects', []);
}

async function getIndexPatternSavedObjects(savedObjectsClient) {
async function getIndexPatternSavedObjects(savedObjectsClient: SavedObjectsClientContract) {
const indexPatternSavedObjects = await savedObjectsClient.find({ type: 'index-pattern' });
return _.get(indexPatternSavedObjects, 'saved_objects', []);
}

export async function getMapsTelemetry(server) {
const savedObjectsClient = getSavedObjectsClient(server);
const mapSavedObjects = await getMapSavedObjects(savedObjectsClient);
const indexPatternSavedObjects = await getIndexPatternSavedObjects(savedObjectsClient);
const settings = {
showMapVisualizationTypes: server.config().get('xpack.maps.showMapVisualizationTypes'),
export async function getMapsTelemetry(
savedObjectsClient: SavedObjectsClientContract,
config: Function
) {
const mapSavedObjects: IMapSavedObject[] = await getMapSavedObjects(savedObjectsClient);
const indexPatternSavedObjects: IIndexPattern[] = await getIndexPatternSavedObjects(
savedObjectsClient
);
const settings: SavedObjectAttribute = {
showMapVisualizationTypes: config().get('xpack.maps.showMapVisualizationTypes'),
};
const mapsTelemetry = buildMapsTelemetry({ mapSavedObjects, indexPatternSavedObjects, settings });
return await savedObjectsClient.create(TELEMETRY_TYPE, mapsTelemetry, {
Expand Down

This file was deleted.

7 changes: 6 additions & 1 deletion x-pack/legacy/plugins/maps/server/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import { APP_ID, APP_ICON, createMapPath, MAP_SAVED_OBJECT_TYPE } from '../commo
import { getEcommerceSavedObjects } from './sample_data/ecommerce_saved_objects';
import { getFlightsSavedObjects } from './sample_data/flights_saved_objects.js';
import { getWebLogsSavedObjects } from './sample_data/web_logs_saved_objects.js';
import { registerMapsUsageCollector } from './maps_telemetry/collectors/register';
import { LICENSE_CHECK_STATE } from '../../../../plugins/licensing/server';
import { initRoutes } from './routes';
import { emsBoundariesSpecProvider } from './tutorials/ems';

export class MapPlugin {
setup(core, plugins, __LEGACY) {
const { featuresPlugin, home, licensing } = plugins;
const { featuresPlugin, home, licensing, usageCollection } = plugins;
let routesInitialized = false;

featuresPlugin.registerFeature({
Expand Down Expand Up @@ -52,6 +53,10 @@ export class MapPlugin {
}
});

// Init telemetry
const { savedObjectsClient } = __LEGACY.savedObjects;
registerMapsUsageCollector(usageCollection, savedObjectsClient, __LEGACY.config);

const sampleDataLinkLabel = i18n.translate('xpack.maps.sampleDataLinkLabel', {
defaultMessage: 'Map',
});
Expand Down

0 comments on commit 6b96036

Please sign in to comment.