diff --git a/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_working_collector.ts b/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_working_collector.ts index b238c5aa346ad..54983278726eb 100644 --- a/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_working_collector.ts +++ b/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_working_collector.ts @@ -75,11 +75,9 @@ export const parsedWorkingCollector: ParsedUsageCollection = [ type: 'StringKeyword', }, my_index_signature_prop: { - '': { - '@@INDEX@@': { - kind: SyntaxKind.NumberKeyword, - type: 'NumberKeyword', - }, + '@@INDEX@@': { + kind: SyntaxKind.NumberKeyword, + type: 'NumberKeyword', }, }, my_objects: { diff --git a/packages/kbn-telemetry-tools/src/tools/__snapshots__/extract_collectors.test.ts.snap b/packages/kbn-telemetry-tools/src/tools/__snapshots__/extract_collectors.test.ts.snap index 68b068b0cfe06..9868a7d31d498 100644 --- a/packages/kbn-telemetry-tools/src/tools/__snapshots__/extract_collectors.test.ts.snap +++ b/packages/kbn-telemetry-tools/src/tools/__snapshots__/extract_collectors.test.ts.snap @@ -96,16 +96,14 @@ Array [ "collectorName": "indexed_interface_with_not_matching_schema", "fetch": Object { "typeDescriptor": Object { - "": Object { - "@@INDEX@@": Object { - "count_1": Object { - "kind": 143, - "type": "NumberKeyword", - }, - "count_2": Object { - "kind": 143, - "type": "NumberKeyword", - }, + "@@INDEX@@": Object { + "count_1": Object { + "kind": 143, + "type": "NumberKeyword", + }, + "count_2": Object { + "kind": 143, + "type": "NumberKeyword", }, }, }, @@ -165,11 +163,9 @@ Array [ }, }, "my_index_signature_prop": Object { - "": Object { - "@@INDEX@@": Object { - "kind": 143, - "type": "NumberKeyword", - }, + "@@INDEX@@": Object { + "kind": 143, + "type": "NumberKeyword", }, }, "my_objects": Object { diff --git a/packages/kbn-telemetry-tools/src/tools/serializer.test.ts b/packages/kbn-telemetry-tools/src/tools/serializer.test.ts index 9475574a44219..6742117226368 100644 --- a/packages/kbn-telemetry-tools/src/tools/serializer.test.ts +++ b/packages/kbn-telemetry-tools/src/tools/serializer.test.ts @@ -44,13 +44,13 @@ export function loadFixtureProgram(fixtureName: string) { } describe('getDescriptor', () => { - const usageInterfaces = new Map(); + const usageInterfaces = new Map(); let tsProgram: ts.Program; beforeAll(() => { const { program, sourceFile } = loadFixtureProgram('constants'); tsProgram = program; for (const node of traverseNodes(sourceFile)) { - if (ts.isInterfaceDeclaration(node)) { + if (ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node)) { const interfaceName = node.name.getText(); usageInterfaces.set(interfaceName, node); } @@ -102,4 +102,26 @@ describe('getDescriptor', () => { 'Mapping does not support conflicting union types.' ); }); + + it('serializes TypeAliasDeclaration', () => { + const usageInterface = usageInterfaces.get('TypeAliasWithUnion')!; + const descriptor = getDescriptor(usageInterface, tsProgram); + expect(descriptor).toEqual({ + locale: { kind: ts.SyntaxKind.StringKeyword, type: 'StringKeyword' }, + prop1: { kind: ts.SyntaxKind.StringKeyword, type: 'StringKeyword' }, + prop2: { kind: ts.SyntaxKind.StringKeyword, type: 'StringKeyword' }, + prop3: { kind: ts.SyntaxKind.StringKeyword, type: 'StringKeyword' }, + prop4: { kind: ts.SyntaxKind.StringLiteral, type: 'StringLiteral' }, + prop5: { kind: ts.SyntaxKind.FirstLiteralToken, type: 'FirstLiteralToken' }, + }); + }); + + it('serializes Record entries', () => { + const usageInterface = usageInterfaces.get('TypeAliasWithRecord')!; + const descriptor = getDescriptor(usageInterface, tsProgram); + expect(descriptor).toEqual({ + locale: { kind: ts.SyntaxKind.StringKeyword, type: 'StringKeyword' }, + '@@INDEX@@': { kind: ts.SyntaxKind.NumberKeyword, type: 'NumberKeyword' }, + }); + }); }); diff --git a/packages/kbn-telemetry-tools/src/tools/serializer.ts b/packages/kbn-telemetry-tools/src/tools/serializer.ts index 7afe828298b4b..6fe02e3824ba7 100644 --- a/packages/kbn-telemetry-tools/src/tools/serializer.ts +++ b/packages/kbn-telemetry-tools/src/tools/serializer.ts @@ -79,9 +79,13 @@ export function getDescriptor(node: ts.Node, program: ts.Program): Descriptor | } if (ts.isTypeLiteralNode(node) || ts.isInterfaceDeclaration(node)) { return node.members.reduce((acc, m) => { - acc[m.name?.getText() || ''] = getDescriptor(m, program); - return acc; - }, {} as any); + const key = m.name?.getText(); + if (key) { + return { ...acc, [key]: getDescriptor(m, program) }; + } else { + return { ...acc, ...getDescriptor(m, program) }; + } + }, {}); } // If it's defined as signature { [key: string]: OtherInterface } @@ -114,6 +118,10 @@ export function getDescriptor(node: ts.Node, program: ts.Program): Descriptor | if (symbolName === 'Date') { return { kind: TelemetryKinds.Date, type: 'Date' }; } + // Support `Record` + if (symbolName === 'Record' && node.typeArguments![0].kind === ts.SyntaxKind.StringKeyword) { + return { '@@INDEX@@': getDescriptor(node.typeArguments![1], program) }; + } const declaration = (symbol?.getDeclarations() || [])[0]; if (declaration) { return getDescriptor(declaration, program); @@ -157,6 +165,19 @@ export function getDescriptor(node: ts.Node, program: ts.Program): Descriptor | return uniqueKinds[0]; } + // Support `type MyUsageType = SomethingElse` + if (ts.isTypeAliasDeclaration(node)) { + return getDescriptor(node.type, program); + } + + // Support `&` unions + if (ts.isIntersectionTypeNode(node)) { + return node.types.reduce( + (acc, unionNode) => ({ ...acc, ...getDescriptor(unionNode, program) }), + {} + ); + } + switch (node.kind) { case ts.SyntaxKind.NumberKeyword: case ts.SyntaxKind.BooleanKeyword: diff --git a/packages/kbn-telemetry-tools/src/tools/utils.ts b/packages/kbn-telemetry-tools/src/tools/utils.ts index 3d6764117374c..e8e1b3fed1aef 100644 --- a/packages/kbn-telemetry-tools/src/tools/utils.ts +++ b/packages/kbn-telemetry-tools/src/tools/utils.ts @@ -249,7 +249,7 @@ export function difference(actual: any, expected: any) { function (result, value, key) { if (key && /@@INDEX@@/.test(`${key}`)) { // The type definition is an Index Signature, fuzzy searching for similar keys - const regexp = new RegExp(`${key}`.replace(/@@INDEX@@/g, '(.+)?')); + const regexp = new RegExp(`^${key}`.replace(/@@INDEX@@/g, '(.+)?')); const keysInBase = Object.keys(base) .map((k) => { const match = k.match(regexp); diff --git a/src/fixtures/telemetry_collectors/constants.ts b/src/fixtures/telemetry_collectors/constants.ts index 4aac9e66cdbdb..d4c9a1f85c4d7 100644 --- a/src/fixtures/telemetry_collectors/constants.ts +++ b/src/fixtures/telemetry_collectors/constants.ts @@ -51,3 +51,7 @@ export const externallyDefinedSchema: MakeSchemaFrom<{ locale: string }> = { type: 'keyword', }, }; + +export type TypeAliasWithUnion = Usage & WithUnion; + +export type TypeAliasWithRecord = Usage & Record; diff --git a/x-pack/.telemetryrc.json b/x-pack/.telemetryrc.json index 2c16491c1096b..30b2178259d68 100644 --- a/x-pack/.telemetryrc.json +++ b/x-pack/.telemetryrc.json @@ -7,7 +7,6 @@ "plugins/apm/server/lib/apm_telemetry/index.ts", "plugins/canvas/server/collectors/collector.ts", "plugins/infra/server/usage/usage_collector.ts", - "plugins/lens/server/usage/collectors.ts", "plugins/reporting/server/usage/reporting_usage_collector.ts", "plugins/maps/server/maps_telemetry/collectors/register.ts" ] diff --git a/x-pack/plugins/lens/server/usage/collectors.ts b/x-pack/plugins/lens/server/usage/collectors.ts index 3f033bd3b03d0..c32fc0371ed8a 100644 --- a/x-pack/plugins/lens/server/usage/collectors.ts +++ b/x-pack/plugins/lens/server/usage/collectors.ts @@ -10,6 +10,7 @@ import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { TaskManagerStartContract } from '../../../task_manager/server'; import { LensUsage, LensTelemetryState } from './types'; +import { lensUsageSchema } from './schema'; export function registerLensUsageCollector( usageCollection: UsageCollectionSetup, @@ -20,9 +21,9 @@ export function registerLensUsageCollector( // mark lensUsageCollector as ready to collect when the TaskManager is ready isCollectorReady = true; }); - const lensUsageCollector = usageCollection.makeUsageCollector({ + const lensUsageCollector = usageCollection.makeUsageCollector({ type: 'lens', - fetch: async (): Promise => { + async fetch() { try { const docs = await getLatestTaskState(await taskManager); // get the accumulated state from the recurring task @@ -55,6 +56,7 @@ export function registerLensUsageCollector( } }, isReady: () => isCollectorReady, + schema: lensUsageSchema, }); usageCollection.registerCollector(lensUsageCollector); diff --git a/x-pack/plugins/lens/server/usage/schema.ts b/x-pack/plugins/lens/server/usage/schema.ts new file mode 100644 index 0000000000000..a35d4d91845ee --- /dev/null +++ b/x-pack/plugins/lens/server/usage/schema.ts @@ -0,0 +1,83 @@ +/* + * 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 { MakeSchemaFrom } from 'src/plugins/usage_collection/server'; +import { LensUsage } from './types'; + +const eventsSchema: MakeSchemaFrom = { + app_query_change: { type: 'long' }, + indexpattern_field_info_click: { type: 'long' }, + loaded: { type: 'long' }, + app_filters_updated: { type: 'long' }, + app_date_change: { type: 'long' }, + save_failed: { type: 'long' }, + loaded_404: { type: 'long' }, + drop_total: { type: 'long' }, + chart_switch: { type: 'long' }, + suggestion_confirmed: { type: 'long' }, + suggestion_clicked: { type: 'long' }, + drop_onto_workspace: { type: 'long' }, + drop_non_empty: { type: 'long' }, + drop_empty: { type: 'long' }, + indexpattern_changed: { type: 'long' }, + indexpattern_filters_cleared: { type: 'long' }, + indexpattern_type_filter_toggled: { type: 'long' }, + indexpattern_existence_toggled: { type: 'long' }, + indexpattern_show_all_fields_clicked: { type: 'long' }, + drop_onto_dimension: { type: 'long' }, + indexpattern_dimension_removed: { type: 'long' }, + indexpattern_dimension_field_changed: { type: 'long' }, + xy_change_layer_display: { type: 'long' }, + xy_layer_removed: { type: 'long' }, + xy_layer_added: { type: 'long' }, + indexpattern_dimension_operation_terms: { type: 'long' }, + indexpattern_dimension_operation_date_histogram: { type: 'long' }, + indexpattern_dimension_operation_avg: { type: 'long' }, + indexpattern_dimension_operation_min: { type: 'long' }, + indexpattern_dimension_operation_max: { type: 'long' }, + indexpattern_dimension_operation_sum: { type: 'long' }, + indexpattern_dimension_operation_count: { type: 'long' }, + indexpattern_dimension_operation_cardinality: { type: 'long' }, + indexpattern_dimension_operation_filters: { type: 'long' }, +}; + +const suggestionEventsSchema: MakeSchemaFrom = { + back_to_current: { type: 'long' }, + reload: { type: 'long' }, +}; + +const savedSchema: MakeSchemaFrom = { + bar: { type: 'long' }, + bar_horizontal: { type: 'long' }, + line: { type: 'long' }, + area: { type: 'long' }, + bar_stacked: { type: 'long' }, + bar_percentage_stacked: { type: 'long' }, + bar_horizontal_stacked: { type: 'long' }, + bar_horizontal_percentage_stacked: { type: 'long' }, + area_stacked: { type: 'long' }, + area_percentage_stacked: { type: 'long' }, + lnsDatatable: { type: 'long' }, + lnsPie: { type: 'long' }, + lnsMetric: { type: 'long' }, +}; + +export const lensUsageSchema: MakeSchemaFrom = { + // LensClickUsage + events_30_days: eventsSchema, + events_90_days: eventsSchema, + suggestion_events_30_days: suggestionEventsSchema, + suggestion_events_90_days: suggestionEventsSchema, + + // LensVisualizationUsage + saved_overall_total: { type: 'long' }, + saved_30_days_total: { type: 'long' }, + saved_90_days_total: { type: 'long' }, + + saved_overall: savedSchema, + saved_30_days: savedSchema, + saved_90_days: savedSchema, +}; diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 904b14a7459ad..86b7889957c9f 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -155,6 +155,380 @@ } } }, + "lens": { + "properties": { + "events_30_days": { + "properties": { + "app_query_change": { + "type": "long" + }, + "indexpattern_field_info_click": { + "type": "long" + }, + "loaded": { + "type": "long" + }, + "app_filters_updated": { + "type": "long" + }, + "app_date_change": { + "type": "long" + }, + "save_failed": { + "type": "long" + }, + "loaded_404": { + "type": "long" + }, + "drop_total": { + "type": "long" + }, + "chart_switch": { + "type": "long" + }, + "suggestion_confirmed": { + "type": "long" + }, + "suggestion_clicked": { + "type": "long" + }, + "drop_onto_workspace": { + "type": "long" + }, + "drop_non_empty": { + "type": "long" + }, + "drop_empty": { + "type": "long" + }, + "indexpattern_changed": { + "type": "long" + }, + "indexpattern_filters_cleared": { + "type": "long" + }, + "indexpattern_type_filter_toggled": { + "type": "long" + }, + "indexpattern_existence_toggled": { + "type": "long" + }, + "indexpattern_show_all_fields_clicked": { + "type": "long" + }, + "drop_onto_dimension": { + "type": "long" + }, + "indexpattern_dimension_removed": { + "type": "long" + }, + "indexpattern_dimension_field_changed": { + "type": "long" + }, + "xy_change_layer_display": { + "type": "long" + }, + "xy_layer_removed": { + "type": "long" + }, + "xy_layer_added": { + "type": "long" + }, + "indexpattern_dimension_operation_terms": { + "type": "long" + }, + "indexpattern_dimension_operation_date_histogram": { + "type": "long" + }, + "indexpattern_dimension_operation_avg": { + "type": "long" + }, + "indexpattern_dimension_operation_min": { + "type": "long" + }, + "indexpattern_dimension_operation_max": { + "type": "long" + }, + "indexpattern_dimension_operation_sum": { + "type": "long" + }, + "indexpattern_dimension_operation_count": { + "type": "long" + }, + "indexpattern_dimension_operation_cardinality": { + "type": "long" + }, + "indexpattern_dimension_operation_filters": { + "type": "long" + } + } + }, + "events_90_days": { + "properties": { + "app_query_change": { + "type": "long" + }, + "indexpattern_field_info_click": { + "type": "long" + }, + "loaded": { + "type": "long" + }, + "app_filters_updated": { + "type": "long" + }, + "app_date_change": { + "type": "long" + }, + "save_failed": { + "type": "long" + }, + "loaded_404": { + "type": "long" + }, + "drop_total": { + "type": "long" + }, + "chart_switch": { + "type": "long" + }, + "suggestion_confirmed": { + "type": "long" + }, + "suggestion_clicked": { + "type": "long" + }, + "drop_onto_workspace": { + "type": "long" + }, + "drop_non_empty": { + "type": "long" + }, + "drop_empty": { + "type": "long" + }, + "indexpattern_changed": { + "type": "long" + }, + "indexpattern_filters_cleared": { + "type": "long" + }, + "indexpattern_type_filter_toggled": { + "type": "long" + }, + "indexpattern_existence_toggled": { + "type": "long" + }, + "indexpattern_show_all_fields_clicked": { + "type": "long" + }, + "drop_onto_dimension": { + "type": "long" + }, + "indexpattern_dimension_removed": { + "type": "long" + }, + "indexpattern_dimension_field_changed": { + "type": "long" + }, + "xy_change_layer_display": { + "type": "long" + }, + "xy_layer_removed": { + "type": "long" + }, + "xy_layer_added": { + "type": "long" + }, + "indexpattern_dimension_operation_terms": { + "type": "long" + }, + "indexpattern_dimension_operation_date_histogram": { + "type": "long" + }, + "indexpattern_dimension_operation_avg": { + "type": "long" + }, + "indexpattern_dimension_operation_min": { + "type": "long" + }, + "indexpattern_dimension_operation_max": { + "type": "long" + }, + "indexpattern_dimension_operation_sum": { + "type": "long" + }, + "indexpattern_dimension_operation_count": { + "type": "long" + }, + "indexpattern_dimension_operation_cardinality": { + "type": "long" + }, + "indexpattern_dimension_operation_filters": { + "type": "long" + } + } + }, + "suggestion_events_30_days": { + "properties": { + "back_to_current": { + "type": "long" + }, + "reload": { + "type": "long" + } + } + }, + "suggestion_events_90_days": { + "properties": { + "back_to_current": { + "type": "long" + }, + "reload": { + "type": "long" + } + } + }, + "saved_overall_total": { + "type": "long" + }, + "saved_30_days_total": { + "type": "long" + }, + "saved_90_days_total": { + "type": "long" + }, + "saved_overall": { + "properties": { + "bar": { + "type": "long" + }, + "bar_horizontal": { + "type": "long" + }, + "line": { + "type": "long" + }, + "area": { + "type": "long" + }, + "bar_stacked": { + "type": "long" + }, + "bar_percentage_stacked": { + "type": "long" + }, + "bar_horizontal_stacked": { + "type": "long" + }, + "bar_horizontal_percentage_stacked": { + "type": "long" + }, + "area_stacked": { + "type": "long" + }, + "area_percentage_stacked": { + "type": "long" + }, + "lnsDatatable": { + "type": "long" + }, + "lnsPie": { + "type": "long" + }, + "lnsMetric": { + "type": "long" + } + } + }, + "saved_30_days": { + "properties": { + "bar": { + "type": "long" + }, + "bar_horizontal": { + "type": "long" + }, + "line": { + "type": "long" + }, + "area": { + "type": "long" + }, + "bar_stacked": { + "type": "long" + }, + "bar_percentage_stacked": { + "type": "long" + }, + "bar_horizontal_stacked": { + "type": "long" + }, + "bar_horizontal_percentage_stacked": { + "type": "long" + }, + "area_stacked": { + "type": "long" + }, + "area_percentage_stacked": { + "type": "long" + }, + "lnsDatatable": { + "type": "long" + }, + "lnsPie": { + "type": "long" + }, + "lnsMetric": { + "type": "long" + } + } + }, + "saved_90_days": { + "properties": { + "bar": { + "type": "long" + }, + "bar_horizontal": { + "type": "long" + }, + "line": { + "type": "long" + }, + "area": { + "type": "long" + }, + "bar_stacked": { + "type": "long" + }, + "bar_percentage_stacked": { + "type": "long" + }, + "bar_horizontal_stacked": { + "type": "long" + }, + "bar_horizontal_percentage_stacked": { + "type": "long" + }, + "area_stacked": { + "type": "long" + }, + "area_percentage_stacked": { + "type": "long" + }, + "lnsDatatable": { + "type": "long" + }, + "lnsPie": { + "type": "long" + }, + "lnsMetric": { + "type": "long" + } + } + } + } + }, "mlTelemetry": { "properties": { "file_data_visualizer": {