Skip to content

Commit 5b7ba55

Browse files
authored
chore: reinstate telemetry/docker change after revert MCP-49 (#339)
1 parent d7d4aa9 commit 5b7ba55

File tree

4 files changed

+67
-28
lines changed

4 files changed

+67
-28
lines changed

src/telemetry/telemetry.ts

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { MACHINE_METADATA } from "./constants.js";
77
import { EventCache } from "./eventCache.js";
88
import nodeMachineId from "node-machine-id";
99
import { getDeviceId } from "@mongodb-js/device-id";
10+
import fs from "fs/promises";
1011

1112
type EventResult = {
1213
success: boolean;
@@ -17,8 +18,8 @@ export const DEVICE_ID_TIMEOUT = 3000;
1718

1819
export class Telemetry {
1920
private isBufferingEvents: boolean = true;
20-
/** Resolves when the device ID is retrieved or timeout occurs */
21-
public deviceIdPromise: Promise<string> | undefined;
21+
/** Resolves when the setup is complete or a timeout occurs */
22+
public setupPromise: Promise<[string, boolean]> | undefined;
2223
private deviceIdAbortController = new AbortController();
2324
private eventCache: EventCache;
2425
private getRawMachineId: () => Promise<string>;
@@ -48,33 +49,62 @@ export class Telemetry {
4849
): Telemetry {
4950
const instance = new Telemetry(session, userConfig, commonProperties, { eventCache, getRawMachineId });
5051

51-
void instance.start();
52+
void instance.setup();
5253
return instance;
5354
}
5455

55-
private async start(): Promise<void> {
56-
if (!this.isTelemetryEnabled()) {
57-
return;
56+
private async isContainerEnv(): Promise<boolean> {
57+
if (process.platform !== "linux") {
58+
return false; // we only support linux containers for now
59+
}
60+
61+
if (process.env.container) {
62+
return true;
5863
}
59-
this.deviceIdPromise = getDeviceId({
60-
getMachineId: () => this.getRawMachineId(),
61-
onError: (reason, error) => {
62-
switch (reason) {
63-
case "resolutionError":
64-
logger.debug(LogId.telemetryDeviceIdFailure, "telemetry", String(error));
65-
break;
66-
case "timeout":
67-
logger.debug(LogId.telemetryDeviceIdTimeout, "telemetry", "Device ID retrieval timed out");
68-
break;
69-
case "abort":
70-
// No need to log in the case of aborts
71-
break;
64+
65+
const exists = await Promise.all(
66+
["/.dockerenv", "/run/.containerenv", "/var/run/.containerenv"].map(async (file) => {
67+
try {
68+
await fs.access(file);
69+
return true;
70+
} catch {
71+
return false;
7272
}
73-
},
74-
abortSignal: this.deviceIdAbortController.signal,
75-
});
73+
})
74+
);
7675

77-
this.commonProperties.device_id = await this.deviceIdPromise;
76+
return exists.includes(true);
77+
}
78+
79+
private async setup(): Promise<void> {
80+
if (!this.isTelemetryEnabled()) {
81+
return;
82+
}
83+
this.setupPromise = Promise.all([
84+
getDeviceId({
85+
getMachineId: () => this.getRawMachineId(),
86+
onError: (reason, error) => {
87+
switch (reason) {
88+
case "resolutionError":
89+
logger.debug(LogId.telemetryDeviceIdFailure, "telemetry", String(error));
90+
break;
91+
case "timeout":
92+
logger.debug(LogId.telemetryDeviceIdTimeout, "telemetry", "Device ID retrieval timed out");
93+
break;
94+
case "abort":
95+
// No need to log in the case of aborts
96+
break;
97+
}
98+
},
99+
abortSignal: this.deviceIdAbortController.signal,
100+
}),
101+
this.isContainerEnv(),
102+
]);
103+
104+
const [deviceId, containerEnv] = await this.setupPromise;
105+
106+
this.commonProperties.device_id = deviceId;
107+
this.commonProperties.is_container_env = containerEnv;
78108

79109
this.isBufferingEvents = false;
80110
}

src/telemetry/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export type CommonStaticProperties = {
6666
*/
6767
export type CommonProperties = {
6868
device_id?: string;
69+
is_container_env?: boolean;
6970
mcp_client_version?: string;
7071
mcp_client_name?: string;
7172
config_atlas_auth?: TelemetryBoolSet;

tests/integration/telemetry.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe("Telemetry", () => {
2020
expect(telemetry.getCommonProperties().device_id).toBe(undefined);
2121
expect(telemetry["isBufferingEvents"]).toBe(true);
2222

23-
await telemetry.deviceIdPromise;
23+
await telemetry.setupPromise;
2424

2525
expect(telemetry.getCommonProperties().device_id).toBe(actualHashedId);
2626
expect(telemetry["isBufferingEvents"]).toBe(false);

tests/unit/telemetry.test.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ describe("Telemetry", () => {
138138
it("should send events successfully", async () => {
139139
const testEvent = createTestEvent();
140140

141+
await telemetry.setupPromise;
142+
141143
await telemetry.emitEvents([testEvent]);
142144

143145
verifyMockCalls({
@@ -152,6 +154,8 @@ describe("Telemetry", () => {
152154

153155
const testEvent = createTestEvent();
154156

157+
await telemetry.setupPromise;
158+
155159
await telemetry.emitEvents([testEvent]);
156160

157161
verifyMockCalls({
@@ -175,6 +179,8 @@ describe("Telemetry", () => {
175179
// Set up mock to return cached events
176180
mockEventCache.getEvents.mockReturnValueOnce([cachedEvent]);
177181

182+
await telemetry.setupPromise;
183+
178184
await telemetry.emitEvents([newEvent]);
179185

180186
verifyMockCalls({
@@ -184,7 +190,9 @@ describe("Telemetry", () => {
184190
});
185191
});
186192

187-
it("should correctly add common properties to events", () => {
193+
it("should correctly add common properties to events", async () => {
194+
await telemetry.setupPromise;
195+
188196
const commonProps = telemetry.getCommonProperties();
189197

190198
// Use explicit type assertion
@@ -219,7 +227,7 @@ describe("Telemetry", () => {
219227
expect(telemetry["isBufferingEvents"]).toBe(true);
220228
expect(telemetry.getCommonProperties().device_id).toBe(undefined);
221229

222-
await telemetry.deviceIdPromise;
230+
await telemetry.setupPromise;
223231

224232
expect(telemetry["isBufferingEvents"]).toBe(false);
225233
expect(telemetry.getCommonProperties().device_id).toBe(hashedMachineId);
@@ -235,7 +243,7 @@ describe("Telemetry", () => {
235243
expect(telemetry["isBufferingEvents"]).toBe(true);
236244
expect(telemetry.getCommonProperties().device_id).toBe(undefined);
237245

238-
await telemetry.deviceIdPromise;
246+
await telemetry.setupPromise;
239247

240248
expect(telemetry["isBufferingEvents"]).toBe(false);
241249
expect(telemetry.getCommonProperties().device_id).toBe("unknown");
@@ -263,7 +271,7 @@ describe("Telemetry", () => {
263271

264272
jest.advanceTimersByTime(DEVICE_ID_TIMEOUT);
265273

266-
await telemetry.deviceIdPromise;
274+
await telemetry.setupPromise;
267275

268276
expect(telemetry.getCommonProperties().device_id).toBe("unknown");
269277
expect(telemetry["isBufferingEvents"]).toBe(false);

0 commit comments

Comments
 (0)