(core) Add new telemetry events

Summary: Adds a handful of new telemetry events, and makes a few tweaks to allow for better organization of telemetry.

Test Plan: Manual.

Reviewers: paulfitz

Reviewed By: paulfitz

Differential Revision: https://phab.getgrist.com/D4100
This commit is contained in:
George Gevoian
2023-11-01 09:54:19 -04:00
parent 51f7402297
commit 7a85aaa7a1
19 changed files with 523 additions and 129 deletions

View File

@@ -24,6 +24,7 @@ import {DocPluginManager} from 'app/client/lib/DocPluginManager';
import {ImportSourceElement} from 'app/client/lib/ImportSourceElement';
import {makeT} from 'app/client/lib/localization';
import {createSessionObs} from 'app/client/lib/sessionObs';
import {logTelemetryEvent} from 'app/client/lib/telemetry';
import {setTestState} from 'app/client/lib/testState';
import {selectFiles} from 'app/client/lib/uploads';
import {AppModel, reportError} from 'app/client/models/AppModel';
@@ -62,7 +63,7 @@ import {DisposableWithEvents} from 'app/common/DisposableWithEvents';
import {isSchemaAction, UserAction} from 'app/common/DocActions';
import {OpenLocalDocResult} from 'app/common/DocListAPI';
import {isList, isListType, isRefListType, RecalcWhen} from 'app/common/gristTypes';
import {HashLink, IDocPage, isViewDocPage, SpecialDocPage, ViewDocPage} from 'app/common/gristUrls';
import {HashLink, IDocPage, isViewDocPage, parseUrlId, SpecialDocPage, ViewDocPage} from 'app/common/gristUrls';
import {undef, waitObs} from 'app/common/gutil';
import {LocalPlugin} from "app/common/plugin";
import {StringUnion} from 'app/common/StringUnion';
@@ -400,6 +401,16 @@ export class GristDoc extends DisposableWithEvents {
&& markAsSeen(this._seenDocTours, this.docId())
);
await startDocTour(this.docData, this.docComm, onFinishCB);
if (this.docPageModel.isTemplate.get()) {
const doc = this.docPageModel.currentDoc.get();
if (!doc) { return; }
logTelemetryEvent('openedTemplateTour', {
full: {
templateId: parseUrlId(doc.urlId || doc.id).trunkId,
},
});
}
} else {
startWelcomeTour(() => this._showGristTour.set(false));
}

View File

@@ -27,6 +27,7 @@ import {Document, NEW_DOCUMENT_CODE, Organization, UserAPI, Workspace} from 'app
import {Holder, Observable, subscribe} from 'grainjs';
import {Computed, Disposable, dom, DomArg, DomElementArg} from 'grainjs';
import {makeT} from 'app/client/lib/localization';
import {logTelemetryEvent} from 'app/client/lib/telemetry';
// tslint:disable:no-console
@@ -365,6 +366,14 @@ It also disables formulas. [{{error}}]", {error: err.message})
await this.updateUrlNoReload(doc.urlId, doc.openMode);
}
if (doc.isTemplate) {
logTelemetryEvent('openedTemplate', {
full: {
templateId: parseUrlId(doc.urlId || doc.id).trunkId,
},
});
}
this.currentDoc.set(doc);
}

View File

@@ -59,6 +59,8 @@ export class DocTutorial extends FloatingPopup {
if (tableData) {
this.autoDispose(tableData.tableActionEmitter.addListener(() => this._reloadSlides()));
}
this._logTelemetryEvent('tutorialOpened');
}
protected _buildTitle() {
@@ -158,6 +160,24 @@ export class DocTutorial extends FloatingPopup {
];
}
private _logTelemetryEvent(event: 'tutorialOpened' | 'tutorialProgressChanged') {
const currentSlideIndex = this._currentSlideIndex.get();
const numSlides = this._slides.get()?.length;
let percentComplete: number | undefined = undefined;
if (numSlides !== undefined && numSlides > 0) {
percentComplete = Math.floor(((currentSlideIndex + 1) / numSlides) * 100);
}
logTelemetryEvent(event, {
full: {
tutorialForkIdDigest: this._currentFork?.id,
tutorialTrunkIdDigest: this._currentFork?.trunkId,
lastSlideIndex: currentSlideIndex,
numSlides,
percentComplete,
},
});
}
private async _loadSlides() {
const tableId = 'GristDocTutorial';
if (!this._docData.getTable(tableId)) {
@@ -234,7 +254,6 @@ export class DocTutorial extends FloatingPopup {
private async _saveCurrentSlidePosition() {
const currentOptions = this._currentDoc?.options ?? {};
const currentSlideIndex = this._currentSlideIndex.get();
const numSlides = this._slides.get()?.length;
await this._appModel.api.updateDoc(this._docId, {
options: {
...currentOptions,
@@ -243,20 +262,7 @@ export class DocTutorial extends FloatingPopup {
}
}
});
let percentComplete: number | undefined = undefined;
if (numSlides !== undefined && numSlides > 0) {
percentComplete = Math.floor(((currentSlideIndex + 1) / numSlides) * 100);
}
logTelemetryEvent('tutorialProgressChanged', {
full: {
tutorialForkIdDigest: this._currentFork?.id,
tutorialTrunkIdDigest: this._currentFork?.trunkId,
lastSlideIndex: currentSlideIndex,
numSlides,
percentComplete,
},
});
this._logTelemetryEvent('tutorialProgressChanged');
}
private async _changeSlide(slideIndex: number) {

View File

@@ -1,3 +1,4 @@
import {logTelemetryEvent} from 'app/client/lib/telemetry';
import {AppModel} from 'app/client/models/AppModel';
import {bigBasicButton, bigPrimaryButtonLink} from 'app/client/ui2018/buttons';
import {testId, theme, vars} from 'app/client/ui2018/cssVars';
@@ -93,7 +94,10 @@ export function showWelcomeCoachingCall(triggerElement: Element, appModel: AppMo
cssPopupButtons(
bigPrimaryButtonLink(
'Schedule Call',
dom.on('click', () => dismissPopup(false)),
dom.on('click', () => {
dismissPopup(false);
logTelemetryEvent('clickedScheduleCoachingCall');
}),
{
href: FREE_COACHING_CALL_URL,
target: '_blank',

View File

@@ -172,9 +172,16 @@ export class FormulaAssistant extends Disposable {
this._triggerFinalize = bundleInfo.triggerFinalize;
this.onDispose(() => {
if (this._hasExpandedOnce) {
const suggestionApplied = this._chat.conversationSuggestedFormulas.get()
.includes(this._options.column.formula.peek());
if (suggestionApplied) {
this._logTelemetryEvent('assistantApplySuggestion', false, {
conversationLength: this._chat.conversationLength.get(),
conversationHistoryLength: this._chat.conversationHistoryLength.get(),
});
}
this._logTelemetryEvent('assistantClose', false, {
suggestionApplied: this._chat.conversationSuggestedFormulas.get()
.includes(this._options.column.formula.peek()),
suggestionApplied,
conversationLength: this._chat.conversationLength.get(),
conversationHistoryLength: this._chat.conversationHistoryLength.get(),
});
@@ -400,7 +407,9 @@ export class FormulaAssistant extends Disposable {
*/
private _cancel() {
if (this._hasExpandedOnce) {
this._logTelemetryEvent('assistantCancel', true);
this._logTelemetryEvent('assistantCancel', true, {
conversationLength: this._chat.conversationLength.get(),
});
}
this._action = 'cancel';
this._triggerFinalize();