Skip to content

Commit

Permalink
[Maps] Remove extra layer of telemetry nesting under "attributes" (#6…
Browse files Browse the repository at this point in the history
…6137)

* Return attributes when telemetry created instead of whole saved object. Update integration test

* Change 'maps-telemetry' to 'maps'

* No need to create a saved object anymore. This is leftover from task manager telemetry mgmt

* Add test confirming attrs undefined. Change tests to check for 'maps' iso 'maps-telemetry'

* Add two more tests confirming expected telemetry shape

* Review feedback. Use TELEMETRY_TYPE constant and set to APP_ID
# Conflicts:
#	x-pack/plugins/maps/server/maps_telemetry/maps_telemetry.ts
  • Loading branch information
Aaron Caldwell committed Jun 23, 2020
1 parent 44e4659 commit 0c82155
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 4 deletions.
2 changes: 1 addition & 1 deletion x-pack/plugins/maps/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const EMS_TILES_VECTOR_TILE_PATH = 'vector/tile';
export const MAP_SAVED_OBJECT_TYPE = 'map';
export const APP_ID = 'maps';
export const APP_ICON = 'gisApp';
export const TELEMETRY_TYPE = 'maps-telemetry';
export const TELEMETRY_TYPE = APP_ID;

export const MAP_APP_PATH = `app/${APP_ID}`;
export const GIS_API_PATH = `api/${APP_ID}`;
Expand Down
185 changes: 185 additions & 0 deletions x-pack/plugins/maps/server/maps_telemetry/maps_telemetry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/*
* 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 _ from 'lodash';
import {
SavedObjectsClientContract,
SavedObjectAttributes,
SavedObjectAttribute,
} from 'kibana/server';
import { IFieldType, IIndexPattern } from 'src/plugins/data/public';
import { SOURCE_TYPES, ES_GEO_FIELD_TYPE, MAP_SAVED_OBJECT_TYPE } from '../../common/constants';
import { LayerDescriptor } from '../../common/descriptor_types';
import { MapSavedObject } from '../../common/map_saved_object_type';
// @ts-ignore
import { getInternalRepository } from '../kibana_server_services';
import { MapsConfigType } from '../../config';

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

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

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

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,
max: typeCounts.length ? _.max(typeCounts) : 0,
avg: typeCountsSum ? typeCountsSum / mapsCount : 0,
};
return accu;
}, {});
}

function getIndexPatternsWithGeoFieldCount(indexPatterns: IIndexPattern[]) {
const fieldLists = indexPatterns.map((indexPattern) =>
indexPattern.attributes && indexPattern.attributes.fields
? JSON.parse(indexPattern.attributes.fields)
: []
);

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
)
);

const fieldListsWithGeoPointFields = fieldLists.filter((fields) =>
fields.some((field: IFieldType) => field.type === ES_GEO_FIELD_TYPE.GEO_POINT)
);

const fieldListsWithGeoShapeFields = fieldLists.filter((fields) =>
fields.some((field: IFieldType) => field.type === ES_GEO_FIELD_TYPE.GEO_SHAPE)
);

return {
indexPatternsWithGeoFieldCount: fieldListsWithGeoFields.length,
indexPatternsWithGeoPointFieldCount: fieldListsWithGeoPointFields.length,
indexPatternsWithGeoShapeFieldCount: fieldListsWithGeoShapeFields.length,
};
}

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

const dataSourcesCount = layerLists.map((lList) => {
// todo: not every source-descriptor has an id
// @ts-ignore
const sourceIdList = lList.map((layer: LayerDescriptor) => layer.sourceDescriptor.id);
return _.uniq(sourceIdList).length;
});

const layersCount = layerLists.map((lList) => lList.length);
const layerTypesCount = layerLists.map((lList) => _.countBy(lList, 'type'));

// Count of EMS Vector layers used
const emsLayersCount = layerLists.map((lList) =>
_(lList)
.countBy((layer: LayerDescriptor) => {
const isEmsFile = _.get(layer, 'sourceDescriptor.type') === SOURCE_TYPES.EMS_FILE;
return isEmsFile && _.get(layer, 'sourceDescriptor.id');
})
.pick((val, key) => key !== 'false')
.value()
);

const dataSourcesCountSum = _.sum(dataSourcesCount);
const layersCountSum = _.sum(layersCount);

const {
indexPatternsWithGeoFieldCount,
indexPatternsWithGeoPointFieldCount,
indexPatternsWithGeoShapeFieldCount,
} = getIndexPatternsWithGeoFieldCount(indexPatternSavedObjects);
return {
settings,
indexPatternsWithGeoFieldCount,
indexPatternsWithGeoPointFieldCount,
indexPatternsWithGeoShapeFieldCount,
// Total count of maps
mapsTotalCount: mapsCount,
// Time of capture
timeCaptured: new Date().toISOString(),
attributesPerMap: {
// Count of data sources per map
dataSourcesCount: {
min: dataSourcesCount.length ? _.min(dataSourcesCount) : 0,
max: dataSourcesCount.length ? _.max(dataSourcesCount) : 0,
avg: dataSourcesCountSum ? layersCountSum / mapsCount : 0,
},
// Total count of layers per map
layersCount: {
min: layersCount.length ? _.min(layersCount) : 0,
max: layersCount.length ? _.max(layersCount) : 0,
avg: layersCountSum ? layersCountSum / mapsCount : 0,
},
// Count of layers by type
layerTypesCount: {
...getUniqueLayerCounts(layerTypesCount, mapsCount),
},
// Count of layer by EMS region
emsVectorLayersCount: {
...getUniqueLayerCounts(emsLayersCount, mapsCount),
},
},
};
}
async function getMapSavedObjects(savedObjectsClient: SavedObjectsClientContract) {
const mapsSavedObjects = await savedObjectsClient.find({ type: MAP_SAVED_OBJECT_TYPE });
return _.get(mapsSavedObjects, 'saved_objects', []);
}

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

export async function getMapsTelemetry(config: MapsConfigType) {
const savedObjectsClient = getInternalRepository();
// @ts-ignore
const mapSavedObjects: MapSavedObject[] = await getMapSavedObjects(savedObjectsClient);
const indexPatternSavedObjects: IIndexPattern[] = await getIndexPatternSavedObjects(
// @ts-ignore
savedObjectsClient
);
const settings: SavedObjectAttribute = {
showMapVisualizationTypes: config.showMapVisualizationTypes,
};
return buildMapsTelemetry({ mapSavedObjects, indexPatternSavedObjects, settings });
}
7 changes: 4 additions & 3 deletions x-pack/test/api_integration/apis/telemetry/telemetry_local.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,10 @@ export default function ({ getService }) {
expect(stats.stack_stats.kibana.plugins.apm.services_per_agent).to.be.an('object');
expect(stats.stack_stats.kibana.plugins.infraops.last_24_hours).to.be.an('object');
expect(stats.stack_stats.kibana.plugins.kql.defaultQueryLanguage).to.be.a('string');
expect(stats.stack_stats.kibana.plugins['maps-telemetry'].attributes.timeCaptured).to.be.a(
'string'
);
expect(stats.stack_stats.kibana.plugins.maps.timeCaptured).to.be.a('string');
expect(stats.stack_stats.kibana.plugins.maps.attributes).to.be(undefined);
expect(stats.stack_stats.kibana.plugins.maps.id).to.be(undefined);
expect(stats.stack_stats.kibana.plugins.maps.type).to.be(undefined);

expect(stats.stack_stats.kibana.plugins.reporting.enabled).to.be(true);
expect(stats.stack_stats.kibana.plugins.rollups.index_patterns).to.be.an('object');
Expand Down

0 comments on commit 0c82155

Please sign in to comment.