mirror of
https://github.com/coder/code-server.git
synced 2026-09-12 02:33:19 +02:00
* Update Code to 1.136.1 * Do not click on tab during test file opens It will already be the selected tab, and if any other tab is already open (like the welcome tab), it will click that instead. We disable the welcome page so this is not supposed to actually matter, but that Setting appears not to be working. Also add the quick input widget selector in the disabled downloads test, since if the widget never shows up it would mistakenly pass.
164 lines
7.0 KiB
Diff
164 lines
7.0 KiB
Diff
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-<version>-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
|
|
@@ -68,6 +68,7 @@ import { IExtensionsScannerService } fro
|
|
import { ExtensionsScannerService } from './extensionsScannerService.js';
|
|
import { IExtensionsProfileScannerService } from '../../platform/extensionManagement/common/extensionsProfileScannerService.js';
|
|
import { IUserDataProfilesService } from '../../platform/userDataProfile/common/userDataProfile.js';
|
|
+import { TelemetryClient } from './telemetryClient.js';
|
|
import { NullPolicyService } from '../../platform/policy/common/policy.js';
|
|
import { OneDataSystemAppender } from '../../platform/telemetry/node/1dsAppender.js';
|
|
import { LoggerService } from '../../platform/log/node/loggerService.js';
|
|
@@ -179,11 +180,23 @@ export async function setupServerService
|
|
const requestService = new RequestService('remote', configurationService, environmentService, logService);
|
|
services.set(IRequestService, requestService);
|
|
|
|
+ let isContainer = undefined;
|
|
+ try {
|
|
+ await fs.promises.stat('/run/.containerenv');
|
|
+ isContainer = true;
|
|
+ } catch (error) { /* Does not exist, probably. */ }
|
|
+ if (!isContainer) {
|
|
+ try {
|
|
+ const content = await fs.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!, machineId, 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,71 @@
|
|
+import { AppInsightsCore, IExtendedTelemetryItem, ITelemetryItem } from '@microsoft/1ds-core-js';
|
|
+import * as https from 'https';
|
|
+import * as http from 'http';
|
|
+import * as os from 'os';
|
|
+
|
|
+interface SystemInfo {
|
|
+ measurements: Record<string, number | undefined>;
|
|
+ properties: Record<string, string | boolean | null | undefined>;
|
|
+}
|
|
+
|
|
+export class TelemetryClient extends AppInsightsCore {
|
|
+ private readonly systemInfo: SystemInfo = {
|
|
+ measurements: {},
|
|
+ properties: {},
|
|
+ };
|
|
+
|
|
+ public constructor(
|
|
+ private readonly endpoint: string,
|
|
+ machineId: string,
|
|
+ isContainer: boolean | undefined) {
|
|
+ super();
|
|
+
|
|
+ // os.cpus() can take a very long time sometimes (personally I see 1-2
|
|
+ // seconds in a Coder workspace). This adds up significantly, especially
|
|
+ // when many telemetry requests are sent during startup, which can cause
|
|
+ // connection timeouts. Try to cache as much as we can.
|
|
+ try {
|
|
+ const cpus = os.cpus();
|
|
+ this.systemInfo.measurements.cores = cpus.length;
|
|
+ this.systemInfo.properties['common.cpuModel'] = cpus[0].model;
|
|
+ } catch (error) {}
|
|
+
|
|
+ try {
|
|
+ this.systemInfo.properties['common.shell'] = os.userInfo().shell;
|
|
+ this.systemInfo.properties['common.release'] = os.release();
|
|
+ this.systemInfo.properties['common.arch'] = os.arch();
|
|
+ } catch (error) {}
|
|
+
|
|
+ this.systemInfo.properties['common.remoteMachineId'] = machineId;
|
|
+ this.systemInfo.properties['common.isContainer'] = isContainer;
|
|
+ }
|
|
+
|
|
+ public override track(item: IExtendedTelemetryItem | ITelemetryItem): void {
|
|
+ const options = item.baseData || {}
|
|
+ options.measurements = {
|
|
+ ...(options.measurements || {}),
|
|
+ ...this.systemInfo.measurements,
|
|
+ }
|
|
+ options.properties = {
|
|
+ ...(options.properties || {}),
|
|
+ ...this.systemInfo.properties,
|
|
+ }
|
|
+
|
|
+ try {
|
|
+ options.measurements.memoryFree = os.freemem();
|
|
+ options.measurements.memoryTotal = os.totalmem();
|
|
+ } 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/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
|
|
@@ -408,6 +408,8 @@ export class WebClientServer {
|
|
scope: vscodeBase + '/',
|
|
path: rootBase + '/_static/out/browser/serviceWorker.js',
|
|
},
|
|
+ enableTelemetry: this._productService.enableTelemetry,
|
|
+ telemetryEndpoint: this._productService.telemetryEndpoint,
|
|
embedderIdentifier: 'server-distro',
|
|
voiceWsUrl: this._productService.voiceWsUrl,
|
|
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
|
|
@@ -106,6 +106,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
|
|
@@ -74,7 +74,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",
|
|
});
|
|
}
|
|
|