@@ -7,6 +7,7 @@ import { MACHINE_METADATA } from "./constants.js";
77import { EventCache } from "./eventCache.js" ;
88import nodeMachineId from "node-machine-id" ;
99import { getDeviceId } from "@mongodb-js/device-id" ;
10+ import fs from "fs/promises" ;
1011
1112type EventResult = {
1213 success : boolean ;
@@ -17,8 +18,8 @@ export const DEVICE_ID_TIMEOUT = 3000;
1718
1819export 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 }
0 commit comments