Skip to content

Commit 3ed3cec

Browse files
committed
use unified analytics endpoint
1 parent 993573c commit 3ed3cec

File tree

6 files changed

+63
-40
lines changed

6 files changed

+63
-40
lines changed

.github/workflows/gitpod-web-docker.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
working-directory: ./gitpod-web
3333
run: |
3434
set -e
35-
setSegmentKey="setpath([\"segmentKey\"]; \"${{ secrets.ANALITYCS_KEY }}\")"
35+
setSegmentKey="setpath([\"segmentKey\"]; \"untrusted-dummy-key\")"
3636
jqCommands="${setSegmentKey}"
3737
cat package.json | jq "${jqCommands}" > package.json.tmp
3838
mv package.json.tmp package.json

.github/workflows/release-gitpod-remote.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
working-directory: ./gitpod-remote
2222
run: |
2323
set -e
24-
setSegmentKey="setpath([\"segmentKey\"]; \"${{ secrets.ANALITYCS_KEY }}\")"
24+
setSegmentKey="setpath([\"segmentKey\"]; \"untrusted-dummy-key\")"
2525
jqCommands="${setSegmentKey}"
2626
cat package.json | jq "${jqCommands}" > package.json.tmp
2727
mv package.json.tmp package.json

gitpod-shared/src/common/telemetry.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ const enum TelemetryLevel {
1515
}
1616

1717
function getTelemetryLevel(): TelemetryLevel {
18+
if (vscode.env.appName === 'Gitpod Code') {
19+
return TelemetryLevel.ON;
20+
}
21+
1822
const TELEMETRY_CONFIG_ID = 'telemetry';
1923
const TELEMETRY_CONFIG_ENABLED_ID = 'enableTelemetry';
2024

@@ -63,15 +67,10 @@ export class BaseTelemetryAppender implements ITelemetryAppender {
6367
private _exceptionQueue: Array<{ exception: Error; data: AppenderData | undefined }> = [];
6468

6569
// Necessary information to create a telemetry client
66-
private _clientFactory: (key: string) => Promise<BaseTelemetryClient>;
67-
private _key: string;
70+
private _clientFactory: () => Promise<BaseTelemetryClient>;
6871

69-
constructor(key: string, clientFactory: (key: string) => Promise<BaseTelemetryClient>) {
72+
constructor(clientFactory: () => Promise<BaseTelemetryClient>) {
7073
this._clientFactory = clientFactory;
71-
this._key = key;
72-
if (getTelemetryLevel() !== TelemetryLevel.OFF) {
73-
this.instantiateAppender();
74-
}
7574
}
7675

7776
/**
@@ -131,10 +130,11 @@ export class BaseTelemetryAppender implements ITelemetryAppender {
131130
if (this._isInstantiated) {
132131
return;
133132
}
133+
this._isInstantiated = true;
134+
134135
// Call the client factory to get the client and then let it know it's instatntiated
135-
this._clientFactory(this._key).then(client => {
136+
this._clientFactory().then(client => {
136137
this._telemetryClient = client;
137-
this._isInstantiated = true;
138138
this._flushQueues();
139139
}).catch(err => {
140140
console.error(err);

gitpod-shared/src/features.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ export async function createGitpodExtensionContext(context: vscode.ExtensionCont
123123
pendingWillCloseSocket,
124124
workspaceInfo,
125125
pendingGetOwner,
126+
pendingGetUserId,
126127
pendingGetUserTeams,
127128
pendingInstanceListener,
128129
pendingWorkspaceOwned,

gitpod-shared/src/gitpodContext.ts

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,33 @@
22
* Copyright (c) Gitpod. All rights reserved.
33
*--------------------------------------------------------------------------------------------*/
44

5-
import * as vscode from 'vscode';
6-
import * as util from 'util';
7-
import * as grpc from '@grpc/grpc-js';
85
import { GitpodClient, GitpodServer, GitpodServiceImpl, WorkspaceInstanceUpdateListener } from '@gitpod/gitpod-protocol/lib/gitpod-service';
9-
import { PortServiceClient } from '@gitpod/supervisor-api-grpc/lib/port_grpc_pb';
10-
import { StatusServiceClient } from '@gitpod/supervisor-api-grpc/lib/status_grpc_pb';
6+
import { User } from '@gitpod/gitpod-protocol/lib/protocol';
117
import { Team } from '@gitpod/gitpod-protocol/lib/teams-projects-protocol';
12-
import { NotificationServiceClient } from '@gitpod/supervisor-api-grpc/lib/notification_grpc_pb';
13-
import { TerminalServiceClient } from '@gitpod/supervisor-api-grpc/lib/terminal_grpc_pb';
14-
import { TokenServiceClient } from '@gitpod/supervisor-api-grpc/lib/token_grpc_pb';
158
import { PortVisibility } from '@gitpod/gitpod-protocol/lib/workspace-instance';
169
import { ControlServiceClient } from '@gitpod/supervisor-api-grpc/lib/control_grpc_pb';
10+
import { ExposePortRequest } from '@gitpod/supervisor-api-grpc/lib/control_pb';
1711
import { InfoServiceClient } from '@gitpod/supervisor-api-grpc/lib/info_grpc_pb';
18-
import * as uuid from 'uuid';
19-
import { CloseTunnelRequest, RetryAutoExposeRequest, TunnelPortRequest, TunnelVisiblity } from '@gitpod/supervisor-api-grpc/lib/port_pb';
2012
import { DebugWorkspaceType, WorkspaceInfoRequest, WorkspaceInfoResponse } from '@gitpod/supervisor-api-grpc/lib/info_pb';
21-
import { User } from '@gitpod/gitpod-protocol/lib/protocol';
22-
import ReconnectingWebSocket from 'reconnecting-websocket';
23-
import { ILogService } from './logService';
24-
import { GitpodYml } from './gitpodYaml';
25-
import * as path from 'path';
13+
import { NotificationServiceClient } from '@gitpod/supervisor-api-grpc/lib/notification_grpc_pb';
14+
import { PortServiceClient } from '@gitpod/supervisor-api-grpc/lib/port_grpc_pb';
15+
import { CloseTunnelRequest, RetryAutoExposeRequest, TunnelPortRequest, TunnelVisiblity } from '@gitpod/supervisor-api-grpc/lib/port_pb';
16+
import { StatusServiceClient } from '@gitpod/supervisor-api-grpc/lib/status_grpc_pb';
17+
import { PortsStatus, PortsStatusRequest, PortsStatusResponse } from '@gitpod/supervisor-api-grpc/lib/status_pb';
18+
import { TerminalServiceClient } from '@gitpod/supervisor-api-grpc/lib/terminal_grpc_pb';
19+
import { TokenServiceClient } from '@gitpod/supervisor-api-grpc/lib/token_grpc_pb';
2620
import { GetTokenRequest } from '@gitpod/supervisor-api-grpc/lib/token_pb';
27-
import { PortsStatusRequest, PortsStatusResponse, PortsStatus } from '@gitpod/supervisor-api-grpc/lib/status_pb';
21+
import * as grpc from '@grpc/grpc-js';
22+
import * as path from 'path';
23+
import ReconnectingWebSocket from 'reconnecting-websocket';
24+
import * as util from 'util';
25+
import * as uuid from 'uuid';
26+
import * as vscode from 'vscode';
2827
import { isGRPCErrorStatus } from './common/utils';
29-
import { ExposePortRequest } from '@gitpod/supervisor-api-grpc/lib/control_pb';
3028
import { ExperimentalSettings } from './experiments';
31-
import { TelemetryService } from './telemetryService';
29+
import { GitpodYml } from './gitpodYaml';
30+
import { ILogService } from './logService';
31+
import { TelemetryService, TelemetrySettings } from './telemetryService';
3232

3333
// Important:
3434
// This class should performs all supervisor API calls used outside this module.
@@ -209,6 +209,7 @@ export class GitpodExtensionContext implements vscode.ExtensionContext {
209209
readonly pendingWillCloseSocket: (() => Promise<void>)[],
210210
readonly info: WorkspaceInfoResponse.AsObject,
211211
readonly owner: Promise<User>,
212+
readonly userId: Promise<string>,
212213
readonly userTeams: Promise<Team[]>,
213214
readonly instanceListener: Promise<WorkspaceInstanceUpdateListener>,
214215
readonly workspaceOwned: Promise<boolean>,
@@ -224,7 +225,17 @@ export class GitpodExtensionContext implements vscode.ExtensionContext {
224225

225226
const extensionId = context.extension.id;
226227
const packageJSON = context.extension.packageJSON;
227-
this.telemetryService = new TelemetryService(extensionId, packageJSON.version, packageJSON.segmentKey);
228+
const telemetrySettigns: TelemetrySettings = {
229+
writeKey: packageJSON.segmentKey,
230+
// in dev mode we report to IDE lab source directly
231+
host: 'https://api.segment.io',
232+
path: '/v1/batch',
233+
}
234+
if (telemetrySettigns.writeKey === "untrusted-dummy-key") {
235+
telemetrySettigns.host = info.gitpodHost;
236+
telemetrySettigns.path = '/analytics' + telemetrySettigns.path;
237+
}
238+
this.telemetryService = new TelemetryService(extensionId, packageJSON.version, userId, telemetrySettigns, logger);
228239
}
229240

230241
get active() {

gitpod-shared/src/telemetryService.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,54 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { AppenderData, BaseTelemetryAppender, BaseTelemetryClient, BaseTelemetryReporter } from './common/telemetry';
7-
import { Analytics } from '@segment/analytics-node';
7+
import { Analytics, AnalyticsSettings } from '@segment/analytics-node';
88
import * as os from 'os';
9-
import * as vscode from 'vscode';
9+
import { ILogService } from './logService';
1010

11-
const analyticsClientFactory = async (key: string): Promise<BaseTelemetryClient> => {
12-
let segmentAnalyticsClient = new Analytics({ writeKey: key });
11+
type RequireKeys<T extends object, K extends keyof T> =
12+
Required<Pick<T, K>> & Omit<T, K>;
13+
14+
export type TelemetrySettings = RequireKeys<AnalyticsSettings, 'writeKey' | 'host' | 'path'>
15+
16+
const analyticsClientFactory = async (pendingUserId: Promise<string>, settings: TelemetrySettings, logger: ILogService): Promise<BaseTelemetryClient> => {
17+
const userId = await pendingUserId;
18+
let segmentAnalyticsClient = new Analytics(settings);
19+
logger.debug("analytics: " + new URL(settings.path, settings.host).href.replace(/\/$/, '')); // aligned with how segment does it internally
1320

1421
// Sets the analytics client into a standardized form
1522
const telemetryClient: BaseTelemetryClient = {
1623
logEvent: (eventName: string, data?: AppenderData) => {
1724
try {
1825
segmentAnalyticsClient.track({
19-
anonymousId: vscode.env.machineId,
26+
userId,
2027
event: eventName,
2128
properties: data?.properties
29+
}, (e) => {
30+
if (e) {
31+
logger.error('Failed to log event to app analytics:', e);
32+
}
2233
});
2334
} catch (e: any) {
24-
console.error('Failed to log event to app analytics!', e);
35+
logger.error('Failed to log event to app analytics:', e);
2536
}
2637
},
2738
logException: (_exception: Error, _data?: AppenderData) => {
28-
throw new Error('Failed to log exception to app analytics!\n');
39+
throw new Error('Failed to log exception to app analytics!\n');
2940
},
3041
flush: async () => {
3142
try {
3243
await segmentAnalyticsClient.closeAndFlush({ timeout: 3000 });
3344
} catch (e: any) {
34-
console.error('Failed to flush app analytics!', e);
45+
logger.error('Failed to flush app analytics!', e);
3546
}
3647
}
3748
};
3849
return telemetryClient;
3950
};
4051

4152
export class TelemetryService extends BaseTelemetryReporter {
42-
constructor(extensionId: string, extensionVersion: string, key: string) {
43-
const appender = new BaseTelemetryAppender(key, (key) => analyticsClientFactory(key));
53+
constructor(extensionId: string, extensionVersion: string, userId: Promise<string>, settings: TelemetrySettings, logger: ILogService) {
54+
const appender = new BaseTelemetryAppender(() => analyticsClientFactory(userId, settings, logger));
4455
super(extensionId, extensionVersion, appender, {
4556
release: os.release(),
4657
platform: os.platform(),

0 commit comments

Comments
 (0)