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

6915 - Telemetry daily frequency #7095

Merged
merged 17 commits into from
Jun 1, 2021
10 changes: 6 additions & 4 deletions scripts/get_users_meta_docs.js
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#!/usr/bin/env node

const inquirer = require('inquirer');
const PouchDB = require('pouchdb-core');
const fs = require('fs');
Expand Down Expand Up @@ -86,7 +88,7 @@ const actionQuestions = [{
}
docs.forEach(doc => console.log(JSON.stringify(doc, null, 2) + ','));
} else if (i === 0) {
console.log('\x1b[31m%s\x1b[0m', `There are no documents of type ${type}`);
console.error('\x1b[31m%s\x1b[0m', `There are no documents of type ${type}`);
break;
} else {
console.log('{}]');
Expand All @@ -100,7 +102,7 @@ const actionQuestions = [{
let docIndex = 0;

if (docs.length === 0) {
console.log('\x1b[31m%s\x1b[0m', `There are no documents of type ${type}`);
console.error('\x1b[31m%s\x1b[0m', `There are no documents of type ${type}`);
} else {
console.log(JSON.stringify(docs[docIndex], null, 2));

Expand All @@ -125,7 +127,7 @@ const actionQuestions = [{

console.log(JSON.stringify(docs[docIndex], null, 2));
if (printMessage) {
console.log('\x1b[31m%s\x1b[0m', `No next document. This is the last one.`);
console.error('\x1b[31m%s\x1b[0m', `No next document. This is the last one.`);
}
} else if (response.action === 'save_current') {
const filePath = path.join(path.resolve(__dirname), docs[docIndex]._id + '.json');
Expand Down Expand Up @@ -154,6 +156,6 @@ const actionQuestions = [{
}
}
} catch(err) {
console.log(err);
console.error(err);
}
})();
53 changes: 40 additions & 13 deletions webapp/src/ts/services/telemetry.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { SessionService } from '@mm-services/session.service';
providedIn: 'root'
})
/**
* TelemetryService: Records, aggregates, and submits telemetry data
* TelemetryService: Records, aggregates, and submits telemetry data.
*/
export class TelemetryService {
// Intentionally scoped to the whole browser (for this domain). We can then tell if multiple users use the same device
Expand Down Expand Up @@ -54,7 +54,16 @@ export class TelemetryService {
return uniqueDeviceId;
}

private getLastAggregatedDate() {
/**
* Returns the time in milliseconds (since Unix epoch) when the first telemetry
* record was created within the day that is going to be aggregated.
mrsarm marked this conversation as resolved.
Show resolved Hide resolved
*
* The date is stored locally once computed by this method, either because is
* the first time is called or because the aggregation was performed last time
* a record was created, therefore `reset(db)' deleted it, and next time this
* method is called the date need to be fetched from the system again.
mrsarm marked this conversation as resolved.
Show resolved Hide resolved
*/
private getFirstAggregatedDate() {
dianabarsan marked this conversation as resolved.
Show resolved Hide resolved
let date = parseInt(window.localStorage.getItem(this.LAST_AGGREGATED_DATE_KEY));

if (!date) {
Expand All @@ -73,14 +82,26 @@ export class TelemetryService {
});
}

private submitIfNeeded(db) {
const monthStart = moment().startOf('month');
const dbDate = moment(this.getLastAggregatedDate());
// moment when the aggregation starts (the beginning of the current day)
private aggregateStartsAt() {
return moment().startOf('day');
//return moment().startOf('minute');
mrsarm marked this conversation as resolved.
Show resolved Hide resolved
}

if (dbDate.isBefore(monthStart)) {
return this
.aggregate(db)
.then(() => this.reset(db));
// if there is telemetry data to aggregate and is before the current date,
// aggregation is performed and the data destroyed
mrsarm marked this conversation as resolved.
Show resolved Hide resolved
private submitIfNeeded(db) {
const startOf = this.aggregateStartsAt();
const dbDate = moment(this.getFirstAggregatedDate());

if (dbDate.isBefore(startOf)) {
return db.info()
mrsarm marked this conversation as resolved.
Show resolved Hide resolved
.then(info => {
if (info.doc_count > 0) {
mrsarm marked this conversation as resolved.
Show resolved Hide resolved
return this.aggregate(db)
mrsarm marked this conversation as resolved.
Show resolved Hide resolved
.then(() => this.reset(db));
}
});
}
}

Expand All @@ -97,6 +118,9 @@ export class TelemetryService {
'telemetry',
metadata.year,
metadata.month,
metadata.day,
//metadata.hour,
mrsarm marked this conversation as resolved.
Show resolved Hide resolved
//metadata.minute,
metadata.user,
metadata.deviceId,
].join('-');
Expand All @@ -109,7 +133,7 @@ export class TelemetryService {
this.dbService.get().query('medic-client/doc_by_type', { key: ['form'], include_docs: true })
])
.then(([ddoc, formResults]) => {
const date = moment(this.getLastAggregatedDate());
const date = moment(this.getFirstAggregatedDate());
mrsarm marked this conversation as resolved.
Show resolved Hide resolved
const version = (ddoc.deploy_info && ddoc.deploy_info.version) || 'unknown';
const forms = formResults.rows.reduce((keyToVersion, row) => {
keyToVersion[row.doc.internalId] = row.doc._rev;
Expand All @@ -120,6 +144,9 @@ export class TelemetryService {
return {
year: date.year(),
month: date.month() + 1,
day: date.date(),
//hour: date.hour(),
mrsarm marked this conversation as resolved.
Show resolved Hide resolved
//minute: date.minute(),
user: this.sessionService.userCtx().name,
deviceId: this.getUniqueDeviceId(),
versions: {
Expand Down Expand Up @@ -225,7 +252,7 @@ export class TelemetryService {
* metric_b: { sum: -16, min: -4, max: -4, count: 4, sumsqr: 64 }
* }
*
* See: https://wiki.apache.org/couchdb/Built-In_Reduce_Functions#A_stats
* See: https://docs.couchdb.org/en/stable/ddocs/ddocs.html#_stats
*
* This single month aggregate document is of type 'telemetry', and is
* stored in the user's meta DB (which replicates up to the main server)
Expand Down Expand Up @@ -255,14 +282,14 @@ export class TelemetryService {
let db;
this.queue = this.queue
.then(() => db = this.getDb())
.then(() => this.storeIt(db, key, value))
.then(() => this.submitIfNeeded(db))
.then(() => db = this.getDb()) // db is fetched again in case submitIfNeeded dropped the old reference
.then(() => this.storeIt(db, key, value))
.catch(err => console.error('Error in telemetry service', err))
.finally(() => {
if (!db || db._destroyed || db._closed) {
return;
}

try {
db.close();
} catch (err) {
Expand Down
Loading