Skip to content

Commit ef15653

Browse files
Aaron Caldwellelasticmachine
andauthored
[Maps][Telemetry] Migrate Maps telemetry to NP (#55055)
* 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>
1 parent 63cfffb commit ef15653

File tree

8 files changed

+154
-66
lines changed

8 files changed

+154
-66
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { IFieldType } from '../../../../../src/plugins/data/common/index_patterns/fields';
8+
9+
export interface ISourceDescriptor {
10+
id: string;
11+
type: string;
12+
}
13+
14+
export interface ILayerDescriptor {
15+
sourceDescriptor: ISourceDescriptor;
16+
id: string;
17+
}

x-pack/legacy/plugins/maps/index.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import mappings from './mappings.json';
99
import { i18n } from '@kbn/i18n';
1010
import { resolve } from 'path';
1111
import { migrations } from './migrations';
12-
import { initTelemetryCollection } from './server/maps_telemetry';
1312
import { getAppTitle } from './common/i18n_getters';
1413
import { MapPlugin } from './server/plugin';
1514
import { APP_ID, APP_ICON, createMapPath, MAP_SAVED_OBJECT_TYPE } from './common/constants';
@@ -92,19 +91,23 @@ export function maps(kibana) {
9291

9392
init(server) {
9493
const mapsEnabled = server.config().get('xpack.maps.enabled');
95-
const { usageCollection } = server.newPlatform.setup.plugins;
9694
if (!mapsEnabled) {
9795
server.log(['info', 'maps'], 'Maps app disabled by configuration');
9896
return;
9997
}
100-
initTelemetryCollection(usageCollection, server);
98+
99+
// Init saved objects client deps
100+
const callCluster = server.plugins.elasticsearch.getCluster('admin').callWithInternalUser;
101+
const { SavedObjectsClient, getSavedObjectsRepository } = server.savedObjects;
102+
const internalRepository = getSavedObjectsRepository(callCluster);
101103

102104
const coreSetup = server.newPlatform.setup.core;
103105
const newPlatformPlugins = server.newPlatform.setup.plugins;
104106
const pluginsSetup = {
105107
featuresPlugin: newPlatformPlugins.features,
106108
licensing: newPlatformPlugins.licensing,
107109
home: newPlatformPlugins.home,
110+
usageCollection: newPlatformPlugins.usageCollection,
108111
};
109112

110113
// legacy dependencies
@@ -118,6 +121,7 @@ export function maps(kibana) {
118121
elasticsearch: server.plugins.elasticsearch,
119122
},
120123
savedObjects: {
124+
savedObjectsClient: new SavedObjectsClient(internalRepository),
121125
getSavedObjectsRepository: server.savedObjects.getSavedObjectsRepository,
122126
},
123127
injectUiAppVars: server.injectUiAppVars,
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
8+
// @ts-ignore
9+
import { SavedObjectsClientContract } from 'src/core/server';
10+
import { getMapsTelemetry } from '../maps_telemetry';
11+
// @ts-ignore
12+
import { TELEMETRY_TYPE } from '../../../common/constants';
13+
14+
export function registerMapsUsageCollector(
15+
usageCollection: UsageCollectionSetup,
16+
savedObjectsClient: SavedObjectsClientContract,
17+
config: Function
18+
): void {
19+
if (!usageCollection) {
20+
return;
21+
}
22+
23+
const mapsUsageCollector = usageCollection.makeUsageCollector({
24+
type: TELEMETRY_TYPE,
25+
isReady: () => true,
26+
fetch: async () => await getMapsTelemetry(savedObjectsClient, config),
27+
});
28+
29+
usageCollection.registerCollector(mapsUsageCollector);
30+
}

x-pack/legacy/plugins/maps/server/maps_telemetry/maps_usage_collector.test.js renamed to x-pack/legacy/plugins/maps/server/maps_telemetry/collectors/register_collector.test.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,28 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
import { initTelemetryCollection } from './maps_usage_collector';
7+
import { registerMapsUsageCollector } from './register';
88

99
describe('buildCollectorObj#fetch', () => {
1010
let makeUsageCollectorStub;
11+
let savedObjectsClient;
1112
let registerStub;
1213
let usageCollection;
14+
let config;
1315

1416
beforeEach(() => {
1517
makeUsageCollectorStub = jest.fn();
18+
savedObjectsClient = jest.fn();
1619
registerStub = jest.fn();
20+
config = jest.fn();
1721
usageCollection = {
1822
makeUsageCollector: makeUsageCollectorStub,
1923
registerCollector: registerStub,
2024
};
2125
});
2226

2327
test('makes and registers maps usage collector', async () => {
24-
const serverPlaceholder = {};
25-
initTelemetryCollection(usageCollection, serverPlaceholder);
28+
registerMapsUsageCollector(usageCollection, savedObjectsClient, config);
2629

2730
expect(registerStub).toHaveBeenCalledTimes(1);
2831
expect(makeUsageCollectorStub).toHaveBeenCalledTimes(1);

x-pack/legacy/plugins/maps/server/maps_telemetry/index.js

Lines changed: 0 additions & 7 deletions
This file was deleted.

x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.js renamed to x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts

Lines changed: 88 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,73 @@
55
*/
66

77
import _ from 'lodash';
8+
import {
9+
SavedObjectsClientContract,
10+
SavedObjectAttributes,
11+
SavedObjectAttribute,
12+
} from 'src/core/server';
13+
import { IFieldType, IIndexPattern } from 'src/plugins/data/public';
814
import {
915
EMS_FILE,
1016
ES_GEO_FIELD_TYPE,
1117
MAP_SAVED_OBJECT_TYPE,
1218
TELEMETRY_TYPE,
19+
// @ts-ignore
1320
} from '../../common/constants';
21+
import { ILayerDescriptor } from '../../common/descriptor_types';
22+
23+
interface IStats {
24+
[key: string]: {
25+
min: number;
26+
max: number;
27+
avg: number;
28+
};
29+
}
1430

15-
function getSavedObjectsClient(server) {
16-
const { SavedObjectsClient, getSavedObjectsRepository } = server.savedObjects;
17-
const callCluster = server.plugins.elasticsearch.getCluster('admin').callWithInternalUser;
18-
const internalRepository = getSavedObjectsRepository(callCluster);
19-
return new SavedObjectsClient(internalRepository);
31+
interface ILayerTypeCount {
32+
[key: string]: number;
33+
}
34+
35+
interface IMapSavedObject {
36+
[key: string]: any;
37+
fields: IFieldType[];
38+
title: string;
39+
id?: string;
40+
type?: string;
41+
timeFieldName?: string;
42+
fieldFormatMap?: Record<
43+
string,
44+
{
45+
id: string;
46+
params: unknown;
47+
}
48+
>;
49+
attributes?: {
50+
title?: string;
51+
description?: string;
52+
mapStateJSON?: string;
53+
layerListJSON?: string;
54+
uiStateJSON?: string;
55+
bounds?: {
56+
type?: string;
57+
coordinates?: [];
58+
};
59+
};
2060
}
2161

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

25-
return uniqueLayerTypes.reduce((accu, type) => {
26-
const typeCounts = layerCountsList.reduce((accu, tCounts) => {
27-
tCounts[type] && accu.push(tCounts[type]);
28-
return accu;
29-
}, []);
65+
return uniqueLayerTypes.reduce((accu: IStats, type: string) => {
66+
const typeCounts = layerCountsList.reduce(
67+
(tCountsAccu: number[], tCounts: ILayerTypeCount): number[] => {
68+
if (tCounts[type]) {
69+
tCountsAccu.push(tCounts[type]);
70+
}
71+
return tCountsAccu;
72+
},
73+
[]
74+
);
3075
const typeCountsSum = _.sum(typeCounts);
3176
accu[type] = {
3277
min: typeCounts.length ? _.min(typeCounts) : 0,
@@ -37,25 +82,35 @@ function getUniqueLayerCounts(layerCountsList, mapsCount) {
3782
}, {});
3883
}
3984

40-
function getIndexPatternsWithGeoFieldCount(indexPatterns) {
85+
function getIndexPatternsWithGeoFieldCount(indexPatterns: IIndexPattern[]) {
4186
const fieldLists = indexPatterns.map(indexPattern => JSON.parse(indexPattern.attributes.fields));
42-
const fieldListsWithGeoFields = fieldLists.filter(fields => {
43-
return fields.some(
44-
field =>
87+
const fieldListsWithGeoFields = fieldLists.filter(fields =>
88+
fields.some(
89+
(field: IFieldType) =>
4590
field.type === ES_GEO_FIELD_TYPE.GEO_POINT || field.type === ES_GEO_FIELD_TYPE.GEO_SHAPE
46-
);
47-
});
91+
)
92+
);
4893
return fieldListsWithGeoFields.length;
4994
}
5095

51-
export function buildMapsTelemetry({ mapSavedObjects, indexPatternSavedObjects, settings }) {
96+
export function buildMapsTelemetry({
97+
mapSavedObjects,
98+
indexPatternSavedObjects,
99+
settings,
100+
}: {
101+
mapSavedObjects: IMapSavedObject[];
102+
indexPatternSavedObjects: IIndexPattern[];
103+
settings: SavedObjectAttribute;
104+
}): SavedObjectAttributes {
52105
const layerLists = mapSavedObjects.map(savedMapObject =>
53-
JSON.parse(savedMapObject.attributes.layerListJSON)
106+
savedMapObject.attributes && savedMapObject.attributes.layerListJSON
107+
? JSON.parse(savedMapObject.attributes.layerListJSON)
108+
: []
54109
);
55110
const mapsCount = layerLists.length;
56111

57112
const dataSourcesCount = layerLists.map(lList => {
58-
const sourceIdList = lList.map(layer => layer.sourceDescriptor.id);
113+
const sourceIdList = lList.map((layer: ILayerDescriptor) => layer.sourceDescriptor.id);
59114
return _.uniq(sourceIdList).length;
60115
});
61116

@@ -65,7 +120,7 @@ export function buildMapsTelemetry({ mapSavedObjects, indexPatternSavedObjects,
65120
// Count of EMS Vector layers used
66121
const emsLayersCount = layerLists.map(lList =>
67122
_(lList)
68-
.countBy(layer => {
123+
.countBy((layer: ILayerDescriptor) => {
69124
const isEmsFile = _.get(layer, 'sourceDescriptor.type') === EMS_FILE;
70125
return isEmsFile && _.get(layer, 'sourceDescriptor.id');
71126
})
@@ -110,23 +165,26 @@ export function buildMapsTelemetry({ mapSavedObjects, indexPatternSavedObjects,
110165
},
111166
};
112167
}
113-
114-
async function getMapSavedObjects(savedObjectsClient) {
168+
async function getMapSavedObjects(savedObjectsClient: SavedObjectsClientContract) {
115169
const mapsSavedObjects = await savedObjectsClient.find({ type: MAP_SAVED_OBJECT_TYPE });
116170
return _.get(mapsSavedObjects, 'saved_objects', []);
117171
}
118172

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

124-
export async function getMapsTelemetry(server) {
125-
const savedObjectsClient = getSavedObjectsClient(server);
126-
const mapSavedObjects = await getMapSavedObjects(savedObjectsClient);
127-
const indexPatternSavedObjects = await getIndexPatternSavedObjects(savedObjectsClient);
128-
const settings = {
129-
showMapVisualizationTypes: server.config().get('xpack.maps.showMapVisualizationTypes'),
178+
export async function getMapsTelemetry(
179+
savedObjectsClient: SavedObjectsClientContract,
180+
config: Function
181+
) {
182+
const mapSavedObjects: IMapSavedObject[] = await getMapSavedObjects(savedObjectsClient);
183+
const indexPatternSavedObjects: IIndexPattern[] = await getIndexPatternSavedObjects(
184+
savedObjectsClient
185+
);
186+
const settings: SavedObjectAttribute = {
187+
showMapVisualizationTypes: config().get('xpack.maps.showMapVisualizationTypes'),
130188
};
131189
const mapsTelemetry = buildMapsTelemetry({ mapSavedObjects, indexPatternSavedObjects, settings });
132190
return await savedObjectsClient.create(TELEMETRY_TYPE, mapsTelemetry, {

x-pack/legacy/plugins/maps/server/maps_telemetry/maps_usage_collector.js

Lines changed: 0 additions & 22 deletions
This file was deleted.

x-pack/legacy/plugins/maps/server/plugin.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ import { APP_ID, APP_ICON, createMapPath, MAP_SAVED_OBJECT_TYPE } from '../commo
88
import { getEcommerceSavedObjects } from './sample_data/ecommerce_saved_objects';
99
import { getFlightsSavedObjects } from './sample_data/flights_saved_objects.js';
1010
import { getWebLogsSavedObjects } from './sample_data/web_logs_saved_objects.js';
11+
import { registerMapsUsageCollector } from './maps_telemetry/collectors/register';
1112
import { LICENSE_CHECK_STATE } from '../../../../plugins/licensing/server';
1213
import { initRoutes } from './routes';
1314
import { emsBoundariesSpecProvider } from './tutorials/ems';
1415

1516
export class MapPlugin {
1617
setup(core, plugins, __LEGACY) {
17-
const { featuresPlugin, home, licensing } = plugins;
18+
const { featuresPlugin, home, licensing, usageCollection } = plugins;
1819
let routesInitialized = false;
1920

2021
featuresPlugin.registerFeature({
@@ -52,6 +53,10 @@ export class MapPlugin {
5253
}
5354
});
5455

56+
// Init telemetry
57+
const { savedObjectsClient } = __LEGACY.savedObjects;
58+
registerMapsUsageCollector(usageCollection, savedObjectsClient, __LEGACY.config);
59+
5560
const sampleDataLinkLabel = i18n.translate('xpack.maps.sampleDataLinkLabel', {
5661
defaultMessage: 'Map',
5762
});

0 commit comments

Comments
 (0)