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

[Reporting] Improve TS and update Reporting usage data model #64841

Merged
merged 10 commits into from
May 4, 2020

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

87 changes: 41 additions & 46 deletions x-pack/legacy/plugins/reporting/server/usage/get_reporting_usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ import {
JobTypes,
KeyCountBucket,
RangeStats,
ReportingUsageType,
SearchResponse,
StatusByAppBucket,
AppCounts,
LayoutCounts,
} from './types';

type XPackInfo = XPackMainPlugin['info'];
Expand All @@ -36,8 +39,11 @@ const DEFAULT_TERMS_SIZE = 10;
const PRINTABLE_PDF_JOBTYPE = 'printable_pdf';

// indexes some key/count buckets by the "key" property
const getKeyCount = (buckets: KeyCountBucket[]): { [key: string]: number } =>
buckets.reduce((accum, { key, doc_count: count }) => ({ ...accum, [key]: count }), {});
const getKeyCount = <BucketType>(buckets: KeyCountBucket[]): BucketType =>
buckets.reduce(
(accum, { key, doc_count: count }) => ({ ...accum, [key]: count }),
{} as BucketType
);

// indexes some key/count buckets by statusType > jobType > appName: statusCount
const getAppStatuses = (buckets: StatusByAppBucket[]) =>
Expand All @@ -58,7 +64,7 @@ const getAppStatuses = (buckets: StatusByAppBucket[]) =>
};
}, {});

function getAggStats(aggs: AggregationResultBuckets): RangeStats {
function getAggStats(aggs: AggregationResultBuckets): Partial<RangeStats> {
const { buckets: jobBuckets } = aggs[JOB_TYPES_KEY];
const jobTypes = jobBuckets.reduce(
(accum: JobTypes, { key, doc_count: count }: { key: string; doc_count: number }) => {
Expand All @@ -72,17 +78,11 @@ function getAggStats(aggs: AggregationResultBuckets): RangeStats {
if (pdfJobs) {
const pdfAppBuckets = get<KeyCountBucket[]>(aggs[OBJECT_TYPES_KEY], '.pdf.buckets', []);
const pdfLayoutBuckets = get<KeyCountBucket[]>(aggs[LAYOUT_TYPES_KEY], '.pdf.buckets', []);
pdfJobs.app = getKeyCount(pdfAppBuckets) as {
visualization: number;
dashboard: number;
};
pdfJobs.layout = getKeyCount(pdfLayoutBuckets) as {
print: number;
preserve_layout: number;
};
pdfJobs.app = getKeyCount<AppCounts>(pdfAppBuckets);
pdfJobs.layout = getKeyCount<LayoutCounts>(pdfLayoutBuckets);
}

const all = aggs.doc_count as number;
const all = aggs.doc_count;
let statusTypes = {};
const statusBuckets = get<KeyCountBucket[]>(aggs[STATUS_TYPES_KEY], 'buckets', []);
if (statusBuckets) {
Expand All @@ -100,27 +100,22 @@ function getAggStats(aggs: AggregationResultBuckets): RangeStats {

type SearchAggregation = SearchResponse['aggregations']['ranges']['buckets'];

type RangeStatSets = Partial<
RangeStats & {
lastDay: RangeStats;
last7Days: RangeStats;
}
>;
type RangeStatSets = Partial<RangeStats> & {
last7Days: Partial<RangeStats>;
};

async function handleResponse(response: SearchResponse): Promise<RangeStatSets> {
async function handleResponse(response: SearchResponse): Promise<Partial<RangeStatSets>> {
const buckets = get<SearchAggregation>(response, 'aggregations.ranges.buckets');
if (!buckets) {
return {};
}
const { lastDay, last7Days, all } = buckets;
const { last7Days, all } = buckets;

const lastDayUsage = lastDay ? getAggStats(lastDay) : ({} as RangeStats);
const last7DaysUsage = last7Days ? getAggStats(last7Days) : ({} as RangeStats);
const allUsage = all ? getAggStats(all) : ({} as RangeStats);
const last7DaysUsage = last7Days ? getAggStats(last7Days) : {};
const allUsage = all ? getAggStats(all) : {};

return {
last7Days: last7DaysUsage,
lastDay: lastDayUsage,
...allUsage,
};
}
Expand All @@ -143,7 +138,6 @@ export async function getReportingUsage(
filters: {
filters: {
all: { match_all: {} },
lastDay: { range: { created_at: { gte: 'now-1d/d' } } },
last7Days: { range: { created_at: { gte: 'now-7d/d' } } },
},
},
Expand Down Expand Up @@ -177,25 +171,26 @@ export async function getReportingUsage(

return callCluster('search', params)
.then((response: SearchResponse) => handleResponse(response))
.then((usage: RangeStatSets) => {
// Allow this to explicitly throw an exception if/when this config is deprecated,
// because we shouldn't collect browserType in that case!
const browserType = config.get('capture', 'browser', 'type');

const exportTypesHandler = getExportTypesHandler(exportTypesRegistry);
const availability = exportTypesHandler.getAvailability(
xpackMainInfo
) as FeatureAvailabilityMap;

const { lastDay, last7Days, ...all } = usage;

return {
available: true,
browser_type: browserType,
enabled: true,
lastDay: decorateRangeStats(lastDay, availability),
last7Days: decorateRangeStats(last7Days, availability),
...decorateRangeStats(all, availability),
};
});
.then(
(usage: Partial<RangeStatSets>): ReportingUsageType => {
// Allow this to explicitly throw an exception if/when this config is deprecated,
// because we shouldn't collect browserType in that case!
const browserType = config.get('capture', 'browser', 'type');

const exportTypesHandler = getExportTypesHandler(exportTypesRegistry);
const availability = exportTypesHandler.getAvailability(
xpackMainInfo
) as FeatureAvailabilityMap;

const { last7Days, ...all } = usage;

return {
available: true,
browser_type: browserType,
enabled: true,
last7Days: decorateRangeStats(last7Days, availability),
...decorateRangeStats(all, availability),
};
}
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
getReportingUsageCollector,
} from './reporting_usage_collector';
import { ReportingConfig } from '../types';
import { SearchResponse } from './types';
import { SearchResponse, ReportingUsageType } from './types';

const exportTypesRegistry = getExportTypesRegistry();

Expand Down Expand Up @@ -345,6 +345,111 @@ describe('data modeling', () => {
const usageStats = await fetch(callClusterMock as any);
expect(usageStats).toMatchSnapshot();
});

test('Cast various example data to the TypeScript definition', () => {
const check = (obj: ReportingUsageType) => {
return typeof obj;
};

// just check that the example objects can be cast to ReportingUsageType
check({
PNG: { available: true, total: 7 },
_all: 21,
available: true,
browser_type: 'chromium',
csv: { available: true, total: 4 },
enabled: true,
last7Days: {
PNG: { available: true, total: 0 },
_all: 0,
csv: { available: true, total: 0 },
printable_pdf: {
app: { dashboard: 0, visualization: 0 },
available: true,
layout: { preserve_layout: 0, print: 0 },
total: 0,
},
status: { completed: 0, failed: 0 },
statuses: {},
},
printable_pdf: {
app: { 'canvas workpad': 3, dashboard: 3, visualization: 4 },
available: true,
layout: { preserve_layout: 7, print: 3 },
total: 10,
},
status: { completed: 21, failed: 0 },
statuses: {
completed: {
PNG: { dashboard: 3, visualization: 4 },
csv: {},
printable_pdf: { 'canvas workpad': 3, dashboard: 3, visualization: 4 },
},
},
});
check({
PNG: { available: true, total: 3 },
_all: 4,
available: true,
browser_type: 'chromium',
csv: { available: true, total: 0 },
enabled: true,
last7Days: {
PNG: { available: true, total: 3 },
_all: 4,
csv: { available: true, total: 0 },
printable_pdf: {
app: { 'canvas workpad': 1, dashboard: 0, visualization: 0 },
available: true,
layout: { preserve_layout: 1, print: 0 },
total: 1,
},
status: { completed: 4, failed: 0 },
statuses: {
completed: { PNG: { visualization: 3 }, printable_pdf: { 'canvas workpad': 1 } },
},
},
printable_pdf: {
app: { 'canvas workpad': 1, dashboard: 0, visualization: 0 },
available: true,
layout: { preserve_layout: 1, print: 0 },
total: 1,
},
status: { completed: 4, failed: 0 },
statuses: {
completed: { PNG: { visualization: 3 }, printable_pdf: { 'canvas workpad': 1 } },
},
});
check({
available: true,
browser_type: 'chromium',
enabled: true,
last7Days: {
_all: 0,
status: { completed: 0, failed: 0 },
statuses: {},
printable_pdf: {
available: true,
total: 0,
app: { dashboard: 0, visualization: 0 },
layout: { preserve_layout: 0, print: 0 },
},
csv: { available: true, total: 0 },
PNG: { available: true, total: 0 },
},
_all: 0,
status: { completed: 0, failed: 0 },
statuses: {},
printable_pdf: {
available: true,
total: 0,
app: { dashboard: 0, visualization: 0 },
layout: { preserve_layout: 0, print: 0 },
},
csv: { available: true, total: 0 },
PNG: { available: true, total: 0 },
});
});
});

describe('Ready for collection observable', () => {
Expand Down
Loading
Loading