[Telemetry] collect number of visualization saved in the past 7, 30 and 90 days (#67865)
* Update telemetry for visualizations to also count the vis from the past 30 and 90 days * Also add metrics for the saved visualizations for the past 7 days Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
e66eaf74fd
commit
fcab9745e0
5 changed files with 127 additions and 14 deletions
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* 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 moment from 'moment';
|
||||
import { getPastDays } from './get_past_days';
|
||||
|
||||
describe('getPastDays', () => {
|
||||
test('Returns 2 days that have passed from the current date', () => {
|
||||
const pastDate = moment().subtract(2, 'days').startOf('day').toString();
|
||||
|
||||
expect(getPastDays(pastDate)).toEqual(2);
|
||||
});
|
||||
|
||||
test('Returns 30 days that have passed from the current date', () => {
|
||||
const pastDate = moment().subtract(30, 'days').startOf('day').toString();
|
||||
|
||||
expect(getPastDays(pastDate)).toEqual(30);
|
||||
});
|
||||
});
|
11
x-pack/plugins/oss_telemetry/server/lib/get_past_days.ts
Normal file
11
x-pack/plugins/oss_telemetry/server/lib/get_past_days.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
export const getPastDays = (dateString: string): number => {
|
||||
const date = new Date(dateString);
|
||||
const today = new Date();
|
||||
const diff = Math.abs(date.getTime() - today.getTime());
|
||||
return Math.trunc(diff / (1000 * 60 * 60 * 24));
|
||||
};
|
|
@ -13,6 +13,7 @@ import {
|
|||
import { visualizationsTaskRunner } from './task_runner';
|
||||
import { TaskInstance } from '../../../../../task_manager/server';
|
||||
import { getNextMidnight } from '../../get_next_midnight';
|
||||
import moment from 'moment';
|
||||
|
||||
describe('visualizationsTaskRunner', () => {
|
||||
let mockTaskInstance: TaskInstance;
|
||||
|
@ -55,6 +56,9 @@ describe('visualizationsTaskRunner', () => {
|
|||
spaces_max: 1,
|
||||
spaces_min: 1,
|
||||
total: 1,
|
||||
saved_7_days_total: 1,
|
||||
saved_30_days_total: 1,
|
||||
saved_90_days_total: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -69,6 +73,7 @@ describe('visualizationsTaskRunner', () => {
|
|||
_source: {
|
||||
type: 'visualization',
|
||||
visualization: { visState: '{"type": "cave_painting"}' },
|
||||
updated_at: moment().subtract(7, 'days').startOf('day').toString(),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -76,11 +81,16 @@ describe('visualizationsTaskRunner', () => {
|
|||
_source: {
|
||||
type: 'visualization',
|
||||
visualization: { visState: '{"type": "printing_press"}' },
|
||||
updated_at: moment().subtract(20, 'days').startOf('day').toString(),
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'meat:visualization:coolviz-789',
|
||||
_source: { type: 'visualization', visualization: { visState: '{"type": "floppy_disk"}' } },
|
||||
_source: {
|
||||
type: 'visualization',
|
||||
visualization: { visState: '{"type": "floppy_disk"}' },
|
||||
updated_at: moment().subtract(2, 'months').startOf('day').toString(),
|
||||
},
|
||||
},
|
||||
// meat space
|
||||
{
|
||||
|
@ -88,38 +98,99 @@ describe('visualizationsTaskRunner', () => {
|
|||
_source: {
|
||||
type: 'visualization',
|
||||
visualization: { visState: '{"type": "cave_painting"}' },
|
||||
updated_at: moment().subtract(89, 'days').startOf('day').toString(),
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'meat:visualization:coolviz-789',
|
||||
_source: { type: 'visualization', visualization: { visState: '{"type": "cuneiform"}' } },
|
||||
_source: {
|
||||
type: 'visualization',
|
||||
visualization: { visState: '{"type": "cuneiform"}' },
|
||||
updated_at: moment().subtract(5, 'months').startOf('day').toString(),
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'meat:visualization:coolviz-789',
|
||||
_source: { type: 'visualization', visualization: { visState: '{"type": "cuneiform"}' } },
|
||||
_source: {
|
||||
type: 'visualization',
|
||||
visualization: { visState: '{"type": "cuneiform"}' },
|
||||
updated_at: moment().subtract(2, 'days').startOf('day').toString(),
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'meat:visualization:coolviz-789',
|
||||
_source: { type: 'visualization', visualization: { visState: '{"type": "floppy_disk"}' } },
|
||||
_source: {
|
||||
type: 'visualization',
|
||||
visualization: { visState: '{"type": "floppy_disk"}' },
|
||||
updated_at: moment().subtract(7, 'days').startOf('day').toString(),
|
||||
},
|
||||
},
|
||||
// cyber space
|
||||
{
|
||||
_id: 'cyber:visualization:coolviz-789',
|
||||
_source: { type: 'visualization', visualization: { visState: '{"type": "floppy_disk"}' } },
|
||||
_source: {
|
||||
type: 'visualization',
|
||||
visualization: { visState: '{"type": "floppy_disk"}' },
|
||||
updated_at: moment().subtract(7, 'months').startOf('day').toString(),
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'cyber:visualization:coolviz-789',
|
||||
_source: { type: 'visualization', visualization: { visState: '{"type": "floppy_disk"}' } },
|
||||
_source: {
|
||||
type: 'visualization',
|
||||
visualization: { visState: '{"type": "floppy_disk"}' },
|
||||
updated_at: moment().subtract(3, 'days').startOf('day').toString(),
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'cyber:visualization:coolviz-123',
|
||||
_source: {
|
||||
type: 'visualization',
|
||||
visualization: { visState: '{"type": "cave_painting"}' },
|
||||
updated_at: moment().subtract(15, 'days').startOf('day').toString(),
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const expectedStats = {
|
||||
cave_painting: {
|
||||
total: 3,
|
||||
spaces_min: 1,
|
||||
spaces_max: 1,
|
||||
spaces_avg: 1,
|
||||
saved_7_days_total: 1,
|
||||
saved_30_days_total: 2,
|
||||
saved_90_days_total: 3,
|
||||
},
|
||||
printing_press: {
|
||||
total: 1,
|
||||
spaces_min: 1,
|
||||
spaces_max: 1,
|
||||
spaces_avg: 1,
|
||||
saved_7_days_total: 0,
|
||||
saved_30_days_total: 1,
|
||||
saved_90_days_total: 1,
|
||||
},
|
||||
cuneiform: {
|
||||
total: 2,
|
||||
spaces_min: 2,
|
||||
spaces_max: 2,
|
||||
spaces_avg: 2,
|
||||
saved_7_days_total: 1,
|
||||
saved_30_days_total: 1,
|
||||
saved_90_days_total: 1,
|
||||
},
|
||||
floppy_disk: {
|
||||
total: 4,
|
||||
spaces_min: 2,
|
||||
spaces_max: 2,
|
||||
spaces_avg: 2,
|
||||
saved_7_days_total: 2,
|
||||
saved_30_days_total: 2,
|
||||
saved_90_days_total: 3,
|
||||
},
|
||||
};
|
||||
|
||||
const runner = visualizationsTaskRunner(
|
||||
mockTaskInstance,
|
||||
getMockConfig(),
|
||||
|
@ -131,13 +202,10 @@ describe('visualizationsTaskRunner', () => {
|
|||
error: undefined,
|
||||
state: {
|
||||
runs: 1,
|
||||
stats: {
|
||||
cave_painting: { total: 3, spaces_min: 1, spaces_max: 1, spaces_avg: 1 },
|
||||
printing_press: { total: 1, spaces_min: 1, spaces_max: 1, spaces_avg: 1 },
|
||||
cuneiform: { total: 2, spaces_min: 2, spaces_max: 2, spaces_avg: 2 },
|
||||
floppy_disk: { total: 4, spaces_min: 2, spaces_max: 2, spaces_avg: 2 },
|
||||
},
|
||||
stats: expectedStats,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.state.stats).toMatchObject(expectedStats);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,12 +10,14 @@ import { first } from 'rxjs/operators';
|
|||
|
||||
import { APICaller, IClusterClient } from 'src/core/server';
|
||||
import { getNextMidnight } from '../../get_next_midnight';
|
||||
import { getPastDays } from '../../get_past_days';
|
||||
import { TaskInstance } from '../../../../../task_manager/server';
|
||||
import { ESSearchHit } from '../../../../../apm/typings/elasticsearch';
|
||||
|
||||
interface VisSummary {
|
||||
type: string;
|
||||
space: string;
|
||||
past_days: number;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -26,7 +28,11 @@ async function getStats(callCluster: APICaller, index: string) {
|
|||
size: 10000, // elasticsearch index.max_result_window default value
|
||||
index,
|
||||
ignoreUnavailable: true,
|
||||
filterPath: ['hits.hits._id', 'hits.hits._source.visualization'],
|
||||
filterPath: [
|
||||
'hits.hits._id',
|
||||
'hits.hits._source.visualization',
|
||||
'hits.hits._source.updated_at',
|
||||
],
|
||||
body: {
|
||||
query: {
|
||||
bool: { filter: { term: { type: 'visualization' } } },
|
||||
|
@ -43,13 +49,14 @@ async function getStats(callCluster: APICaller, index: string) {
|
|||
const visSummaries: VisSummary[] = esResponse.hits.hits.map(
|
||||
(hit: ESSearchHit<{ visState: string }>) => {
|
||||
const spacePhrases: string[] = hit._id.split(':');
|
||||
const lastUpdated: string = _.get(hit, '_source.updated_at');
|
||||
const space = spacePhrases.length === 3 ? spacePhrases[0] : 'default'; // if in a custom space, the format of a saved object ID is space:type:id
|
||||
const visualization = _.get(hit, '_source.visualization', { visState: '{}' });
|
||||
const visState: { type?: string } = JSON.parse(visualization.visState);
|
||||
|
||||
return {
|
||||
type: visState.type || '_na_',
|
||||
space,
|
||||
past_days: getPastDays(lastUpdated),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
@ -68,6 +75,9 @@ async function getStats(callCluster: APICaller, index: string) {
|
|||
spaces_min: _.min(spaceCounts),
|
||||
spaces_max: _.max(spaceCounts),
|
||||
spaces_avg: total / spaceCounts.length,
|
||||
saved_7_days_total: curr.filter((c) => c.past_days <= 7).length,
|
||||
saved_30_days_total: curr.filter((c) => c.past_days <= 30).length,
|
||||
saved_90_days_total: curr.filter((c) => c.past_days <= 90).length,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import { APICaller } from 'kibana/server';
|
||||
|
||||
import { of } from 'rxjs';
|
||||
import moment from 'moment';
|
||||
import { elasticsearchServiceMock } from '../../../../../src/core/server/mocks';
|
||||
import {
|
||||
ConcreteTaskInstance,
|
||||
|
@ -38,6 +39,7 @@ const defaultMockSavedObjects = [
|
|||
_source: {
|
||||
type: 'visualization',
|
||||
visualization: { visState: '{"type": "shell_beads"}' },
|
||||
updated_at: moment().subtract(7, 'days').startOf('day').toString(),
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
Loading…
Reference in a new issue