Add support for telemetry endpoint To test: 1. Create a mock API using [RequestBin](https://requestbin.io/) or [Beeceptor](https://beeceptor.com/) 2. Run code-server with `CS_TELEMETRY_URL` set: i.e. `CS_TELEMETRY_URL="https://requestbin.io/1ebub9z1" ./code-server--macos-amd64/bin/code-server` NOTE: it has to be a production build. 3. Load code-server in browser an do things (i.e. open a file) 4. Refresh RequestBin and you should see logs 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 @@ -65,6 +65,7 @@ import { IExtensionsScannerService } fro import { ExtensionsScannerService } from 'vs/server/node/extensionsScannerService'; import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; import { IUserDataProfilesService } 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'; import { LoggerService } from 'vs/platform/log/node/loggerService'; @@ -146,11 +147,23 @@ export async function setupServerService const requestService = new RequestService(configurationService, environmentService, logService, loggerService); services.set(IRequestService, requestService); + let isContainer = undefined; + try { + await Promises.stat('/run/.containerenv'); + isContainer = true; + } catch (error) { /* Does not exist, probably. */ } + if (!isContainer) { + try { + const content = await Promises.readFile('/proc/self/cgroup', 'utf8') + isContainer = content.includes('docker'); + } catch (error) { /* Permission denied, probably. */ } + } + let oneDsAppender: ITelemetryAppender = NullAppender; const isInternal = isInternalTelemetry(productService, configurationService); if (supportsTelemetry(productService, environmentService)) { - if (!isLoggingOnly(productService, environmentService) && productService.aiConfig?.ariaKey) { - oneDsAppender = new OneDataSystemAppender(requestService, isInternal, eventPrefix, null, productService.aiConfig.ariaKey); + if (!isLoggingOnly(productService, environmentService) && productService.telemetryEndpoint) { + oneDsAppender = new OneDataSystemAppender(requestService, isInternal, eventPrefix, null, () => new TelemetryClient(productService.telemetryEndpoint!, isContainer)); disposables.add(toDisposable(() => oneDsAppender?.flush())); // Ensure the AI appender is disposed so that it flushes remaining data } 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,53 @@ +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, + private readonly isContainer: Boolean | undefined) { + 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) {} + + options.properties['common.isContainer'] = this.isContainer; + + 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/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 @@ -318,6 +318,8 @@ export class WebClientServer { scope: vscodeBase + '/', path: base + '/_static/out/browser/serviceWorker.js', }, + enableTelemetry: this._productService.enableTelemetry, + telemetryEndpoint: this._productService.telemetryEndpoint, embedderIdentifier: 'server-distro', extensionsGallery: this._productService.extensionsGallery, }; Index: code-server/lib/vscode/src/vs/base/common/product.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/base/common/product.ts +++ code-server/lib/vscode/src/vs/base/common/product.ts @@ -64,6 +64,7 @@ export interface IProductConfiguration { readonly path: string; readonly scope: string; } + readonly telemetryEndpoint?: string readonly version: string; readonly date?: string; Index: code-server/lib/vscode/src/vs/platform/product/common/product.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/platform/product/common/product.ts +++ code-server/lib/vscode/src/vs/platform/product/common/product.ts @@ -55,7 +55,8 @@ else if (globalThis._VSCODE_PRODUCT_JSON resourceUrlTemplate: "https://open-vsx.org/vscode/asset/{publisher}/{name}/{version}/Microsoft.VisualStudio.Code.WebResources/{path}", controlUrl: "", recommendationsUrl: "", - }) + }), + telemetryEndpoint: env.CS_TELEMETRY_URL || product.telemetryEndpoint || "https://v1.telemetry.coder.com/track", }); }