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

[Maps][Telemetry] Migrate Maps telemetry to NP #55055

Merged
merged 15 commits into from
Feb 19, 2020
Merged
Show file tree
Hide file tree
Changes from 14 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
44 changes: 44 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,44 @@
/*
* 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;
}

export interface IMapSavedObject {
kindsun marked this conversation as resolved.
Show resolved Hide resolved
[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?: [];
};
};
}
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,42 @@
*/

import _ from 'lodash';
import { SavedObjectsClientContract } from 'src/core/server';
import { 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, IMapSavedObject } from '../../common/descriptor_types';

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 IStats {
[key: string]: {
min: number;
max: number;
avg: number;
};
}

interface ILayerTypeCount {
[key: string]: number;
}

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 +51,33 @@ 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(
const fieldListsWithGeoFields = fieldLists.filter(fields =>
fields.some(
field =>
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: object;
}) {
const layerLists = mapSavedObjects.map(savedMapObject =>
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 +87,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,26 +132,29 @@ 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);
export async function getMapsTelemetry(
savedObjectsClient: SavedObjectsClientContract,
config: Function
) {
const mapSavedObjects: IMapSavedObject[] = await getMapSavedObjects(savedObjectsClient);
const indexPatternSavedObjects: IIndexPattern[] = await getIndexPatternSavedObjects(
savedObjectsClient
);
const settings = {
showMapVisualizationTypes: server.config().get('xpack.maps.showMapVisualizationTypes'),
showMapVisualizationTypes: config().get('xpack.maps.showMapVisualizationTypes'),
};
const mapsTelemetry = buildMapsTelemetry({ mapSavedObjects, indexPatternSavedObjects, settings });
return await savedObjectsClient.create(TELEMETRY_TYPE, mapsTelemetry, {
return await savedObjectsClient.create('maps-telemetry', mapsTelemetry, {
kindsun marked this conversation as resolved.
Show resolved Hide resolved
id: TELEMETRY_TYPE,
overwrite: true,
});
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