Add support for telemetry endpoint Index: code-server/lib/vscode/src/vs/server/node/serverServices.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/server/node/serverServices.ts +++ code-server/lib/vscode/src/vs/server/node/serverServices.ts @@ -71,6 +71,7 @@ import { IExtensionsScannerService } fro import { ExtensionsScannerService } from 'vs/server/node/extensionsScannerService'; import { ExtensionsProfileScannerService, IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; import { IUserDataProfilesService, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { TelemetryClient } from "vs/server/node/telemetryClient"; import { NullPolicyService } from 'vs/platform/policy/common/policy'; import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender'; @@ -133,10 +134,13 @@ export async function setupServerService const machineId = await getMachineId(); const isInternal = isInternalTelemetry(productService, configurationService); if (supportsTelemetry(productService, environmentService)) { - if (productService.aiConfig && productService.aiConfig.ariaKey) { + const telemetryEndpoint = process.env.CS_TELEMETRY_URL || "https://v1.telemetry.coder.com/track"; + if (telemetryEndpoint) { + oneDsAppender = new OneDataSystemAppender(false, eventPrefix, null, () => new TelemetryClient(telemetryEndpoint)); + } else if (productService.aiConfig && productService.aiConfig.ariaKey) { oneDsAppender = new OneDataSystemAppender(isInternal, eventPrefix, null, productService.aiConfig.ariaKey); - disposables.add(toDisposable(() => oneDsAppender?.flush())); // Ensure the AI appender is disposed so that it flushes remaining data } + disposables.add(toDisposable(() => oneDsAppender?.flush())); // Ensure the AI appender is disposed so that it flushes remaining data const config: ITelemetryServiceConfig = { appenders: [oneDsAppender], Index: code-server/lib/vscode/src/vs/server/node/telemetryClient.ts =================================================================== --- /dev/null +++ code-server/lib/vscode/src/vs/server/node/telemetryClient.ts @@ -0,0 +1,49 @@ +import { AppInsightsCore, IExtendedTelemetryItem, ITelemetryItem } from '@microsoft/1ds-core-js'; +import * as https from 'https'; +import * as http from 'http'; +import * as os from 'os'; + +export class TelemetryClient extends AppInsightsCore { + public constructor(private readonly endpoint: string) { + super(); + } + + public override track(item: IExtendedTelemetryItem | ITelemetryItem): void { + const options = item.baseData || {} + if (!options.properties) { + options.properties = {}; + } + if (!options.measurements) { + options.measurements = {}; + } + + try { + const cpus = os.cpus(); + options.measurements.cores = cpus.length; + options.properties['common.cpuModel'] = cpus[0].model; + } catch (error) {} + + try { + options.measurements.memoryFree = os.freemem(); + options.measurements.memoryTotal = os.totalmem(); + } catch (error) {} + + try { + options.properties['common.shell'] = os.userInfo().shell; + options.properties['common.release'] = os.release(); + options.properties['common.arch'] = os.arch(); + } catch (error) {} + + try { + const request = (/^http:/.test(this.endpoint) ? http : https).request(this.endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }); + request.on('error', () => { /* We don't care. */ }); + request.write(JSON.stringify(options)); + request.end(); + } catch (error) {} + } +} Index: code-server/lib/vscode/src/vs/workbench/services/telemetry/browser/telemetryService.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/workbench/services/telemetry/browser/telemetryService.ts +++ code-server/lib/vscode/src/vs/workbench/services/telemetry/browser/telemetryService.ts @@ -38,26 +38,30 @@ export class TelemetryService extends Di ) { super(); - if (supportsTelemetry(productService, environmentService) && productService.aiConfig?.ariaKey) { + if (supportsTelemetry(productService, environmentService)) { // If remote server is present send telemetry through that, else use the client side appender const appenders = []; const isInternal = isInternalTelemetry(productService, configurationService); - const telemetryProvider: ITelemetryAppender = remoteAgentService.getConnection() !== null ? { log: remoteAgentService.logTelemetry.bind(remoteAgentService), flush: remoteAgentService.flushTelemetry.bind(remoteAgentService) } : new OneDataSystemWebAppender(isInternal, 'monacoworkbench', null, productService.aiConfig?.ariaKey); - appenders.push(telemetryProvider); - appenders.push(new TelemetryLogAppender(loggerService, environmentService)); - const config: ITelemetryServiceConfig = { - appenders, - commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, isInternal, environmentService.remoteAuthority, productService.embedderIdentifier, productService.removeTelemetryMachineId, environmentService.options && environmentService.options.resolveCommonTelemetryProperties), - sendErrorTelemetry: this.sendErrorTelemetry, - }; - this.impl = this._register(new BaseTelemetryService(config, configurationService, productService)); - - if (getTelemetryLevel(configurationService) !== TelemetryLevel.NONE) { - // If we cannot fetch the endpoint it means it is down and we should not send any telemetry. - // This is most likely due to ad blockers - fetch(telemetryEndpointUrl, { method: 'POST' }).catch(err => { - this.impl = NullTelemetryService; - }); + const telemetryProvider: ITelemetryAppender | undefined = remoteAgentService.getConnection() !== null ? { log: remoteAgentService.logTelemetry.bind(remoteAgentService), flush: remoteAgentService.flushTelemetry.bind(remoteAgentService) } : productService.aiConfig?.ariaKey ? new OneDataSystemWebAppender(isInternal, 'monacoworkbench', null, productService.aiConfig?.ariaKey) : undefined; + if (telemetryProvider) { + appenders.push(telemetryProvider); + appenders.push(new TelemetryLogAppender(loggerService, environmentService)); + const config: ITelemetryServiceConfig = { + appenders, + commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, isInternal, environmentService.remoteAuthority, productService.embedderIdentifier, productService.removeTelemetryMachineId, environmentService.options && environmentService.options.resolveCommonTelemetryProperties), + sendErrorTelemetry: this.sendErrorTelemetry, + }; + this.impl = this._register(new BaseTelemetryService(config, configurationService, productService)); + + if (remoteAgentService.getConnection() === null && getTelemetryLevel(configurationService) !== TelemetryLevel.NONE) { + // If we cannot fetch the endpoint it means it is down and we should not send any telemetry. + // This is most likely due to ad blockers + fetch(telemetryEndpointUrl, { method: 'POST' }).catch(err => { + this.impl = NullTelemetryService; + }); + } + } else { + this.impl = NullTelemetryService; } } else { this.impl = NullTelemetryService; Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts +++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts @@ -324,6 +324,7 @@ export class WebClientServer { scope: vscodeBase + '/', path: base + '/_static/out/browser/serviceWorker.js', }, + enableTelemetry: this._productService.enableTelemetry, embedderIdentifier: 'server-distro', extensionsGallery: this._productService.extensionsGallery, },