Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Telemetry] Collector Schema #64942

Merged
merged 38 commits into from
Jun 26, 2020
Merged
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
86563ce
first working draft
Bamieh Apr 30, 2020
e80f27f
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh Apr 30, 2020
a870296
first working draft
Bamieh Apr 30, 2020
80b3257
add more test scenarios
Bamieh May 4, 2020
adb1bea
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh May 4, 2020
9f68343
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh May 6, 2020
b4dfeb8
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh May 11, 2020
babf185
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh May 17, 2020
1dbee95
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh May 23, 2020
16ed263
finalize initial implementation
Bamieh May 26, 2020
e580992
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh May 26, 2020
c452ab4
running typechecker
Bamieh May 26, 2020
ddc5f12
add telemetry cli checker - phase 1
Bamieh May 26, 2020
fa81c2a
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh May 27, 2020
a3fad35
xpack .telemetryrc file
Bamieh Jun 1, 2020
e2795af
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh Jun 1, 2020
1c3e112
code review changes
Bamieh Jun 12, 2020
34444f2
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh Jun 12, 2020
a924d65
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh Jun 12, 2020
526d132
reporting usage
Bamieh Jun 14, 2020
b5c50d7
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh Jun 14, 2020
b95a431
ready for review
Bamieh Jun 15, 2020
0e879d6
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh Jun 15, 2020
fd2086e
self code review
Bamieh Jun 15, 2020
23d087a
fix typecheck
Bamieh Jun 15, 2020
f957e67
fix some more schemas
Bamieh Jun 15, 2020
902f5ff
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh Jun 15, 2020
e04a074
move into a pacakge
Bamieh Jun 18, 2020
71dc5b1
merge master
Bamieh Jun 18, 2020
9afad1a
Merge branch 'master' into telemetry/automate_mapping
elasticmachine Jun 18, 2020
f1f4146
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh Jun 24, 2020
3c360f0
add CI job and complete code review suggestions
Bamieh Jun 24, 2020
3ecf97e
fix typecheck
Bamieh Jun 24, 2020
bf590ee
fix package tests
Bamieh Jun 24, 2020
32664b9
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh Jun 24, 2020
1fd4625
revert to maps-telemetry
Bamieh Jun 25, 2020
f5bd5f1
Merge branch 'master' of github.com:elastic/kibana into telemetry/aut…
Bamieh Jun 25, 2020
bac4718
revert to maps
Bamieh Jun 25, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
running typechecker
Bamieh committed May 26, 2020

Unverified

This user has not yet uploaded their public signing key.
commit c452ab4df789064909487949170831adab7b7711
9 changes: 2 additions & 7 deletions src/dev/run_telemetry_extract.ts
Original file line number Diff line number Diff line change
@@ -17,12 +17,9 @@
* under the License.
*/

import chalk from 'chalk';
import Listr from 'listr';
import { resolve } from 'path';
import { run } from '@kbn/dev-utils';

import { createFailError, run } from '@kbn/dev-utils';
// import { ErrorReporter, serializeToJson, serializeToJson5, writeFileAsync } from './telemetry';
import {
createTaskContext,
ErrorReporter,
@@ -33,9 +30,7 @@ import {
} from './telemetry/tasks';

run(
async ({ flags: { 'output-format': outputFormat }, log }) => {
// const srcPaths = Array().concat(path || ['./src', './x-pack']);

async ({ flags: {}, log }) => {
const list = new Listr([
{
title: 'Parsing .telemetryrc.json files',
7 changes: 4 additions & 3 deletions src/dev/telemetry/__fixture__/externally_defined_collector.ts
Original file line number Diff line number Diff line change
@@ -17,9 +17,10 @@
* under the License.
*/
import { CollectorSet } from '../../../plugins/usage_collection/server/collector';
import { loggingServiceMock } from '../../../core/server/mocks';

const collectorSet = new CollectorSet({
logger: null,
logger: loggingServiceMock.createLogger(),
maximumWaitTimeForAllCollectorsInS: 0,
});

@@ -38,7 +39,7 @@ function createCollector() {
},
mapping: {
locale: {
type: 'keyword',
type: 'keyword' as 'keyword',
},
},
};
@@ -55,7 +56,7 @@ export function defineCollectorFromVariable() {
},
mapping: {
locale: {
type: 'keyword',
type: 'keyword' as 'keyword',
},
},
};
6 changes: 4 additions & 2 deletions src/dev/telemetry/__fixture__/nested_collector.ts
Original file line number Diff line number Diff line change
@@ -17,9 +17,10 @@
* under the License.
*/
import { CollectorSet, UsageCollector } from '../../../plugins/usage_collection/server/collector';
import { loggingServiceMock } from '../../../core/server/mocks';

const collectorSet = new CollectorSet({
logger: null,
logger: loggingServiceMock.createLogger(),
maximumWaitTimeForAllCollectorsInS: 0,
});

@@ -28,10 +29,11 @@ interface Usage {
}

export class NestedInside {
collector?: UsageCollector<Usage>;
collector?: UsageCollector<Usage, Usage>;
createMyCollector() {
this.collector = collectorSet.makeUsageCollector<Usage>({
type: 'my_nested_collector',
isReady: () => true,
fetch: async () => {
return {
locale: 'en',
3 changes: 2 additions & 1 deletion src/dev/telemetry/__fixture__/unmapped_collector.ts
Original file line number Diff line number Diff line change
@@ -17,9 +17,10 @@
* under the License.
*/
import { CollectorSet } from '../../../plugins/usage_collection/server/collector';
import { loggingServiceMock } from '../../../core/server/mocks';

const { makeUsageCollector } = new CollectorSet({
logger: null,
logger: loggingServiceMock.createLogger(),
maximumWaitTimeForAllCollectorsInS: 0,
});

5 changes: 2 additions & 3 deletions src/dev/telemetry/__fixture__/working_collector.ts
Original file line number Diff line number Diff line change
@@ -16,12 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/

// https://ts-ast-viewer.com/
import { CollectorSet } from '../../../plugins/usage_collection/server/collector';
import { loggingServiceMock } from '../../../core/server/mocks';

const { makeUsageCollector } = new CollectorSet({
logger: null,
logger: loggingServiceMock.createLogger(),
maximumWaitTimeForAllCollectorsInS: 0,
});

33 changes: 15 additions & 18 deletions src/dev/telemetry/check_collector__integrity.test.ts
Original file line number Diff line number Diff line change
@@ -17,15 +17,11 @@
* under the License.
*/

import esMapping from './__fixture__/mock_mapping.json';
import { parsedWorkingCollector } from './__fixture__/parsed_working_collector';
import {
checkCollectorIntegrity,
checkCompatibleTypeDescriptor,
checkMatchingMapping,
} from './check_collector_integrity';
import * as _ from 'lodash';
import * as ts from 'typescript';
import esMapping from './__fixture__/mock_mapping.json';
import { parsedWorkingCollector } from './__fixture__/parsed_working_collector';
import { checkCompatibleTypeDescriptor, checkMatchingMapping } from './check_collector_integrity';

describe('checkMatchingMapping', () => {
it('returns no diff on matching parsedCollections and stored mapping', () => {
@@ -70,7 +66,9 @@ describe('checkMatchingMapping', () => {

describe('checkCompatibleTypeDescriptor', () => {
it('returns no diff on compatible type descriptor with mapping', () => {
const { diff, message } = checkCompatibleTypeDescriptor([parsedWorkingCollector]);
const incompatibles = checkCompatibleTypeDescriptor([parsedWorkingCollector]);
expect(incompatibles).toHaveLength(1);
const { diff, message } = incompatibles[0];
expect(diff).toEqual({});
expect(message).toHaveLength(0);
});
@@ -79,7 +77,9 @@ describe('checkCompatibleTypeDescriptor', () => {
it('returns diff on incompatible type descriptor with mapping', () => {
const malformedParsedCollector = _.cloneDeep(parsedWorkingCollector);
malformedParsedCollector[1].fetch.typeDescriptor.flat.kind = ts.SyntaxKind.BooleanKeyword;
const { diff, message } = checkCompatibleTypeDescriptor([malformedParsedCollector]);
const incompatibles = checkCompatibleTypeDescriptor([malformedParsedCollector]);
expect(incompatibles).toHaveLength(1);
const { diff, message } = incompatibles[0];
expect(diff).toEqual({ 'flat.kind': ts.SyntaxKind.BooleanKeyword });
expect(message).toHaveLength(1);
expect(message).toEqual([
@@ -94,15 +94,19 @@ describe('checkCompatibleTypeDescriptor', () => {
it('returns no diff when mapping change between text and keyword', () => {
const malformedParsedCollector = _.cloneDeep(parsedWorkingCollector);
malformedParsedCollector[1].mapping.value.flat.type = 'text';
const { diff, message } = checkCompatibleTypeDescriptor([malformedParsedCollector]);
const incompatibles = checkCompatibleTypeDescriptor([malformedParsedCollector]);
expect(incompatibles).toHaveLength(1);
const { diff, message } = incompatibles[0];
expect(diff).toEqual({});
expect(message).toHaveLength(0);
});

it('returns diff on incompatible type descriptor with mapping', () => {
const malformedParsedCollector = _.cloneDeep(parsedWorkingCollector);
malformedParsedCollector[1].mapping.value.flat.type = 'boolean';
const { diff, message } = checkCompatibleTypeDescriptor([malformedParsedCollector]);
const incompatibles = checkCompatibleTypeDescriptor([malformedParsedCollector]);
expect(incompatibles).toHaveLength(1);
const { diff, message } = incompatibles[0];
expect(diff).toEqual({ 'flat.kind': ts.SyntaxKind.StringKeyword });
expect(message).toHaveLength(1);
expect(message).toEqual([
@@ -113,10 +117,3 @@ describe('checkCompatibleTypeDescriptor', () => {
it.todo('returns diff when missing mapping');
});
});

// describe('checkCollectorIntegrity', () => {
// it('checks file integrity', () => {
// const result = checkCollectorIntegrity([parsedWorkingCollector], esMapping);
// console.log('result::', result)
// })
// })
12 changes: 6 additions & 6 deletions src/dev/telemetry/check_collector_integrity.ts
Original file line number Diff line number Diff line change
@@ -28,34 +28,34 @@ export function checkMatchingMapping(UsageCollections: ParsedUsageCollection[],
return difference(generatedMapping, esMapping);
}

export function checkCompatibleTypeDescriptor(UsageCollections: ParsedUsageCollection[]) {
for (const [, collectorDetails] of UsageCollections) {
export function checkCompatibleTypeDescriptor(usageCollections: ParsedUsageCollection[]) {
return usageCollections.map(([, collectorDetails]) => {
const typeDescriptorKinds = flattenKeys(
pickDeep(collectorDetails.fetch.typeDescriptor, 'kind')
);
const mappingTypes = flattenKeys(pickDeep(collectorDetails.mapping.value, 'type'));

const transformedMappingKinds = _.reduce(
mappingTypes,
(acc, type, key) => {
(acc: any, type: string, key: string) => {
acc[key.replace('.type', '.kind')] = getMappingTypeToKind(type);
return acc;
},
{} as any
);

const diff = difference(typeDescriptorKinds, transformedMappingKinds);
const diff: any[] = difference(typeDescriptorKinds, transformedMappingKinds);

return {
diff,
message: Object.entries(diff).map(([key, kind]) => {
message: Object.entries(diff).map(([key]) => {
const interfaceKey = key.replace('.kind', '');
const expectedDescriptorType = kindToDescriptorName(_.get(transformedMappingKinds, key));
const actualDescriptorType = kindToDescriptorName(_.get(typeDescriptorKinds, key));
return `incompatible Type key (${collectorDetails.fetch.typeName}.${interfaceKey}): expected (${expectedDescriptorType}) got (${actualDescriptorType}).`;
}),
};
}
});
}

export function checkCollectorIntegrity(UsageCollections: ParsedUsageCollection[], esMapping: any) {
3 changes: 3 additions & 0 deletions src/dev/telemetry/tasks/generate_mappings_task.ts
Original file line number Diff line number Diff line change
@@ -24,6 +24,9 @@ import { generateMapping } from '../manage_mapping';
export function generateMappingsTask({ roots }: TaskContext) {
return roots.map((root) => ({
task: () => {
if (!root.parsedCollections || !root.parsedCollections.length) {
return;
}
const mapping = generateMapping(root.parsedCollections);
root.mapping = mapping;
},
4 changes: 2 additions & 2 deletions src/dev/telemetry/tasks/task_context.ts
Original file line number Diff line number Diff line change
@@ -22,8 +22,8 @@ import { ErrorReporter } from './error_reporter';
import { ParsedUsageCollection } from '../ts_parser';
export interface TelemetryRoot {
config: TelemetryRC;
parsedCollections: ParsedUsageCollection[];
mapping: any;
parsedCollections?: ParsedUsageCollection[];
mapping?: any;
}

export interface TaskContext {
9 changes: 3 additions & 6 deletions src/dev/telemetry/tasks/write_to_file_task.ts
Original file line number Diff line number Diff line change
@@ -18,18 +18,15 @@
*/

import * as path from 'path';
import { ErrorReporter, serializeToJson, serializeToJson5, writeFileAsync } from '../utils';

import { writeFileAsync } from '../utils';
import { TaskContext } from './task_context';
import { generateMapping } from '../manage_mapping';

export function writeToFileTask({ roots }: TaskContext) {
return roots.map((root) => ({
task: async () => {
const fullPath = path.resolve(process.cwd(), root.config.output);
const mapping = generateMapping(root.parsedCollections);
if (Object.keys(mapping.properties).length > 0) {
const serializedMapping = JSON.stringify(mapping, null, 2).concat('\n');
if (root.mapping && Object.keys(root.mapping.properties).length > 0) {
const serializedMapping = JSON.stringify(root.mapping, null, 2).concat('\n');
await writeFileAsync(fullPath, serializedMapping);
}
},
8 changes: 4 additions & 4 deletions src/dev/telemetry/utils.ts
Original file line number Diff line number Diff line change
@@ -97,13 +97,13 @@ export function pickDeep(collection: any, identity: any, thisArg?: any) {
return picked;
}

export const flattenKeys = (obj: any, keyPath = []) => {
export const flattenKeys = (obj: any, keyPath: any[] = []): any => {
if (_.isObject(obj)) {
return _.reduce(
obj,
(cum, next, key) => {
const keys = [...keyPath, key];
return _.merge(cum, flattenKeys(next, keys as any));
return _.merge(cum, flattenKeys(next, keys));
},
{}
);
@@ -112,9 +112,9 @@ export const flattenKeys = (obj: any, keyPath = []) => {
};

export function difference(actual: any, expected: any) {
function changes(obj, base) {
function changes(obj: any, base: any) {
return _.transform(obj, function (result, value, key) {
if (!_.isEqual(value, base[key])) {
if (key && !_.isEqual(value, base[key])) {
result[key] =
_.isObject(value) && _.isObject(base[key]) ? changes(value, base[key]) : value;
}
Original file line number Diff line number Diff line change
@@ -45,13 +45,13 @@ export function createCspCollector(server: Server) {
},
mapping: {
strict: {
type: 'boolean',
type: 'boolean' as 'boolean',
},
warnLegacyBrowsers: {
type: 'boolean',
type: 'boolean' as 'boolean',
},
rulesChangedFromDefault: {
type: 'boolean',
type: 'boolean' as 'boolean',
},
},
};
Original file line number Diff line number Diff line change
@@ -23,7 +23,6 @@ import {
SavedObjectsServiceSetup,
} from 'kibana/server';
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
import { UI_METRIC_USAGE_TYPE } from '../../../common/constants';
import { findAll } from '../find_all';

interface UIMetricsSavedObjects extends SavedObjectAttributes {
2 changes: 1 addition & 1 deletion src/plugins/usage_collection/server/collector/collector.ts
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ import { Logger, APICaller } from 'kibana/server';

export type CollectorFormatForBulkUpload<T, U> = (result: T) => { type: string; payload: U };

type AllowedMappingTypes = 'keyword' | 'text' | 'number';
type AllowedMappingTypes = 'keyword' | 'text' | 'number' | 'boolean';

type Purify<T extends string> = { [P in T]: T }[T];