Skip to content

Commit

Permalink
[Reporting] Improve TS and update Reporting usage data model (elastic…
Browse files Browse the repository at this point in the history
…#64841)

* Stricter types for Reporting Usage data

* Allow more type inference

* remove lastDay filter

* update ts and add test

* fix tests

* fix test

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
tsullivan and elasticmachine committed May 4, 2020
1 parent 90a4a5e commit 4c78a3d
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 174 deletions.

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

0 comments on commit 4c78a3d

Please sign in to comment.