From b051ca2960922b5f24de57639f846c5aeba1895a Mon Sep 17 00:00:00 2001 From: Zhongnan Su Date: Wed, 23 Dec 2020 17:26:43 -0800 Subject: [PATCH 1/5] add metrics --- kibana-reports/server/routes/index.ts | 2 + kibana-reports/server/routes/metric.ts | 32 +++ kibana-reports/server/routes/report.ts | 29 ++- .../server/routes/utils/constants.ts | 7 + .../server/routes/utils/metricHelper.ts | 188 ++++++++++++++++++ kibana-reports/server/routes/utils/types.ts | 27 +++ 6 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 kibana-reports/server/routes/metric.ts create mode 100644 kibana-reports/server/routes/utils/metricHelper.ts diff --git a/kibana-reports/server/routes/index.ts b/kibana-reports/server/routes/index.ts index ebceb2a3..131f5c00 100644 --- a/kibana-reports/server/routes/index.ts +++ b/kibana-reports/server/routes/index.ts @@ -16,10 +16,12 @@ import registerReportRoute from './report'; import registerReportDefinitionRoute from './reportDefinition'; import registerReportSourceRoute from './reportSource'; +import registerMetricRoute from './metric'; import { IRouter } from '../../../../src/core/server'; export default function (router: IRouter) { registerReportRoute(router); registerReportDefinitionRoute(router); registerReportSourceRoute(router); + registerMetricRoute(router); } diff --git a/kibana-reports/server/routes/metric.ts b/kibana-reports/server/routes/metric.ts new file mode 100644 index 00000000..6dc2b964 --- /dev/null +++ b/kibana-reports/server/routes/metric.ts @@ -0,0 +1,32 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import { IRouter } from '../../../../src/core/server'; +import { API_PREFIX } from '../../common'; +import { getMetrics } from './utils/metricHelper'; + +export default function (router: IRouter) { + router.get( + { + path: `${API_PREFIX}/stats`, + validate: false, + }, + async (context, request, response): Promise => { + return response.ok({ + body: getMetrics(), + }); + } + ); +} diff --git a/kibana-reports/server/routes/report.ts b/kibana-reports/server/routes/report.ts index 3f0ddcf3..b95de8ad 100644 --- a/kibana-reports/server/routes/report.ts +++ b/kibana-reports/server/routes/report.ts @@ -30,6 +30,7 @@ import { backendToUiReport, backendToUiReportsList, } from './utils/converters/backendToUi'; +import { addToMetric } from './utils/metricHelper'; export default function (router: IRouter) { // generate report (with provided metadata) @@ -51,6 +52,8 @@ export default function (router: IRouter) { //@ts-ignore const logger: Logger = context.reporting_plugin.logger; let report = request.body; + // Add to metric + addToMetric(report, 'count'); // input validation try { report.report_definition.report_params.core_params.origin = @@ -58,6 +61,7 @@ export default function (router: IRouter) { report = reportSchema.validate(report); } catch (error) { logger.error(`Failed input validation for create report ${error}`); + addToMetric(report, 'customer_error'); return response.badRequest({ body: error }); } @@ -83,6 +87,11 @@ export default function (router: IRouter) { // TODO: better error handling for delivery and stages in generating report, pass logger to deeper level logger.error(`Failed to generate report: ${error}`); logger.error(error); + if (error.statusCode && Math.floor(error.statusCode / 100) === 4) { + addToMetric(report, 'customer_error'); + } else { + addToMetric(report, 'system_error'); + } return errorResponse(response, error); } } @@ -108,6 +117,7 @@ export default function (router: IRouter) { ): Promise> => { //@ts-ignore const logger: Logger = context.reporting_plugin.logger; + let report: any; try { const savedReportId = request.params.reportId; // @ts-ignore @@ -122,7 +132,9 @@ export default function (router: IRouter) { } ); // convert report to use UI model - const report = backendToUiReport(esResp.reportInstance); + report = backendToUiReport(esResp.reportInstance); + // Add to metric + addToMetric(report, 'count'); // generate report const reportData = await createReport( request, @@ -140,6 +152,11 @@ export default function (router: IRouter) { } catch (error) { logger.error(`Failed to generate report by id: ${error}`); logger.error(error); + if (error.statusCode && Math.floor(error.statusCode / 100) === 4) { + addToMetric(report, 'customer_error'); + } else { + addToMetric(report, 'system_error'); + } return errorResponse(response, error); } } @@ -166,6 +183,7 @@ export default function (router: IRouter) { //@ts-ignore const logger: Logger = context.reporting_plugin.logger; const reportDefinitionId = request.params.reportDefinitionId; + let report: any; try { // @ts-ignore const esReportsClient: ILegacyScopedClusterClient = context.reporting_plugin.esReportsClient.asScoped( @@ -183,7 +201,9 @@ export default function (router: IRouter) { ); const reportId = esResp.reportInstance.id; // convert report to use UI model - const report = backendToUiReport(esResp.reportInstance); + report = backendToUiReport(esResp.reportInstance); + // Add to metric + addToMetric(report, 'count'); // generate report const reportData = await createReport( request, @@ -203,6 +223,11 @@ export default function (router: IRouter) { `Failed to generate report from reportDefinition id ${reportDefinitionId} : ${error}` ); logger.error(error); + if (error.statusCode && Math.floor(error.statusCode / 100) === 4) { + addToMetric(report, 'customer_error'); + } else { + addToMetric(report, 'system_error'); + } return errorResponse(response, error); } } diff --git a/kibana-reports/server/routes/utils/constants.ts b/kibana-reports/server/routes/utils/constants.ts index 9e8f245b..61e9f002 100644 --- a/kibana-reports/server/routes/utils/constants.ts +++ b/kibana-reports/server/routes/utils/constants.ts @@ -80,3 +80,10 @@ export const DEFAULT_REPORT_HEADER = '

Open Distro Kibana Reports

'; export const SECURITY_AUTH_COOKIE_NAME = 'security_authentication'; export const CHROMIUM_PATH = `${__dirname}/../../../.chromium/headless_shell`; + +/** + * Metrics setting + */ +export const WINDOW = 3600; +export const INTERVAL = 60; +export const CAPACITY = (WINDOW / INTERVAL) * 2; diff --git a/kibana-reports/server/routes/utils/metricHelper.ts b/kibana-reports/server/routes/utils/metricHelper.ts new file mode 100644 index 00000000..8881b5b7 --- /dev/null +++ b/kibana-reports/server/routes/utils/metricHelper.ts @@ -0,0 +1,188 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import { ReportSchemaType } from 'server/model'; +import { + BasicCounterType, + RollingCountersNameType, + RollingCountersType, +} from './types'; +import _ from 'lodash'; +import { CAPACITY, INTERVAL, WINDOW } from './constants'; + +export let time2CountWin: Map = new Map(); +let globalBasicCounter: BasicCounterType = { + dashboard: { + pdf: { + download: { + total: 0, + }, + }, + png: { + download: { + total: 0, + }, + }, + }, + visualization: { + pdf: { + download: { + total: 0, + }, + }, + png: { + download: { + total: 0, + }, + }, + }, + saved_search: { + csv: { + download: { + total: 0, + }, + }, + }, +}; + +let defaultRollingCounter: RollingCountersType = { + dashboard: { + pdf: { + download: { + count: 0, + system_error: 0, + customer_error: 0, + }, + }, + png: { + download: { + count: 0, + system_error: 0, + customer_error: 0, + }, + }, + }, + visualization: { + pdf: { + download: { + count: 0, + system_error: 0, + customer_error: 0, + }, + }, + png: { + download: { + count: 0, + system_error: 0, + customer_error: 0, + }, + }, + }, + saved_search: { + csv: { + download: { + count: 0, + system_error: 0, + customer_error: 0, + }, + }, + }, +}; + +export const addToMetric = ( + report: ReportSchemaType, + field: RollingCountersNameType +) => { + const count = 1; + // remove outdated key-value pairs + trim(); + + const timeKey = getKey(Date.now()); + const rollingCounters = time2CountWin.get(timeKey); + rollingCounters + ? time2CountWin.set( + timeKey, + updateCounters(report, field, rollingCounters, count) + ) + : time2CountWin.set( + timeKey, + updateCounters(report, field, _.cloneDeep(defaultRollingCounter), count) + ); +}; + +const trim = () => { + if (time2CountWin.size > CAPACITY) { + time2CountWin.forEach((_value, key, map) => { + if (key < getKey(Date.now() - WINDOW * 1000)) { + map.delete(key); + } + }); + } +}; + +const getKey = (milliseconds: number) => { + return Math.floor(milliseconds / 1000 / INTERVAL); +}; + +const getPreKey = (milliseconds: number) => { + return getKey(milliseconds) - 1; +}; + +export const getMetrics = () => { + const preTimeKey = getPreKey(Date.now()); + const rollingCounters = time2CountWin.get(preTimeKey); + const metrics = buildMetrics(rollingCounters, globalBasicCounter); + return metrics; +}; + +const buildMetrics = ( + rollingCounters: RollingCountersType | undefined, + basicCounters: BasicCounterType +) => { + if (!rollingCounters) { + rollingCounters = defaultRollingCounter; + } + return _.merge(rollingCounters, basicCounters); +}; + +const updateCounters = ( + report: ReportSchemaType, + field: RollingCountersNameType, + rollingCounter: RollingCountersType, + count: number +) => { + const { + report_definition: { + report_params: { + report_source: source, + core_params: { report_format: format }, + }, + }, + } = report; + + // @ts-ignore + rollingCounter[source.toLowerCase().replace(' ', '_')][format]['download'][ + field + ] += count; + //update basic counter for total + if (field === 'count') { + //@ts-ignore + globalBasicCounter[source.toLowerCase().replace(' ', '_')][format][ + 'download' + ]['total']++; + } + + return rollingCounter; +}; diff --git a/kibana-reports/server/routes/utils/types.ts b/kibana-reports/server/routes/utils/types.ts index 1f9226a2..7eb1baaf 100644 --- a/kibana-reports/server/routes/utils/types.ts +++ b/kibana-reports/server/routes/utils/types.ts @@ -18,3 +18,30 @@ export interface CreateReportResultType { dataUrl: string; fileName: string; } + +type ReportSource = 'dashboard' | 'visualization' | 'saved_search'; +type ReportFormat = 'pdf' | 'png' | 'csv'; +export type RollingCountersNameType = + | 'count' + | 'system_error' + | 'customer_error'; + +export type RollingCountersType = { + [source in ReportSource]: { + [format in ReportFormat]?: { + download: { + [counter in RollingCountersNameType]: number; + }; + }; + }; +}; + +export type BasicCounterType = { + [source in ReportSource]: { + [format in ReportFormat]?: { + download: { + total: number; + }; + }; + }; +}; From f90d30ac949ef43aed270fd54c5c9f1407a49e4a Mon Sep 17 00:00:00 2001 From: Zhongnan Su Date: Wed, 23 Dec 2020 17:47:06 -0800 Subject: [PATCH 2/5] clean code --- kibana-reports/server/routes/metric.ts | 27 +++++++++++++++---- kibana-reports/server/routes/report.ts | 3 --- .../server/routes/utils/constants.ts | 4 +-- .../server/routes/utils/metricHelper.ts | 14 +++++----- kibana-reports/server/routes/utils/types.ts | 5 ++-- 5 files changed, 33 insertions(+), 20 deletions(-) diff --git a/kibana-reports/server/routes/metric.ts b/kibana-reports/server/routes/metric.ts index 6dc2b964..9a3570ee 100644 --- a/kibana-reports/server/routes/metric.ts +++ b/kibana-reports/server/routes/metric.ts @@ -13,8 +13,13 @@ * permissions and limitations under the License. */ -import { IRouter } from '../../../../src/core/server'; +import { + IKibanaResponse, + IRouter, + ResponseError, +} from '../../../../src/core/server'; import { API_PREFIX } from '../../common'; +import { errorResponse } from './utils/helpers'; import { getMetrics } from './utils/metricHelper'; export default function (router: IRouter) { @@ -23,10 +28,22 @@ export default function (router: IRouter) { path: `${API_PREFIX}/stats`, validate: false, }, - async (context, request, response): Promise => { - return response.ok({ - body: getMetrics(), - }); + async ( + context, + request, + response + ): Promise> => { + //@ts-ignore + const logger: Logger = context.reporting_plugin.logger; + try { + const metrics = getMetrics(); + return response.ok({ + body: metrics, + }); + } catch (error) { + logger.error(`failed during query reporting stats: ${error}`); + return errorResponse(response, error); + } } ); } diff --git a/kibana-reports/server/routes/report.ts b/kibana-reports/server/routes/report.ts index b95de8ad..ad108242 100644 --- a/kibana-reports/server/routes/report.ts +++ b/kibana-reports/server/routes/report.ts @@ -52,7 +52,6 @@ export default function (router: IRouter) { //@ts-ignore const logger: Logger = context.reporting_plugin.logger; let report = request.body; - // Add to metric addToMetric(report, 'count'); // input validation try { @@ -133,7 +132,6 @@ export default function (router: IRouter) { ); // convert report to use UI model report = backendToUiReport(esResp.reportInstance); - // Add to metric addToMetric(report, 'count'); // generate report const reportData = await createReport( @@ -202,7 +200,6 @@ export default function (router: IRouter) { const reportId = esResp.reportInstance.id; // convert report to use UI model report = backendToUiReport(esResp.reportInstance); - // Add to metric addToMetric(report, 'count'); // generate report const reportData = await createReport( diff --git a/kibana-reports/server/routes/utils/constants.ts b/kibana-reports/server/routes/utils/constants.ts index 61e9f002..73a764d2 100644 --- a/kibana-reports/server/routes/utils/constants.ts +++ b/kibana-reports/server/routes/utils/constants.ts @@ -13,8 +13,6 @@ * permissions and limitations under the License. */ -import { PLUGIN_ID } from '../../../common'; - export enum FORMAT { pdf = 'pdf', png = 'png', @@ -82,7 +80,7 @@ export const SECURITY_AUTH_COOKIE_NAME = 'security_authentication'; export const CHROMIUM_PATH = `${__dirname}/../../../.chromium/headless_shell`; /** - * Metrics setting + * Metrics setting constants */ export const WINDOW = 3600; export const INTERVAL = 60; diff --git a/kibana-reports/server/routes/utils/metricHelper.ts b/kibana-reports/server/routes/utils/metricHelper.ts index 8881b5b7..ce1b6ce8 100644 --- a/kibana-reports/server/routes/utils/metricHelper.ts +++ b/kibana-reports/server/routes/utils/metricHelper.ts @@ -122,6 +122,13 @@ export const addToMetric = ( ); }; +export const getMetrics = () => { + const preTimeKey = getPreKey(Date.now()); + const rollingCounters = time2CountWin.get(preTimeKey); + const metrics = buildMetrics(rollingCounters, globalBasicCounter); + return metrics; +}; + const trim = () => { if (time2CountWin.size > CAPACITY) { time2CountWin.forEach((_value, key, map) => { @@ -140,13 +147,6 @@ const getPreKey = (milliseconds: number) => { return getKey(milliseconds) - 1; }; -export const getMetrics = () => { - const preTimeKey = getPreKey(Date.now()); - const rollingCounters = time2CountWin.get(preTimeKey); - const metrics = buildMetrics(rollingCounters, globalBasicCounter); - return metrics; -}; - const buildMetrics = ( rollingCounters: RollingCountersType | undefined, basicCounters: BasicCounterType diff --git a/kibana-reports/server/routes/utils/types.ts b/kibana-reports/server/routes/utils/types.ts index 7eb1baaf..473de7c8 100644 --- a/kibana-reports/server/routes/utils/types.ts +++ b/kibana-reports/server/routes/utils/types.ts @@ -21,6 +21,7 @@ export interface CreateReportResultType { type ReportSource = 'dashboard' | 'visualization' | 'saved_search'; type ReportFormat = 'pdf' | 'png' | 'csv'; +type UserActionType = 'download'; export type RollingCountersNameType = | 'count' | 'system_error' @@ -29,7 +30,7 @@ export type RollingCountersNameType = export type RollingCountersType = { [source in ReportSource]: { [format in ReportFormat]?: { - download: { + [action in UserActionType]: { [counter in RollingCountersNameType]: number; }; }; @@ -39,7 +40,7 @@ export type RollingCountersType = { export type BasicCounterType = { [source in ReportSource]: { [format in ReportFormat]?: { - download: { + [action in UserActionType]: { total: number; }; }; From 756467ad5cd0d273d90300d59d8f86729e08466e Mon Sep 17 00:00:00 2001 From: Zhongnan Su Date: Tue, 29 Dec 2020 14:13:15 -0800 Subject: [PATCH 3/5] add usage metrics --- kibana-reports/server/routes/report.ts | 33 ++-- .../server/routes/reportDefinition.ts | 16 +- .../server/routes/utils/constants.ts | 160 ++++++++++++++- kibana-reports/server/routes/utils/helpers.ts | 8 + .../server/routes/utils/metricHelper.ts | 185 ++++++------------ kibana-reports/server/routes/utils/types.ts | 58 ++++-- 6 files changed, 301 insertions(+), 159 deletions(-) diff --git a/kibana-reports/server/routes/report.ts b/kibana-reports/server/routes/report.ts index ad108242..43473db0 100644 --- a/kibana-reports/server/routes/report.ts +++ b/kibana-reports/server/routes/report.ts @@ -24,7 +24,7 @@ import { import { API_PREFIX } from '../../common'; import { createReport } from './lib/createReport'; import { reportSchema } from '../model'; -import { errorResponse } from './utils/helpers'; +import { checkErrorType, errorResponse } from './utils/helpers'; import { DEFAULT_MAX_SIZE, DELIVERY_TYPE } from './utils/constants'; import { backendToUiReport, @@ -52,7 +52,7 @@ export default function (router: IRouter) { //@ts-ignore const logger: Logger = context.reporting_plugin.logger; let report = request.body; - addToMetric(report, 'count'); + // input validation try { report.report_definition.report_params.core_params.origin = @@ -60,7 +60,7 @@ export default function (router: IRouter) { report = reportSchema.validate(report); } catch (error) { logger.error(`Failed input validation for create report ${error}`); - addToMetric(report, 'customer_error'); + addToMetric('report', 'create', 'user_error', report); return response.badRequest({ body: error }); } @@ -69,6 +69,7 @@ export default function (router: IRouter) { // if not deliver to user himself , no need to send actual file data to client const delivery = report.report_definition.delivery; + addToMetric('report', 'create', 'count', report); if ( delivery.delivery_type === DELIVERY_TYPE.kibanaUser && delivery.delivery_params.kibana_recipients.length === 0 @@ -86,11 +87,7 @@ export default function (router: IRouter) { // TODO: better error handling for delivery and stages in generating report, pass logger to deeper level logger.error(`Failed to generate report: ${error}`); logger.error(error); - if (error.statusCode && Math.floor(error.statusCode / 100) === 4) { - addToMetric(report, 'customer_error'); - } else { - addToMetric(report, 'system_error'); - } + addToMetric('report', 'create', checkErrorType(error), report); return errorResponse(response, error); } } @@ -132,7 +129,6 @@ export default function (router: IRouter) { ); // convert report to use UI model report = backendToUiReport(esResp.reportInstance); - addToMetric(report, 'count'); // generate report const reportData = await createReport( request, @@ -140,6 +136,7 @@ export default function (router: IRouter) { report, savedReportId ); + addToMetric('report', 'download', 'count', report); return response.ok({ body: { @@ -150,11 +147,7 @@ export default function (router: IRouter) { } catch (error) { logger.error(`Failed to generate report by id: ${error}`); logger.error(error); - if (error.statusCode && Math.floor(error.statusCode / 100) === 4) { - addToMetric(report, 'customer_error'); - } else { - addToMetric(report, 'system_error'); - } + addToMetric('report', 'download', checkErrorType(error), report); return errorResponse(response, error); } } @@ -200,7 +193,6 @@ export default function (router: IRouter) { const reportId = esResp.reportInstance.id; // convert report to use UI model report = backendToUiReport(esResp.reportInstance); - addToMetric(report, 'count'); // generate report const reportData = await createReport( request, @@ -208,6 +200,7 @@ export default function (router: IRouter) { report, reportId ); + addToMetric('report', 'create', 'count', report); return response.ok({ body: { @@ -220,11 +213,7 @@ export default function (router: IRouter) { `Failed to generate report from reportDefinition id ${reportDefinitionId} : ${error}` ); logger.error(error); - if (error.statusCode && Math.floor(error.statusCode / 100) === 4) { - addToMetric(report, 'customer_error'); - } else { - addToMetric(report, 'system_error'); - } + addToMetric('report', 'create', checkErrorType(error), report); return errorResponse(response, error); } } @@ -265,6 +254,7 @@ export default function (router: IRouter) { ); const reportsList = backendToUiReportsList(esResp.reportInstanceList); + addToMetric('report', 'list', 'count'); return response.ok({ body: { @@ -276,6 +266,7 @@ export default function (router: IRouter) { context.reporting_plugin.logger.error( `Failed to get reports details: ${error}` ); + addToMetric('report', 'list', checkErrorType(error)); return errorResponse(response, error); } } @@ -310,6 +301,7 @@ export default function (router: IRouter) { ); const report = backendToUiReport(esResp.reportInstance); + addToMetric('report', 'info', 'count'); return response.ok({ body: report, @@ -319,6 +311,7 @@ export default function (router: IRouter) { context.reporting_plugin.logger.error( `Failed to get single report details: ${error}` ); + addToMetric('report', 'info', checkErrorType(error)); return errorResponse(response, error); } } diff --git a/kibana-reports/server/routes/reportDefinition.ts b/kibana-reports/server/routes/reportDefinition.ts index 285f08bf..7ae3c801 100644 --- a/kibana-reports/server/routes/reportDefinition.ts +++ b/kibana-reports/server/routes/reportDefinition.ts @@ -22,7 +22,7 @@ import { } from '../../../../src/core/server'; import { API_PREFIX } from '../../common'; import { reportDefinitionSchema } from '../model'; -import { errorResponse } from './utils/helpers'; +import { checkErrorType, errorResponse } from './utils/helpers'; import { createReportDefinition } from './lib/createReportDefinition'; import { backendToUiReportDefinition, @@ -30,6 +30,7 @@ import { } from './utils/converters/backendToUi'; import { updateReportDefinition } from './lib/updateReportDefinition'; import { DEFAULT_MAX_SIZE } from './utils/constants'; +import { addToMetric } from './utils/metricHelper'; export default function (router: IRouter) { // Create report Definition @@ -57,6 +58,7 @@ export default function (router: IRouter) { logger.error( `Failed input validation for create report definition ${error}` ); + addToMetric('report_definition', 'create', 'user_error'); return response.badRequest({ body: error }); } @@ -68,6 +70,7 @@ export default function (router: IRouter) { reportDefinition ); + addToMetric('report_definition', 'create', 'count'); return response.ok({ body: { state: 'Report definition created', @@ -76,6 +79,7 @@ export default function (router: IRouter) { }); } catch (error) { logger.error(`Failed to create report definition: ${error}`); + addToMetric('report_definition', 'create', checkErrorType(error)); return errorResponse(response, error); } } @@ -109,6 +113,7 @@ export default function (router: IRouter) { logger.error( `Failed input validation for update report definition ${error}` ); + addToMetric('report_definition', 'update', 'user_error'); return response.badRequest({ body: error }); } // Update report definition metadata @@ -119,6 +124,7 @@ export default function (router: IRouter) { reportDefinition ); + addToMetric('report_definition', 'update', 'count'); return response.ok({ body: { state: 'Report definition updated', @@ -127,6 +133,7 @@ export default function (router: IRouter) { }); } catch (error) { logger.error(`Failed to update report definition: ${error}`); + addToMetric('report_definition', 'update', checkErrorType(error)); return errorResponse(response, error); } } @@ -170,6 +177,8 @@ export default function (router: IRouter) { const reportDefinitionsList = backendToUiReportDefinitionsList( esResp.reportDefinitionDetailsList ); + addToMetric('report_definition', 'list', 'count'); + return response.ok({ body: { data: reportDefinitionsList, @@ -180,6 +189,7 @@ export default function (router: IRouter) { context.reporting_plugin.logger.error( `Failed to get report definition details: ${error}` ); + addToMetric('report_definition', 'list', checkErrorType(error)); return errorResponse(response, error); } } @@ -216,6 +226,7 @@ export default function (router: IRouter) { const reportDefinition = backendToUiReportDefinition( esResp.reportDefinitionDetails ); + addToMetric('report_definition', 'info', 'count'); return response.ok({ body: { report_definition: reportDefinition }, @@ -225,6 +236,7 @@ export default function (router: IRouter) { context.reporting_plugin.logger.error( `Failed to get single report details: ${error}` ); + addToMetric('report_definition', 'info', checkErrorType(error)); return errorResponse(response, error); } } @@ -257,6 +269,7 @@ export default function (router: IRouter) { reportDefinitionId: request.params.reportDefinitionId, } ); + addToMetric('report_definition', 'delete', 'count'); return response.ok({ body: { @@ -269,6 +282,7 @@ export default function (router: IRouter) { context.reporting_plugin.logger.error( `Failed to delete report definition: ${error}` ); + addToMetric('report_definition', 'delete', checkErrorType(error)); return errorResponse(response, error); } } diff --git a/kibana-reports/server/routes/utils/constants.ts b/kibana-reports/server/routes/utils/constants.ts index 73a764d2..b3955fb9 100644 --- a/kibana-reports/server/routes/utils/constants.ts +++ b/kibana-reports/server/routes/utils/constants.ts @@ -13,6 +13,8 @@ * permissions and limitations under the License. */ +import { BasicCounters, RollingCounters } from './types'; + export enum FORMAT { pdf = 'pdf', png = 'png', @@ -80,8 +82,164 @@ export const SECURITY_AUTH_COOKIE_NAME = 'security_authentication'; export const CHROMIUM_PATH = `${__dirname}/../../../.chromium/headless_shell`; /** - * Metrics setting constants + * Metric constants */ export const WINDOW = 3600; export const INTERVAL = 60; export const CAPACITY = (WINDOW / INTERVAL) * 2; + +export const GLOBAL_BASIC_COUNTER: BasicCounters = { + usage: { + report: { + create: { + total: 0, + }, + download: { + total: 0, + }, + list: { + total: 0, + }, + info: { + total: 0, + }, + }, + report_definition: { + create: { + total: 0, + }, + list: { + total: 0, + }, + info: { + total: 0, + }, + update: { + total: 0, + }, + delete: { + total: 0, + }, + }, + }, + business: { + dashboard: { + pdf: { + download: { + total: 0, + }, + }, + png: { + download: { + total: 0, + }, + }, + }, + visualization: { + pdf: { + download: { + total: 0, + }, + }, + png: { + download: { + total: 0, + }, + }, + }, + saved_search: { + csv: { + download: { + total: 0, + }, + }, + }, + }, +}; + +export const DEFAULT_ROLLING_COUNTER: RollingCounters = { + usage: { + report: { + create: { + count: 0, + system_error: 0, + user_error: 0, + }, + download: { + count: 0, + system_error: 0, + user_error: 0, + }, + list: { + count: 0, + system_error: 0, + user_error: 0, + }, + info: { + count: 0, + system_error: 0, + user_error: 0, + }, + }, + report_definition: { + create: { + count: 0, + system_error: 0, + user_error: 0, + }, + list: { + count: 0, + system_error: 0, + user_error: 0, + }, + info: { + count: 0, + system_error: 0, + user_error: 0, + }, + update: { + count: 0, + system_error: 0, + user_error: 0, + }, + delete: { + count: 0, + system_error: 0, + user_error: 0, + }, + }, + }, + business: { + dashboard: { + pdf: { + download: { + count: 0, + }, + }, + png: { + download: { + count: 0, + }, + }, + }, + visualization: { + pdf: { + download: { + count: 0, + }, + }, + png: { + download: { + count: 0, + }, + }, + }, + saved_search: { + csv: { + download: { + count: 0, + }, + }, + }, + }, +}; diff --git a/kibana-reports/server/routes/utils/helpers.ts b/kibana-reports/server/routes/utils/helpers.ts index 40c8a492..7e68fc2f 100644 --- a/kibana-reports/server/routes/utils/helpers.ts +++ b/kibana-reports/server/routes/utils/helpers.ts @@ -86,3 +86,11 @@ export const callCluster = async ( } return esResp; }; + +export const checkErrorType = (error: any) => { + if (error.statusCode && Math.floor(error.statusCode / 100) === 4) { + return 'user_error'; + } else { + return 'system_error'; + } +}; diff --git a/kibana-reports/server/routes/utils/metricHelper.ts b/kibana-reports/server/routes/utils/metricHelper.ts index ce1b6ce8..bbd54d1d 100644 --- a/kibana-reports/server/routes/utils/metricHelper.ts +++ b/kibana-reports/server/routes/utils/metricHelper.ts @@ -15,95 +15,27 @@ import { ReportSchemaType } from 'server/model'; import { - BasicCounterType, + EntityType, RollingCountersNameType, - RollingCountersType, + RollingCounters, + UsageActionType, } from './types'; import _ from 'lodash'; -import { CAPACITY, INTERVAL, WINDOW } from './constants'; +import { + CAPACITY, + DEFAULT_ROLLING_COUNTER, + GLOBAL_BASIC_COUNTER, + INTERVAL, + WINDOW, +} from './constants'; -export let time2CountWin: Map = new Map(); -let globalBasicCounter: BasicCounterType = { - dashboard: { - pdf: { - download: { - total: 0, - }, - }, - png: { - download: { - total: 0, - }, - }, - }, - visualization: { - pdf: { - download: { - total: 0, - }, - }, - png: { - download: { - total: 0, - }, - }, - }, - saved_search: { - csv: { - download: { - total: 0, - }, - }, - }, -}; - -let defaultRollingCounter: RollingCountersType = { - dashboard: { - pdf: { - download: { - count: 0, - system_error: 0, - customer_error: 0, - }, - }, - png: { - download: { - count: 0, - system_error: 0, - customer_error: 0, - }, - }, - }, - visualization: { - pdf: { - download: { - count: 0, - system_error: 0, - customer_error: 0, - }, - }, - png: { - download: { - count: 0, - system_error: 0, - customer_error: 0, - }, - }, - }, - saved_search: { - csv: { - download: { - count: 0, - system_error: 0, - customer_error: 0, - }, - }, - }, -}; +export const time2CountWin: Map = new Map(); export const addToMetric = ( - report: ReportSchemaType, - field: RollingCountersNameType + entity: EntityType, + action: UsageActionType, + counter: RollingCountersNameType, + reportMetadata?: ReportSchemaType ) => { const count = 1; // remove outdated key-value pairs @@ -111,28 +43,32 @@ export const addToMetric = ( const timeKey = getKey(Date.now()); const rollingCounters = time2CountWin.get(timeKey); - rollingCounters - ? time2CountWin.set( - timeKey, - updateCounters(report, field, rollingCounters, count) - ) - : time2CountWin.set( - timeKey, - updateCounters(report, field, _.cloneDeep(defaultRollingCounter), count) - ); + + time2CountWin.set( + timeKey, + updateCounters( + entity, + action, + counter, + rollingCounters || _.cloneDeep(DEFAULT_ROLLING_COUNTER), + count, + reportMetadata + ) + ); }; export const getMetrics = () => { const preTimeKey = getPreKey(Date.now()); const rollingCounters = time2CountWin.get(preTimeKey); - const metrics = buildMetrics(rollingCounters, globalBasicCounter); + const metrics = buildMetrics(rollingCounters); return metrics; }; const trim = () => { if (time2CountWin.size > CAPACITY) { + const currentKey = getKey(Date.now() - WINDOW * 1000); time2CountWin.forEach((_value, key, map) => { - if (key < getKey(Date.now() - WINDOW * 1000)) { + if (key < currentKey) { map.delete(key); } }); @@ -147,41 +83,50 @@ const getPreKey = (milliseconds: number) => { return getKey(milliseconds) - 1; }; -const buildMetrics = ( - rollingCounters: RollingCountersType | undefined, - basicCounters: BasicCounterType -) => { +const buildMetrics = (rollingCounters: RollingCounters | undefined) => { if (!rollingCounters) { - rollingCounters = defaultRollingCounter; + rollingCounters = DEFAULT_ROLLING_COUNTER; } - return _.merge(rollingCounters, basicCounters); + return _.merge(rollingCounters, GLOBAL_BASIC_COUNTER); }; const updateCounters = ( - report: ReportSchemaType, - field: RollingCountersNameType, - rollingCounter: RollingCountersType, - count: number + entity: EntityType, + action: UsageActionType, + counter: RollingCountersNameType, + rollingCounter: RollingCounters, + count: number, + reportMetadata?: ReportSchemaType ) => { - const { - report_definition: { - report_params: { - report_source: source, - core_params: { report_format: format }, + // update business metrics + if (reportMetadata) { + const { + report_definition: { + report_params: { + report_source: source, + core_params: { report_format: format }, + }, }, - }, - } = report; + } = reportMetadata; - // @ts-ignore - rollingCounter[source.toLowerCase().replace(' ', '_')][format]['download'][ - field - ] += count; - //update basic counter for total - if (field === 'count') { - //@ts-ignore - globalBasicCounter[source.toLowerCase().replace(' ', '_')][format][ + // @ts-ignore + rollingCounter.business[source.toLowerCase().replace(' ', '_')][format][ 'download' - ]['total']++; + ][counter] += count; + //update basic counter for total + if (counter === 'count') { + //@ts-ignore + GLOBAL_BASIC_COUNTER.business[source.toLowerCase().replace(' ', '_')][ + format + ]['download']['total']++; + } + } + // update usage metric + // @ts-ignore + rollingCounter.usage[entity][action][counter] += count; + if (counter === 'count') { + // @ts-ignore + GLOBAL_BASIC_COUNTER.usage[entity][action]['total']++; } return rollingCounter; diff --git a/kibana-reports/server/routes/utils/types.ts b/kibana-reports/server/routes/utils/types.ts index 473de7c8..9871777d 100644 --- a/kibana-reports/server/routes/utils/types.ts +++ b/kibana-reports/server/routes/utils/types.ts @@ -19,30 +19,54 @@ export interface CreateReportResultType { fileName: string; } -type ReportSource = 'dashboard' | 'visualization' | 'saved_search'; -type ReportFormat = 'pdf' | 'png' | 'csv'; -type UserActionType = 'download'; -export type RollingCountersNameType = - | 'count' - | 'system_error' - | 'customer_error'; +type ReportSourceType = 'dashboard' | 'visualization' | 'saved_search'; +type ReportFormatType = 'pdf' | 'png' | 'csv'; +type BusinessActionType = 'download'; +export type RollingCountersNameType = 'count' | 'system_error' | 'user_error'; -export type RollingCountersType = { - [source in ReportSource]: { - [format in ReportFormat]?: { - [action in UserActionType]: { +export type EntityType = 'report' | 'report_definition'; +export type UsageActionType = + | 'info' + | 'list' + | 'delete' + | 'create' + | 'download' + | 'update'; + +export interface RollingCounters { + usage: { + [entity in EntityType]: { + [action in UsageActionType]?: { [counter in RollingCountersNameType]: number; }; }; }; -}; + business: { + [source in ReportSourceType]: { + [format in ReportFormatType]?: { + [action in BusinessActionType]: { + [counter in RollingCountersNameType]?: number; + }; + }; + }; + }; +} -export type BasicCounterType = { - [source in ReportSource]: { - [format in ReportFormat]?: { - [action in UserActionType]: { +export interface BasicCounters { + usage: { + [entity in EntityType]: { + [action in UsageActionType]?: { total: number; }; }; }; -}; + business: { + [source in ReportSourceType]: { + [format in ReportFormatType]?: { + [action in BusinessActionType]: { + total: number; + }; + }; + }; + }; +} From d4598bc0ea2d35d6c91a594e4c6018820d9bccab Mon Sep 17 00:00:00 2001 From: Zhongnan Su Date: Tue, 29 Dec 2020 16:54:16 -0800 Subject: [PATCH 4/5] update --- kibana-reports/server/routes/reportSource.ts | 6 +- .../utils/__tests__/metricHelper.test.ts | 38 +++ .../server/routes/utils/constants.ts | 248 +++++++++--------- .../server/routes/utils/metricHelper.ts | 42 +-- kibana-reports/server/routes/utils/types.ts | 56 ++-- 5 files changed, 211 insertions(+), 179 deletions(-) create mode 100644 kibana-reports/server/routes/utils/__tests__/metricHelper.test.ts diff --git a/kibana-reports/server/routes/reportSource.ts b/kibana-reports/server/routes/reportSource.ts index f628ac13..e7fd0d96 100644 --- a/kibana-reports/server/routes/reportSource.ts +++ b/kibana-reports/server/routes/reportSource.ts @@ -19,10 +19,11 @@ import { ResponseError, } from '../../../../src/core/server'; import { API_PREFIX } from '../../common'; -import { parseEsErrorResponse } from './utils/helpers'; +import { checkErrorType, parseEsErrorResponse } from './utils/helpers'; import { RequestParams } from '@elastic/elasticsearch'; import { schema } from '@kbn/config-schema'; import { DEFAULT_MAX_SIZE } from './utils/constants'; +import { addToMetric } from './utils/metricHelper'; export default function (router: IRouter) { router.get( @@ -67,6 +68,8 @@ export default function (router: IRouter) { 'search', responseParams ); + addToMetric('report_source', 'list', 'count'); + return response.ok({ body: esResp, }); @@ -75,6 +78,7 @@ export default function (router: IRouter) { context.reporting_plugin.logger.error( `Failed to get reports source for ${request.params.reportSourceType}: ${error}` ); + addToMetric('report_source', 'list', checkErrorType(error)); return response.custom({ statusCode: error.statusCode, body: parseEsErrorResponse(error), diff --git a/kibana-reports/server/routes/utils/__tests__/metricHelper.test.ts b/kibana-reports/server/routes/utils/__tests__/metricHelper.test.ts new file mode 100644 index 00000000..d0713908 --- /dev/null +++ b/kibana-reports/server/routes/utils/__tests__/metricHelper.test.ts @@ -0,0 +1,38 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import { checkErrorType } from '../helpers'; + +describe('Test collecting metrics', () => { + // TODO: need more tests + + test('check error type', () => { + const badRequestError = { + statusCode: 400, + }; + const serverError = { + statusCode: 500, + }; + const unknownError = { + statusCode: undefined, + }; + const userErrorType = checkErrorType(badRequestError); + const sysErrorType = checkErrorType(serverError); + const unknownErrorType = checkErrorType(unknownError); + expect(userErrorType).toEqual('user_error'); + expect(sysErrorType).toEqual('system_error'); + expect(unknownErrorType).toEqual('system_error'); + }); +}); diff --git a/kibana-reports/server/routes/utils/constants.ts b/kibana-reports/server/routes/utils/constants.ts index b3955fb9..beb9ddf0 100644 --- a/kibana-reports/server/routes/utils/constants.ts +++ b/kibana-reports/server/routes/utils/constants.ts @@ -13,7 +13,7 @@ * permissions and limitations under the License. */ -import { BasicCounters, RollingCounters } from './types'; +import { CountersType } from './types'; export enum FORMAT { pdf = 'pdf', @@ -88,157 +88,161 @@ export const WINDOW = 3600; export const INTERVAL = 60; export const CAPACITY = (WINDOW / INTERVAL) * 2; -export const GLOBAL_BASIC_COUNTER: BasicCounters = { - usage: { - report: { - create: { - total: 0, - }, +export const GLOBAL_BASIC_COUNTER: CountersType = { + report: { + create: { + total: 0, + }, + download: { + total: 0, + }, + list: { + total: 0, + }, + info: { + total: 0, + }, + }, + report_definition: { + create: { + total: 0, + }, + list: { + total: 0, + }, + info: { + total: 0, + }, + update: { + total: 0, + }, + delete: { + total: 0, + }, + }, + report_source: { + list: { + total: 0, + }, + }, + dashboard: { + pdf: { download: { total: 0, }, - list: { - total: 0, - }, - info: { - total: 0, - }, }, - report_definition: { - create: { - total: 0, - }, - list: { + png: { + download: { total: 0, }, - info: { + }, + }, + visualization: { + pdf: { + download: { total: 0, }, - update: { + }, + png: { + download: { total: 0, }, - delete: { + }, + }, + saved_search: { + csv: { + download: { total: 0, }, }, }, - business: { - dashboard: { - pdf: { - download: { - total: 0, - }, - }, - png: { - download: { - total: 0, - }, - }, +}; + +export const DEFAULT_ROLLING_COUNTER: CountersType = { + report: { + create: { + count: 0, + system_error: 0, + user_error: 0, }, - visualization: { - pdf: { - download: { - total: 0, - }, - }, - png: { - download: { - total: 0, - }, - }, + download: { + count: 0, + system_error: 0, + user_error: 0, }, - saved_search: { - csv: { - download: { - total: 0, - }, - }, + list: { + count: 0, + system_error: 0, + user_error: 0, + }, + info: { + count: 0, + system_error: 0, + user_error: 0, }, }, -}; - -export const DEFAULT_ROLLING_COUNTER: RollingCounters = { - usage: { - report: { - create: { - count: 0, - system_error: 0, - user_error: 0, - }, + report_definition: { + create: { + count: 0, + system_error: 0, + user_error: 0, + }, + list: { + count: 0, + system_error: 0, + user_error: 0, + }, + info: { + count: 0, + system_error: 0, + user_error: 0, + }, + update: { + count: 0, + system_error: 0, + user_error: 0, + }, + delete: { + count: 0, + system_error: 0, + user_error: 0, + }, + }, + report_source: { + list: { + count: 0, + system_error: 0, + user_error: 0, + }, + }, + dashboard: { + pdf: { download: { count: 0, - system_error: 0, - user_error: 0, - }, - list: { - count: 0, - system_error: 0, - user_error: 0, - }, - info: { - count: 0, - system_error: 0, - user_error: 0, }, }, - report_definition: { - create: { - count: 0, - system_error: 0, - user_error: 0, - }, - list: { - count: 0, - system_error: 0, - user_error: 0, - }, - info: { - count: 0, - system_error: 0, - user_error: 0, - }, - update: { - count: 0, - system_error: 0, - user_error: 0, - }, - delete: { + png: { + download: { count: 0, - system_error: 0, - user_error: 0, }, }, }, - business: { - dashboard: { - pdf: { - download: { - count: 0, - }, - }, - png: { - download: { - count: 0, - }, + visualization: { + pdf: { + download: { + count: 0, }, }, - visualization: { - pdf: { - download: { - count: 0, - }, - }, - png: { - download: { - count: 0, - }, + png: { + download: { + count: 0, }, }, - saved_search: { - csv: { - download: { - count: 0, - }, + }, + saved_search: { + csv: { + download: { + count: 0, }, }, }, diff --git a/kibana-reports/server/routes/utils/metricHelper.ts b/kibana-reports/server/routes/utils/metricHelper.ts index bbd54d1d..fb4b7332 100644 --- a/kibana-reports/server/routes/utils/metricHelper.ts +++ b/kibana-reports/server/routes/utils/metricHelper.ts @@ -16,9 +16,9 @@ import { ReportSchemaType } from 'server/model'; import { EntityType, - RollingCountersNameType, - RollingCounters, - UsageActionType, + CountersNameType, + CountersType, + ActionType, } from './types'; import _ from 'lodash'; import { @@ -29,12 +29,12 @@ import { WINDOW, } from './constants'; -export const time2CountWin: Map = new Map(); +export const time2CountWin: Map = new Map(); export const addToMetric = ( entity: EntityType, - action: UsageActionType, - counter: RollingCountersNameType, + action: ActionType, + counter: CountersNameType, reportMetadata?: ReportSchemaType ) => { const count = 1; @@ -83,7 +83,7 @@ const getPreKey = (milliseconds: number) => { return getKey(milliseconds) - 1; }; -const buildMetrics = (rollingCounters: RollingCounters | undefined) => { +const buildMetrics = (rollingCounters: CountersType | undefined) => { if (!rollingCounters) { rollingCounters = DEFAULT_ROLLING_COUNTER; } @@ -92,13 +92,13 @@ const buildMetrics = (rollingCounters: RollingCounters | undefined) => { const updateCounters = ( entity: EntityType, - action: UsageActionType, - counter: RollingCountersNameType, - rollingCounter: RollingCounters, + action: ActionType, + counter: CountersNameType, + rollingCounter: CountersType, count: number, reportMetadata?: ReportSchemaType ) => { - // update business metrics + // update usage metrics if (reportMetadata) { const { report_definition: { @@ -110,23 +110,23 @@ const updateCounters = ( } = reportMetadata; // @ts-ignore - rollingCounter.business[source.toLowerCase().replace(' ', '_')][format][ - 'download' - ][counter] += count; - //update basic counter for total + rollingCounter[source.toLowerCase().replace(' ', '_')][format]['download'][ + counter + ] += count; + // update basic counter for total request count if (counter === 'count') { //@ts-ignore - GLOBAL_BASIC_COUNTER.business[source.toLowerCase().replace(' ', '_')][ - format - ]['download']['total']++; + GLOBAL_BASIC_COUNTER[source.toLowerCase().replace(' ', '_')][format][ + 'download' + ]['total']++; } } - // update usage metric + // update action metric per API // @ts-ignore - rollingCounter.usage[entity][action][counter] += count; + rollingCounter[entity][action][counter] += count; if (counter === 'count') { // @ts-ignore - GLOBAL_BASIC_COUNTER.usage[entity][action]['total']++; + GLOBAL_BASIC_COUNTER[entity][action]['total']++; } return rollingCounter; diff --git a/kibana-reports/server/routes/utils/types.ts b/kibana-reports/server/routes/utils/types.ts index 9871777d..6e7d1d75 100644 --- a/kibana-reports/server/routes/utils/types.ts +++ b/kibana-reports/server/routes/utils/types.ts @@ -21,11 +21,15 @@ export interface CreateReportResultType { type ReportSourceType = 'dashboard' | 'visualization' | 'saved_search'; type ReportFormatType = 'pdf' | 'png' | 'csv'; -type BusinessActionType = 'download'; -export type RollingCountersNameType = 'count' | 'system_error' | 'user_error'; +type UsageActionType = 'download'; +export type EntityType = 'report' | 'report_definition' | 'report_source'; -export type EntityType = 'report' | 'report_definition'; -export type UsageActionType = +export type CountersNameType = + | 'count' + | 'system_error' + | 'user_error' + | 'total'; +export type ActionType = | 'info' | 'list' | 'delete' @@ -33,40 +37,22 @@ export type UsageActionType = | 'download' | 'update'; -export interface RollingCounters { - usage: { - [entity in EntityType]: { - [action in UsageActionType]?: { - [counter in RollingCountersNameType]: number; - }; - }; - }; - business: { - [source in ReportSourceType]: { - [format in ReportFormatType]?: { - [action in BusinessActionType]: { - [counter in RollingCountersNameType]?: number; - }; - }; - }; - }; -} +export type CountersType = ActionCountersType & UsageCountersType; -export interface BasicCounters { - usage: { - [entity in EntityType]: { - [action in UsageActionType]?: { - total: number; - }; +type ActionCountersType = { + [entity in EntityType]: { + [action in ActionType]?: { + [counter in CountersNameType]?: number; }; }; - business: { - [source in ReportSourceType]: { - [format in ReportFormatType]?: { - [action in BusinessActionType]: { - total: number; - }; +}; + +type UsageCountersType = { + [source in ReportSourceType]: { + [format in ReportFormatType]?: { + [action in UsageActionType]: { + [counter in CountersNameType]?: number; }; }; }; -} +}; From e2323d6a15198ff209f16447221e981171e85f09 Mon Sep 17 00:00:00 2001 From: Zhongnan Su Date: Tue, 29 Dec 2020 19:47:25 -0800 Subject: [PATCH 5/5] minor fix --- kibana-reports/server/routes/report.ts | 10 +++++----- kibana-reports/server/routes/utils/constants.ts | 8 ++++++++ kibana-reports/server/routes/utils/types.ts | 3 ++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/kibana-reports/server/routes/report.ts b/kibana-reports/server/routes/report.ts index 43473db0..9244d712 100644 --- a/kibana-reports/server/routes/report.ts +++ b/kibana-reports/server/routes/report.ts @@ -60,7 +60,7 @@ export default function (router: IRouter) { report = reportSchema.validate(report); } catch (error) { logger.error(`Failed input validation for create report ${error}`); - addToMetric('report', 'create', 'user_error', report); + addToMetric('report', 'create', 'user_error'); return response.badRequest({ body: error }); } @@ -87,7 +87,7 @@ export default function (router: IRouter) { // TODO: better error handling for delivery and stages in generating report, pass logger to deeper level logger.error(`Failed to generate report: ${error}`); logger.error(error); - addToMetric('report', 'create', checkErrorType(error), report); + addToMetric('report', 'create', checkErrorType(error)); return errorResponse(response, error); } } @@ -147,7 +147,7 @@ export default function (router: IRouter) { } catch (error) { logger.error(`Failed to generate report by id: ${error}`); logger.error(error); - addToMetric('report', 'download', checkErrorType(error), report); + addToMetric('report', 'download', checkErrorType(error)); return errorResponse(response, error); } } @@ -200,7 +200,7 @@ export default function (router: IRouter) { report, reportId ); - addToMetric('report', 'create', 'count', report); + addToMetric('report', 'create_from_definition', 'count', report); return response.ok({ body: { @@ -213,7 +213,7 @@ export default function (router: IRouter) { `Failed to generate report from reportDefinition id ${reportDefinitionId} : ${error}` ); logger.error(error); - addToMetric('report', 'create', checkErrorType(error), report); + addToMetric('report', 'create_from_definition', checkErrorType(error)); return errorResponse(response, error); } } diff --git a/kibana-reports/server/routes/utils/constants.ts b/kibana-reports/server/routes/utils/constants.ts index beb9ddf0..325a8930 100644 --- a/kibana-reports/server/routes/utils/constants.ts +++ b/kibana-reports/server/routes/utils/constants.ts @@ -93,6 +93,9 @@ export const GLOBAL_BASIC_COUNTER: CountersType = { create: { total: 0, }, + create_from_definition: { + total: 0, + }, download: { total: 0, }, @@ -165,6 +168,11 @@ export const DEFAULT_ROLLING_COUNTER: CountersType = { system_error: 0, user_error: 0, }, + create_from_definition: { + count: 0, + system_error: 0, + user_error: 0, + }, download: { count: 0, system_error: 0, diff --git a/kibana-reports/server/routes/utils/types.ts b/kibana-reports/server/routes/utils/types.ts index 6e7d1d75..22f89284 100644 --- a/kibana-reports/server/routes/utils/types.ts +++ b/kibana-reports/server/routes/utils/types.ts @@ -35,7 +35,8 @@ export type ActionType = | 'delete' | 'create' | 'download' - | 'update'; + | 'update' + | 'create_from_definition'; export type CountersType = ActionCountersType & UsageCountersType;