From b838c1a2184e14304c22febdb9733c2193cf982a Mon Sep 17 00:00:00 2001 From: Junqiu Lei Date: Thu, 23 Mar 2023 09:42:14 -0700 Subject: [PATCH] Add maps metrics api from saved object Signed-off-by: Junqiu Lei --- CHANGELOG.md | 1 + common/index.ts | 5 +- server/common/metrics/metrics_helper.ts | 73 +++++++++++++++++++++++++ server/common/metrics/type.ts | 19 +++++++ server/plugin.ts | 6 +- server/routes/index.ts | 3 +- server/routes/metrics_router.ts | 47 ++++++++++++++++ 7 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 server/common/metrics/metrics_helper.ts create mode 100644 server/common/metrics/type.ts create mode 100644 server/routes/metrics_router.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index d7bba741..958a730e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Infrastructure * Add CHANGELOG ([#342](https://github.com/opensearch-project/dashboards-maps/pull/342)) +* Add maps metrics api from saved object ([#362](https://github.com/opensearch-project/dashboards-maps/pull/362)) ### Documentation diff --git a/common/index.ts b/common/index.ts index c6160e8c..ae8afe1c 100644 --- a/common/index.ts +++ b/common/index.ts @@ -81,8 +81,11 @@ export const APP_PATH = { LANDING_PAGE_PATH: '/', CREATE_MAP: '/create', EDIT_MAP: '/:id', + METRICS: '/stats', }; +export const APP_API = '/api/maps-dashboards'; + export enum DASHBOARDS_MAPS_LAYER_NAME { OPENSEARCH_MAP = 'OpenSearch map', DOCUMENTS = 'Documents', @@ -146,7 +149,7 @@ export const LAYER_ICON_TYPE_MAP: { [key: string]: string } = { [DASHBOARDS_MAPS_LAYER_TYPE.CUSTOM_MAP]: 'globe', }; -//refer https://github.com/opensearch-project/i18n-plugin/blob/main/DEVELOPER_GUIDE.md#new-locale for OSD supported languages +// refer https://github.com/opensearch-project/i18n-plugin/blob/main/DEVELOPER_GUIDE.md#new-locale for OSD supported languages export const OSD_LANGUAGES = ['en', 'es', 'fr', 'de', 'ja', 'ko', 'zh']; // all these codes are also supported in vector tiles map export const FALLBACK_LANGUAGE = 'en'; diff --git a/server/common/metrics/metrics_helper.ts b/server/common/metrics/metrics_helper.ts new file mode 100644 index 00000000..7d3afc94 --- /dev/null +++ b/server/common/metrics/metrics_helper.ts @@ -0,0 +1,73 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectsFindResponse } from '../../../../../src/core/server'; +import { MapLayerSpecification } from '../../../public/model/mapLayerType'; +import { MapSavedObjectAttributes } from '../../../common/map_saved_object_attributes'; +import { MAPS_INFO, MAPS_METRICS } from './type'; +import { DASHBOARDS_MAPS_LAYER_TYPE } from '../../../common'; + +export const getMetrics = ( + mapsSavedObjects: SavedObjectsFindResponse +) => { + let totalLayersCount = 0; + let totalDocumentsLayersCount = 0; + let totalOpensearchBaseLayersCount = 0; + let totalCustomTmsLayersCount = 0; + let totalCustomWmsLayersCount = 0; + const mapsInfo: MAPS_INFO[] = []; + mapsSavedObjects.saved_objects.forEach((mapRes) => { + let documentsLayersCount = 0; + let opensearchBaseLayersCount = 0; + let customTmsLayersCount = 0; + let customWmsLayersCount = 0; + const layerList: MapLayerSpecification[] = JSON.parse(mapRes.attributes.layerList as string); + const layersCount = layerList.length; + totalLayersCount += layerList.length; + + layerList.forEach((layer) => { + switch (layer.type) { + case DASHBOARDS_MAPS_LAYER_TYPE.DOCUMENTS: + totalDocumentsLayersCount++; + documentsLayersCount++; + break; + case DASHBOARDS_MAPS_LAYER_TYPE.OPENSEARCH_MAP: + totalOpensearchBaseLayersCount++; + opensearchBaseLayersCount++; + break; + case DASHBOARDS_MAPS_LAYER_TYPE.CUSTOM_MAP: + if (layer.source.customType === 'wms') { + totalCustomWmsLayersCount++; + customWmsLayersCount++; + } else { + totalCustomTmsLayersCount++; + customTmsLayersCount++; + } + break; + } + }); + + mapsInfo.push({ + id: mapRes.id, + title: mapRes.attributes.title, + layers_total_count: layersCount, + documents_layers_total_count: documentsLayersCount, + custom_tms_layers_total_count: customTmsLayersCount, + custom_wms_layers_total_count: customWmsLayersCount, + opensearch_base_map_layers_total_count: opensearchBaseLayersCount, + }); + }); + + const metrics: MAPS_METRICS = { + maps_total_count: mapsSavedObjects.total, + layers_total_count: totalLayersCount, + documents_layers_total_count: totalDocumentsLayersCount, + custom_tms_layers_total_count: totalCustomTmsLayersCount, + custom_wms_layers_total_count: totalCustomWmsLayersCount, + opensearch_base_map_layers_total_count: totalOpensearchBaseLayersCount, + maps_info: mapsInfo, + }; + return metrics; +}; diff --git a/server/common/metrics/type.ts b/server/common/metrics/type.ts new file mode 100644 index 00000000..95e24a80 --- /dev/null +++ b/server/common/metrics/type.ts @@ -0,0 +1,19 @@ +export interface MAPS_METRICS { + maps_total_count: number; + layers_total_count: number; + documents_layers_total_count: number; + opensearch_base_map_layers_total_count: number; + custom_tms_layers_total_count: number; + custom_wms_layers_total_count: number; + maps_info: Array<{ id: string; title: string }>; +} + +export interface MAPS_INFO { + id: string; + title: string; + layers_total_count: number; + documents_layers_total_count: number; + opensearch_base_map_layers_total_count: number; + custom_tms_layers_total_count: number; + custom_wms_layers_total_count: number; +} diff --git a/server/plugin.ts b/server/plugin.ts index cae4e8ce..05c05f27 100644 --- a/server/plugin.ts +++ b/server/plugin.ts @@ -22,13 +22,14 @@ import { } from './types'; import { createGeospatialCluster } from './clusters'; import { GeospatialService, OpensearchService } from './services'; -import { geospatial, opensearch } from '../server/routes'; +import { geospatial, opensearch, metricsRoute } from '../server/routes'; import { mapSavedObjectsType } from './saved_objects'; import { capabilitiesProvider } from './saved_objects/capabilities_provider'; import { ConfigSchema } from '../common/config'; export class CustomImportMapPlugin - implements Plugin { + implements Plugin +{ private readonly logger: Logger; private readonly globalConfig$; private readonly config$; @@ -62,6 +63,7 @@ export class CustomImportMapPlugin // Register server side APIs geospatial(geospatialService, router); opensearch(opensearchService, router); + metricsRoute(router); // Register saved object types core.savedObjects.registerType(mapSavedObjectsType); diff --git a/server/routes/index.ts b/server/routes/index.ts index f3ed5073..c0f08f53 100644 --- a/server/routes/index.ts +++ b/server/routes/index.ts @@ -5,5 +5,6 @@ import geospatial from './geospatial'; import opensearch from './opensearch'; +import { metricsRoute } from './metrics_router'; -export { geospatial, opensearch }; +export { geospatial, opensearch, metricsRoute }; diff --git a/server/routes/metrics_router.ts b/server/routes/metrics_router.ts new file mode 100644 index 00000000..51b71346 --- /dev/null +++ b/server/routes/metrics_router.ts @@ -0,0 +1,47 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ResponseError } from '@opensearch-project/opensearch/lib/errors'; +import { + IOpenSearchDashboardsResponse, + IRouter, + SavedObjectsFindResponse, +} from '../../../../src/core/server'; +import { APP_API, APP_PATH } from '../../common'; +import { getMetrics } from '../common/metrics/metrics_helper'; +import { MapSavedObjectAttributes } from '../../common/map_saved_object_attributes'; + +export function metricsRoute(router: IRouter) { + router.get( + { + path: `${APP_API}${APP_PATH.METRICS}`, + validate: false, + }, + async ( + context, + request, + response + ): Promise> => { + try { + const savedObjectsClient = context.core.savedObjects.client; + const mapsSavedObjects: SavedObjectsFindResponse = + await savedObjectsClient?.find({ + type: 'map', + }); + const metrics = getMetrics(mapsSavedObjects); + return response.ok({ + body: metrics, + }); + } catch (error) { + // eslint-disable-next-line no-console + console.error(error); + return response.custom({ + statusCode: error.statusCode || 500, + body: error.message, + }); + } + } + ); +}