[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:
Stratoula Kalafateli 2020-06-08 17:29:20 +03:00 committed by GitHub
parent e66eaf74fd
commit fcab9745e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 127 additions and 14 deletions

View file

@ -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);
});
});

View 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));
};

View file

@ -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);
});
});

View file

@ -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,
};
});
}

View file

@ -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(),
},
},
];