Skip to content

Commit 4e55c23

Browse files
authored
Add ide_heartbeat telemetry IDE-19 (#46)
* Add `ide_heartbeat` telemetry * Add delta a property of telemetry * Remove origin delta report * Stop send `ide_heartbeat` if workspace is not running (will send last report)
1 parent 614dc18 commit 4e55c23

File tree

1 file changed

+48
-11
lines changed

1 file changed

+48
-11
lines changed

src/heartbeat.ts

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,37 @@ import { ITelemetryService } from './services/telemetryService';
1212
import { SSHConnectionParams } from './remote';
1313
import { ISessionService } from './services/sessionService';
1414
import { ILogService } from './services/logService';
15+
import { RawTelemetryEventProperties } from './common/telemetry';
16+
17+
const IDEHeartbeatTelemetryEvent = 'ide_heartbeat';
18+
interface IDEHeartbeatTelemetryData extends RawTelemetryEventProperties {
19+
clientKind: 'vscode-desktop'; // 'ssh' | 'jetbrains' | 'vscode-desktop' | 'supervisor-frontend';
20+
totalCount: number;
21+
successfulCount: number;
22+
workspaceId: string;
23+
instanceId: string;
24+
gitpodHost: string;
25+
debugWorkspace: 'true' | 'false';
26+
delta?: { [key: string]: number; };
27+
}
1528

1629
export class HeartbeatManager extends Disposable {
1730

1831
static HEARTBEAT_INTERVAL = 30000;
19-
static EVENT_COUNTER_INTERVAL = 3600000;
32+
static IDE_HEARTBEAT_INTERVAL = 900000; // 15 minutes
2033

2134
private lastActivity = new Date().getTime();
2235
private lastActivityEvent: string = 'init';
2336
private isWorkspaceRunning = true;
2437
private heartBeatHandle: NodeJS.Timer | undefined;
2538

2639
private eventCounterMap = new Map<string, number>();
27-
private eventCounterHandle: NodeJS.Timer | undefined;
40+
41+
private ideHeartbeatTelemetryHandle: NodeJS.Timer | undefined;
42+
private ideHeartbeatData: Pick<IDEHeartbeatTelemetryData, "successfulCount" | "totalCount"> = {
43+
successfulCount: 0,
44+
totalCount: 0,
45+
}
2846

2947
constructor(
3048
private readonly connectionInfo: SSHConnectionParams,
@@ -104,7 +122,7 @@ export class HeartbeatManager extends Disposable {
104122
this.sendHeartBeat();
105123
}, HeartbeatManager.HEARTBEAT_INTERVAL);
106124

107-
this.eventCounterHandle = setInterval(() => this.sendEventData(), HeartbeatManager.EVENT_COUNTER_INTERVAL);
125+
this.ideHeartbeatTelemetryHandle = setInterval(() => this.sendIDEHeartbeatTelemetry(), HeartbeatManager.IDE_HEARTBEAT_INTERVAL);
108126
}
109127

110128
private updateLastActivity(event: string, document?: vscode.TextDocument) {
@@ -118,6 +136,7 @@ export class HeartbeatManager extends Disposable {
118136
}
119137

120138
private async sendHeartBeat(wasClosed?: true) {
139+
let heartbeatSucceed = false
121140
try {
122141
await withServerApi(this.sessionService.getGitpodToken(), this.connectionInfo.gitpodHost, async service => {
123142
const workspaceInfo = this.usePublicApi
@@ -136,9 +155,11 @@ export class HeartbeatManager extends Disposable {
136155
} else {
137156
this.logService.trace(`Send heartbeat, triggered by ${this.lastActivityEvent} event`);
138157
}
158+
heartbeatSucceed = true;
139159
} else {
140160
this.logService.trace('Stopping heartbeat as workspace is not running');
141161
this.stopHeartbeat();
162+
this.stopIDEHeartbeatTelemetry();
142163
}
143164
}, this.logService);
144165
} catch (e) {
@@ -148,6 +169,11 @@ export class HeartbeatManager extends Disposable {
148169
this.logService.error(e);
149170
e.message = `Failed to send ${suffix}: ${originMsg}`;
150171
this.telemetryService.sendTelemetryException(this.connectionInfo.gitpodHost, e, { workspaceId: this.connectionInfo.workspaceId, instanceId: this.connectionInfo.instanceId});
172+
} finally {
173+
if (heartbeatSucceed) {
174+
this.ideHeartbeatData.successfulCount++;
175+
}
176+
this.ideHeartbeatData.totalCount++;
151177
}
152178
}
153179

@@ -158,22 +184,33 @@ export class HeartbeatManager extends Disposable {
158184
}
159185
}
160186

161-
private sendEventData() {
162-
this.telemetryService.sendRawTelemetryEvent(this.connectionInfo.gitpodHost, 'vscode_desktop_heartbeat_delta', { events: Object.fromEntries(this.eventCounterMap), workspaceId: this.connectionInfo.workspaceId, instanceId: this.connectionInfo.instanceId, gitpodHost: this.connectionInfo.gitpodHost, clientKind: 'vscode' });
187+
private sendIDEHeartbeatTelemetry() {
188+
this.telemetryService.sendRawTelemetryEvent(this.connectionInfo.gitpodHost, IDEHeartbeatTelemetryEvent, {
189+
...this.ideHeartbeatData,
190+
workspaceId: this.connectionInfo.workspaceId,
191+
instanceId: this.connectionInfo.instanceId,
192+
gitpodHost: this.connectionInfo.gitpodHost,
193+
clientKind: 'vscode-desktop',
194+
debugWorkspace: String(!!this.connectionInfo.debugWorkspace),
195+
delta: Object.fromEntries(this.eventCounterMap),
196+
} as IDEHeartbeatTelemetryData);
197+
163198
this.eventCounterMap.clear();
199+
this.ideHeartbeatData.successfulCount = 0;
200+
this.ideHeartbeatData.totalCount = 0;
164201
}
165202

166-
private stopEventCounter() {
167-
if (this.eventCounterHandle) {
168-
clearInterval(this.eventCounterHandle);
169-
this.eventCounterHandle = undefined;
203+
private stopIDEHeartbeatTelemetry() {
204+
if (this.ideHeartbeatTelemetryHandle) {
205+
clearInterval(this.ideHeartbeatTelemetryHandle);
206+
this.ideHeartbeatTelemetryHandle = undefined;
207+
this.sendIDEHeartbeatTelemetry()
170208
}
171209
}
172210

173211
public override async dispose(): Promise<void> {
174212
super.dispose();
175-
this.stopEventCounter();
176-
this.sendEventData();
213+
this.stopIDEHeartbeatTelemetry();
177214
this.stopHeartbeat();
178215
if (this.isWorkspaceRunning) {
179216
await this.sendHeartBeat(true);

0 commit comments

Comments
 (0)