mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[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>
This commit is contained in:
parent
63cfffbe11
commit
ef1565347c
8 changed files with 154 additions and 66 deletions
17
x-pack/legacy/plugins/maps/common/descriptor_types.d.ts
vendored
Normal file
17
x-pack/legacy/plugins/maps/common/descriptor_types.d.ts
vendored
Normal file
|
@ -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;
|
||||
}
|
|
@ -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';
|
||||
|
@ -92,12 +91,15 @@ 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;
|
||||
|
@ -105,6 +107,7 @@ export function maps(kibana) {
|
|||
featuresPlugin: newPlatformPlugins.features,
|
||||
licensing: newPlatformPlugins.licensing,
|
||||
home: newPlatformPlugins.home,
|
||||
usageCollection: newPlatformPlugins.usageCollection,
|
||||
};
|
||||
|
||||
// legacy dependencies
|
||||
|
@ -118,6 +121,7 @@ export function maps(kibana) {
|
|||
elasticsearch: server.plugins.elasticsearch,
|
||||
},
|
||||
savedObjects: {
|
||||
savedObjectsClient: new SavedObjectsClient(internalRepository),
|
||||
getSavedObjectsRepository: server.savedObjects.getSavedObjectsRepository,
|
||||
},
|
||||
injectUiAppVars: server.injectUiAppVars,
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -4,16 +4,20 @@
|
|||
* 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,
|
||||
|
@ -21,8 +25,7 @@ describe('buildCollectorObj#fetch', () => {
|
|||
});
|
||||
|
||||
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);
|
|
@ -1,7 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { initTelemetryCollection } from './maps_usage_collector';
|
|
@ -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';
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
function getUniqueLayerCounts(layerCountsList, mapsCount) {
|
||||
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: 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,
|
||||
|
@ -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;
|
||||
});
|
||||
|
||||
|
@ -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');
|
||||
})
|
||||
|
@ -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, {
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* 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 { getMapsTelemetry } from './maps_telemetry';
|
||||
import { TELEMETRY_TYPE } from '../../common/constants';
|
||||
|
||||
export function initTelemetryCollection(usageCollection, server) {
|
||||
if (!usageCollection) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mapsUsageCollector = usageCollection.makeUsageCollector({
|
||||
type: TELEMETRY_TYPE,
|
||||
isReady: () => true,
|
||||
fetch: async () => await getMapsTelemetry(server),
|
||||
});
|
||||
|
||||
usageCollection.registerCollector(mapsUsageCollector);
|
||||
}
|
|
@ -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({
|
||||
|
@ -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',
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue