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
@@ -4,6 +4,7 @@
  *--------------------------------------------------------------------------------------------*/
 
 import { hostname, release } from 'os';
+import { promises as fs } from 'fs';
 import { Emitter, Event } from '../../base/common/event.js';
 import { DisposableStore, toDisposable } from '../../base/common/lifecycle.js';
 import { Schemas } from '../../base/common/network.js';
@@ -65,6 +66,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';
@@ -166,11 +168,23 @@ export async function setupServerService
 	const requestService = new RequestService('remote', configurationService, environmentService, logService);
 	services.set(IRequestService, requestService);
 
+	let isContainer = undefined;
+	try {
+		await fs.stat('/run/.containerenv');
+		isContainer = true;
+	} catch (error) { /* Does not exist, probably. */ }
+	if (!isContainer) {
+		try {
+			const content = await fs.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
@@ -347,6 +347,8 @@ export class WebClientServer {
 				scope: vscodeBase + '/',
 				path: rootBase + '/_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
@@ -73,6 +73,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
@@ -58,7 +58,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",
 	});
 }
 
