diff --git a/src/plugins/vis_type_timeseries/server/plugin.ts b/src/plugins/vis_type_timeseries/server/plugin.ts index b667cbd3213cc..05257cb79a75c 100644 --- a/src/plugins/vis_type_timeseries/server/plugin.ts +++ b/src/plugins/vis_type_timeseries/server/plugin.ts @@ -31,6 +31,7 @@ import { Observable } from 'rxjs'; import { Server } from 'hapi'; import { VisTypeTimeseriesConfig } from './config'; import { getVisData, GetVisData, GetVisDataOptions } from './lib/get_vis_data'; +import { ValidationTelemetryService } from './validation_telemetry'; import { UsageCollectionSetup } from '../../usage_collection/server'; import { visDataRoutes } from './routes/vis'; // @ts-ignore @@ -65,8 +66,11 @@ export interface Framework { } export class VisTypeTimeseriesPlugin implements Plugin { + private validationTelementryService: ValidationTelemetryService; + constructor(private readonly initializerContext: PluginInitializerContext) { this.initializerContext = initializerContext; + this.validationTelementryService = new ValidationTelemetryService(); } public setup(core: CoreSetup, plugins: VisTypeTimeseriesPluginSetupDependencies) { @@ -88,9 +92,15 @@ export class VisTypeTimeseriesPlugin implements Plugin { searchStrategyRegistry, }; - visDataRoutes(router, framework); + (async () => { + const validationTelemetry = await this.validationTelementryService.setup(core, { + ...plugins, + globalConfig$, + }); + visDataRoutes(router, framework, validationTelemetry); - fieldsRoutes(framework); + fieldsRoutes(framework); + })(); return { getVisData: async ( diff --git a/src/plugins/vis_type_timeseries/server/routes/vis.ts b/src/plugins/vis_type_timeseries/server/routes/vis.ts index abb7af5ad802e..744020b583882 100644 --- a/src/plugins/vis_type_timeseries/server/routes/vis.ts +++ b/src/plugins/vis_type_timeseries/server/routes/vis.ts @@ -18,19 +18,38 @@ */ import { IRouter, KibanaRequest } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; import { getVisData, GetVisDataOptions } from '../lib/get_vis_data'; import { visPayloadSchema } from './post_vis_schema'; -import { Framework } from '../index'; +import { Framework, ValidationTelemetryServiceSetup } from '../index'; -export const visDataRoutes = (router: IRouter, framework: Framework) => { +const escapeHatch = schema.object({}, { unknowns: 'allow' }); + +export const visDataRoutes = ( + router: IRouter, + framework: Framework, + { logFailedValidation }: ValidationTelemetryServiceSetup +) => { router.post( { path: '/api/metrics/vis/data', validate: { - body: visPayloadSchema, + body: escapeHatch, }, }, async (requestContext, request, response) => { + try { + visPayloadSchema.validate(request.body); + } catch (error) { + logFailedValidation(); + const savedObjectId = + (typeof request.body === 'object' && (request.body as any).savedObjectId) || + 'unavailable'; + framework.logger.warn( + `Request validation error: ${error.message} (saved object id: ${savedObjectId}). This most likely means your TSVB visualization contains outdated configuration. You can report this problem under https://github.com/elastic/kibana/issues/new?template=Bug_report.md` + ); + } + try { const results = await getVisData( requestContext,