Skip to content

Commit 3bbfd11

Browse files
[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>
1 parent 823ce64 commit 3bbfd11

5 files changed

Lines changed: 127 additions & 14 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import moment from 'moment';
8+
import { getPastDays } from './get_past_days';
9+
10+
describe('getPastDays', () => {
11+
test('Returns 2 days that have passed from the current date', () => {
12+
const pastDate = moment().subtract(2, 'days').startOf('day').toString();
13+
14+
expect(getPastDays(pastDate)).toEqual(2);
15+
});
16+
17+
test('Returns 30 days that have passed from the current date', () => {
18+
const pastDate = moment().subtract(30, 'days').startOf('day').toString();
19+
20+
expect(getPastDays(pastDate)).toEqual(30);
21+
});
22+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
export const getPastDays = (dateString: string): number => {
7+
const date = new Date(dateString);
8+
const today = new Date();
9+
const diff = Math.abs(date.getTime() - today.getTime());
10+
return Math.trunc(diff / (1000 * 60 * 60 * 24));
11+
};

x-pack/plugins/oss_telemetry/server/lib/tasks/visualizations/task_runner.test.ts

Lines changed: 80 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
import { visualizationsTaskRunner } from './task_runner';
1414
import { TaskInstance } from '../../../../../task_manager/server';
1515
import { getNextMidnight } from '../../get_next_midnight';
16+
import moment from 'moment';
1617

1718
describe('visualizationsTaskRunner', () => {
1819
let mockTaskInstance: TaskInstance;
@@ -55,6 +56,9 @@ describe('visualizationsTaskRunner', () => {
5556
spaces_max: 1,
5657
spaces_min: 1,
5758
total: 1,
59+
saved_7_days_total: 1,
60+
saved_30_days_total: 1,
61+
saved_90_days_total: 1,
5862
},
5963
},
6064
},
@@ -69,57 +73,124 @@ describe('visualizationsTaskRunner', () => {
6973
_source: {
7074
type: 'visualization',
7175
visualization: { visState: '{"type": "cave_painting"}' },
76+
updated_at: moment().subtract(7, 'days').startOf('day').toString(),
7277
},
7378
},
7479
{
7580
_id: 'visualization:coolviz-456',
7681
_source: {
7782
type: 'visualization',
7883
visualization: { visState: '{"type": "printing_press"}' },
84+
updated_at: moment().subtract(20, 'days').startOf('day').toString(),
7985
},
8086
},
8187
{
8288
_id: 'meat:visualization:coolviz-789',
83-
_source: { type: 'visualization', visualization: { visState: '{"type": "floppy_disk"}' } },
89+
_source: {
90+
type: 'visualization',
91+
visualization: { visState: '{"type": "floppy_disk"}' },
92+
updated_at: moment().subtract(2, 'months').startOf('day').toString(),
93+
},
8494
},
8595
// meat space
8696
{
8797
_id: 'meat:visualization:coolviz-789',
8898
_source: {
8999
type: 'visualization',
90100
visualization: { visState: '{"type": "cave_painting"}' },
101+
updated_at: moment().subtract(89, 'days').startOf('day').toString(),
91102
},
92103
},
93104
{
94105
_id: 'meat:visualization:coolviz-789',
95-
_source: { type: 'visualization', visualization: { visState: '{"type": "cuneiform"}' } },
106+
_source: {
107+
type: 'visualization',
108+
visualization: { visState: '{"type": "cuneiform"}' },
109+
updated_at: moment().subtract(5, 'months').startOf('day').toString(),
110+
},
96111
},
97112
{
98113
_id: 'meat:visualization:coolviz-789',
99-
_source: { type: 'visualization', visualization: { visState: '{"type": "cuneiform"}' } },
114+
_source: {
115+
type: 'visualization',
116+
visualization: { visState: '{"type": "cuneiform"}' },
117+
updated_at: moment().subtract(2, 'days').startOf('day').toString(),
118+
},
100119
},
101120
{
102121
_id: 'meat:visualization:coolviz-789',
103-
_source: { type: 'visualization', visualization: { visState: '{"type": "floppy_disk"}' } },
122+
_source: {
123+
type: 'visualization',
124+
visualization: { visState: '{"type": "floppy_disk"}' },
125+
updated_at: moment().subtract(7, 'days').startOf('day').toString(),
126+
},
104127
},
105128
// cyber space
106129
{
107130
_id: 'cyber:visualization:coolviz-789',
108-
_source: { type: 'visualization', visualization: { visState: '{"type": "floppy_disk"}' } },
131+
_source: {
132+
type: 'visualization',
133+
visualization: { visState: '{"type": "floppy_disk"}' },
134+
updated_at: moment().subtract(7, 'months').startOf('day').toString(),
135+
},
109136
},
110137
{
111138
_id: 'cyber:visualization:coolviz-789',
112-
_source: { type: 'visualization', visualization: { visState: '{"type": "floppy_disk"}' } },
139+
_source: {
140+
type: 'visualization',
141+
visualization: { visState: '{"type": "floppy_disk"}' },
142+
updated_at: moment().subtract(3, 'days').startOf('day').toString(),
143+
},
113144
},
114145
{
115146
_id: 'cyber:visualization:coolviz-123',
116147
_source: {
117148
type: 'visualization',
118149
visualization: { visState: '{"type": "cave_painting"}' },
150+
updated_at: moment().subtract(15, 'days').startOf('day').toString(),
119151
},
120152
},
121153
]);
122154

155+
const expectedStats = {
156+
cave_painting: {
157+
total: 3,
158+
spaces_min: 1,
159+
spaces_max: 1,
160+
spaces_avg: 1,
161+
saved_7_days_total: 1,
162+
saved_30_days_total: 2,
163+
saved_90_days_total: 3,
164+
},
165+
printing_press: {
166+
total: 1,
167+
spaces_min: 1,
168+
spaces_max: 1,
169+
spaces_avg: 1,
170+
saved_7_days_total: 0,
171+
saved_30_days_total: 1,
172+
saved_90_days_total: 1,
173+
},
174+
cuneiform: {
175+
total: 2,
176+
spaces_min: 2,
177+
spaces_max: 2,
178+
spaces_avg: 2,
179+
saved_7_days_total: 1,
180+
saved_30_days_total: 1,
181+
saved_90_days_total: 1,
182+
},
183+
floppy_disk: {
184+
total: 4,
185+
spaces_min: 2,
186+
spaces_max: 2,
187+
spaces_avg: 2,
188+
saved_7_days_total: 2,
189+
saved_30_days_total: 2,
190+
saved_90_days_total: 3,
191+
},
192+
};
193+
123194
const runner = visualizationsTaskRunner(
124195
mockTaskInstance,
125196
getMockConfig(),
@@ -131,13 +202,10 @@ describe('visualizationsTaskRunner', () => {
131202
error: undefined,
132203
state: {
133204
runs: 1,
134-
stats: {
135-
cave_painting: { total: 3, spaces_min: 1, spaces_max: 1, spaces_avg: 1 },
136-
printing_press: { total: 1, spaces_min: 1, spaces_max: 1, spaces_avg: 1 },
137-
cuneiform: { total: 2, spaces_min: 2, spaces_max: 2, spaces_avg: 2 },
138-
floppy_disk: { total: 4, spaces_min: 2, spaces_max: 2, spaces_avg: 2 },
139-
},
205+
stats: expectedStats,
140206
},
141207
});
208+
209+
expect(result.state.stats).toMatchObject(expectedStats);
142210
});
143211
});

x-pack/plugins/oss_telemetry/server/lib/tasks/visualizations/task_runner.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ import { first } from 'rxjs/operators';
1010

1111
import { APICaller, IClusterClient } from 'src/core/server';
1212
import { getNextMidnight } from '../../get_next_midnight';
13+
import { getPastDays } from '../../get_past_days';
1314
import { TaskInstance } from '../../../../../task_manager/server';
1415
import { ESSearchHit } from '../../../../../apm/typings/elasticsearch';
1516

1617
interface VisSummary {
1718
type: string;
1819
space: string;
20+
past_days: number;
1921
}
2022

2123
/*
@@ -26,7 +28,11 @@ async function getStats(callCluster: APICaller, index: string) {
2628
size: 10000, // elasticsearch index.max_result_window default value
2729
index,
2830
ignoreUnavailable: true,
29-
filterPath: ['hits.hits._id', 'hits.hits._source.visualization'],
31+
filterPath: [
32+
'hits.hits._id',
33+
'hits.hits._source.visualization',
34+
'hits.hits._source.updated_at',
35+
],
3036
body: {
3137
query: {
3238
bool: { filter: { term: { type: 'visualization' } } },
@@ -43,13 +49,14 @@ async function getStats(callCluster: APICaller, index: string) {
4349
const visSummaries: VisSummary[] = esResponse.hits.hits.map(
4450
(hit: ESSearchHit<{ visState: string }>) => {
4551
const spacePhrases: string[] = hit._id.split(':');
52+
const lastUpdated: string = _.get(hit, '_source.updated_at');
4653
const space = spacePhrases.length === 3 ? spacePhrases[0] : 'default'; // if in a custom space, the format of a saved object ID is space:type:id
4754
const visualization = _.get(hit, '_source.visualization', { visState: '{}' });
4855
const visState: { type?: string } = JSON.parse(visualization.visState);
49-
5056
return {
5157
type: visState.type || '_na_',
5258
space,
59+
past_days: getPastDays(lastUpdated),
5360
};
5461
}
5562
);
@@ -68,6 +75,9 @@ async function getStats(callCluster: APICaller, index: string) {
6875
spaces_min: _.min(spaceCounts),
6976
spaces_max: _.max(spaceCounts),
7077
spaces_avg: total / spaceCounts.length,
78+
saved_7_days_total: curr.filter((c) => c.past_days <= 7).length,
79+
saved_30_days_total: curr.filter((c) => c.past_days <= 30).length,
80+
saved_90_days_total: curr.filter((c) => c.past_days <= 90).length,
7181
};
7282
});
7383
}

x-pack/plugins/oss_telemetry/server/test_utils/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import { APICaller } from 'src/core/server';
88
import { of } from 'rxjs';
9+
import moment from 'moment';
910
import { elasticsearchServiceMock } from '../../../../../src/core/server/mocks';
1011
import {
1112
ConcreteTaskInstance,
@@ -37,6 +38,7 @@ const defaultMockSavedObjects = [
3738
_source: {
3839
type: 'visualization',
3940
visualization: { visState: '{"type": "shell_beads"}' },
41+
updated_at: moment().subtract(7, 'days').startOf('day').toString(),
4042
},
4143
},
4244
];

0 commit comments

Comments
 (0)