Skip to content

Commit

Permalink
Add frontend metrics for reporting (opendistro-for-elasticsearch#277)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhongnansu committed Jan 5, 2021
1 parent cc054d3 commit 9658563
Show file tree
Hide file tree
Showing 10 changed files with 483 additions and 6 deletions.
2 changes: 2 additions & 0 deletions kibana-reports/server/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
49 changes: 49 additions & 0 deletions kibana-reports/server/routes/metric.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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 {
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) {
router.get(
{
path: `${API_PREFIX}/stats`,
validate: false,
},
async (
context,
request,
response
): Promise<IKibanaResponse<any | ResponseError>> => {
//@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);
}
}
);
}
21 changes: 18 additions & 3 deletions kibana-reports/server/routes/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ 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,
backendToUiReportsList,
} from './utils/converters/backendToUi';
import { addToMetric } from './utils/metricHelper';

export default function (router: IRouter) {
// generate report (with provided metadata)
Expand All @@ -51,13 +52,15 @@ export default function (router: IRouter) {
//@ts-ignore
const logger: Logger = context.reporting_plugin.logger;
let report = request.body;

// input validation
try {
report.report_definition.report_params.core_params.origin =
request.headers.origin;
report = reportSchema.validate(report);
} catch (error) {
logger.error(`Failed input validation for create report ${error}`);
addToMetric('report', 'create', 'user_error');
return response.badRequest({ body: error });
}

Expand All @@ -66,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
Expand All @@ -83,6 +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));
return errorResponse(response, error);
}
}
Expand All @@ -108,6 +113,7 @@ export default function (router: IRouter) {
): Promise<IKibanaResponse<any | ResponseError>> => {
//@ts-ignore
const logger: Logger = context.reporting_plugin.logger;
let report: any;
try {
const savedReportId = request.params.reportId;
// @ts-ignore
Expand All @@ -122,14 +128,15 @@ export default function (router: IRouter) {
}
);
// convert report to use UI model
const report = backendToUiReport(esResp.reportInstance);
report = backendToUiReport(esResp.reportInstance);
// generate report
const reportData = await createReport(
request,
context,
report,
savedReportId
);
addToMetric('report', 'download', 'count', report);

return response.ok({
body: {
Expand All @@ -140,6 +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));
return errorResponse(response, error);
}
}
Expand All @@ -166,6 +174,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(
Expand All @@ -183,14 +192,15 @@ 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);
// generate report
const reportData = await createReport(
request,
context,
report,
reportId
);
addToMetric('report', 'create_from_definition', 'count', report);

return response.ok({
body: {
Expand All @@ -203,6 +213,7 @@ export default function (router: IRouter) {
`Failed to generate report from reportDefinition id ${reportDefinitionId} : ${error}`
);
logger.error(error);
addToMetric('report', 'create_from_definition', checkErrorType(error));
return errorResponse(response, error);
}
}
Expand Down Expand Up @@ -243,6 +254,7 @@ export default function (router: IRouter) {
);

const reportsList = backendToUiReportsList(esResp.reportInstanceList);
addToMetric('report', 'list', 'count');

return response.ok({
body: {
Expand All @@ -254,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);
}
}
Expand Down Expand Up @@ -288,6 +301,7 @@ export default function (router: IRouter) {
);

const report = backendToUiReport(esResp.reportInstance);
addToMetric('report', 'info', 'count');

return response.ok({
body: report,
Expand All @@ -297,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);
}
}
Expand Down
16 changes: 15 additions & 1 deletion kibana-reports/server/routes/reportDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ 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,
backendToUiReportDefinitionsList,
} 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
Expand Down Expand Up @@ -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 });
}

Expand All @@ -68,6 +70,7 @@ export default function (router: IRouter) {
reportDefinition
);

addToMetric('report_definition', 'create', 'count');
return response.ok({
body: {
state: 'Report definition created',
Expand All @@ -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);
}
}
Expand Down Expand Up @@ -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
Expand All @@ -119,6 +124,7 @@ export default function (router: IRouter) {
reportDefinition
);

addToMetric('report_definition', 'update', 'count');
return response.ok({
body: {
state: 'Report definition updated',
Expand All @@ -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);
}
}
Expand Down Expand Up @@ -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,
Expand All @@ -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);
}
}
Expand Down Expand Up @@ -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 },
Expand All @@ -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);
}
}
Expand Down Expand Up @@ -257,6 +269,7 @@ export default function (router: IRouter) {
reportDefinitionId: request.params.reportDefinitionId,
}
);
addToMetric('report_definition', 'delete', 'count');

return response.ok({
body: {
Expand All @@ -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);
}
}
Expand Down
6 changes: 5 additions & 1 deletion kibana-reports/server/routes/reportSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -67,6 +68,8 @@ export default function (router: IRouter) {
'search',
responseParams
);
addToMetric('report_source', 'list', 'count');

return response.ok({
body: esResp,
});
Expand All @@ -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),
Expand Down
38 changes: 38 additions & 0 deletions kibana-reports/server/routes/utils/__tests__/metricHelper.test.ts
Original file line number Diff line number Diff line change
@@ -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');
});
});
Loading

0 comments on commit 9658563

Please sign in to comment.