(core) Add optional telemetry to grist-core

Summary:
Adds support for optional telemetry to grist-core.

A new environment variable, GRIST_TELEMETRY_LEVEL, controls the level of telemetry collected.

Test Plan: Server and unit tests.

Reviewers: paulfitz

Reviewed By: paulfitz

Subscribers: dsagal, anaisconce

Differential Revision: https://phab.getgrist.com/D3880
This commit is contained in:
George Gevoian
2023-06-06 13:08:50 -04:00
parent 0d082c9cfc
commit 10f5f0cb37
38 changed files with 2177 additions and 201 deletions

View File

@@ -164,12 +164,14 @@ export class Document extends Resource {
const percentComplete = lastSlideIndex !== undefined && numSlides !== undefined
? Math.floor((lastSlideIndex / numSlides) * 100)
: undefined;
dbManager?.emit('tutorialProgressChange', {
tutorialForkIdDigest: hashId(this.id),
tutorialTrunkIdDigest: this.trunkId ? hashId(this.trunkId) : undefined,
lastSlideIndex,
numSlides,
percentComplete,
dbManager?.emit('tutorialProgressChanged', {
full: {
tutorialForkIdDigest: hashId(this.id),
tutorialTrunkIdDigest: this.trunkId ? hashId(this.trunkId) : undefined,
lastSlideIndex,
numSlides,
percentComplete,
},
});
}
}

View File

@@ -89,13 +89,13 @@ export const NotifierEvents = StringUnion(
export type NotifierEvent = typeof NotifierEvents.type;
export const TelemetryEvents = StringUnion(
'tutorialProgressChange',
export const HomeDBTelemetryEvents = StringUnion(
'tutorialProgressChanged',
);
export type TelemetryEvent = typeof TelemetryEvents.type;
export type HomeDBTelemetryEvent = typeof HomeDBTelemetryEvents.type;
export type Event = NotifierEvent | TelemetryEvent;
export type Event = NotifierEvent | HomeDBTelemetryEvent;
// Nominal email address of a user who can view anything (for thumbnails).
export const PREVIEWER_EMAIL = 'thumbnail@getgrist.com';

View File

@@ -37,6 +37,7 @@ export class Housekeeper {
private _deleteTrashinterval?: NodeJS.Timeout;
private _logMetricsInterval?: NodeJS.Timeout;
private _electionKey?: string;
private _telemetry = this._server.getTelemetry();
public constructor(private _dbManager: HomeDBManager, private _server: GristServer,
private _permitStore: IPermitStore, private _electionStore: IElectionStore) {
@@ -174,30 +175,37 @@ export class Housekeeper {
*/
public async logMetrics() {
await this._dbManager.connection.transaction('READ UNCOMMITTED', async (manager) => {
const telemetryManager = this._server.getTelemetryManager();
const usageSummaries = await this._getOrgUsageSummaries(manager);
for (const summary of usageSummaries) {
telemetryManager?.logEvent('siteUsage', {
siteId: summary.site_id,
siteType: summary.site_type,
inGoodStanding: Boolean(summary.in_good_standing),
stripePlanId: summary.stripe_plan_id,
numDocs: Number(summary.num_docs),
numWorkspaces: Number(summary.num_workspaces),
numMembers: Number(summary.num_members),
lastActivity: summary.last_activity,
});
this._telemetry.logEvent('siteUsage', {
limited: {
siteId: summary.site_id,
siteType: summary.site_type,
inGoodStanding: Boolean(summary.in_good_standing),
numDocs: Number(summary.num_docs),
numWorkspaces: Number(summary.num_workspaces),
numMembers: Number(summary.num_members),
lastActivity: summary.last_activity,
},
full: {
stripePlanId: summary.stripe_plan_id,
},
})
.catch(e => log.error('failed to log telemetry event siteUsage', e));
}
const membershipSummaries = await this._getOrgMembershipSummaries(manager);
for (const summary of membershipSummaries) {
telemetryManager?.logEvent('siteMembership', {
siteId: summary.site_id,
siteType: summary.site_type,
numOwners: Number(summary.num_owners),
numEditors: Number(summary.num_editors),
numViewers: Number(summary.num_viewers),
});
this._telemetry.logEvent('siteMembership', {
limited: {
siteId: summary.site_id,
siteType: summary.site_type,
numOwners: Number(summary.num_owners),
numEditors: Number(summary.num_editors),
numViewers: Number(summary.num_viewers),
},
})
.catch(e => log.error('failed to log telemetry event siteMembership', e));
}
});
}