|
1 | | -import * as os from "os"; |
2 | | -import * as fs from "fs"; |
3 | | -import * as path from "path"; |
4 | | -import { v4 as uuid } from "uuid"; |
5 | | -import { PostHog } from "posthog-node"; |
6 | | -import * as process from "process"; |
7 | | - |
8 | | -export class Telemetry { |
9 | | - private static instance: Telemetry; |
10 | | - private static readonly ANON_ID_PATH = `${os.homedir()}/.cache/honeyhive/telemetry_anon_id`; |
11 | | - private static readonly UNKNOWN_ANON_ID = "UNKNOWN"; |
12 | | - private telemetryEnabled: boolean; |
13 | | - private posthog: PostHog | undefined; |
14 | | - private anonId: string | undefined; |
15 | | - |
16 | | - public static getInstance(): Telemetry { |
17 | | - if (!Telemetry.instance) { |
18 | | - Telemetry.instance = new Telemetry(); |
19 | | - } |
20 | | - return Telemetry.instance; |
21 | | - } |
22 | | - |
23 | | - private constructor() { |
24 | | - this.telemetryEnabled = |
25 | | - !process.env['HONEYHIVE_TELEMETRY'] || |
26 | | - process.env['HONEYHIVE_TELEMETRY']?.toLowerCase() === "true"; |
27 | | - if (this.telemetryEnabled) { |
28 | | - this.posthog = new PostHog( |
29 | | - "phc_yeqaIP07fjwZ5n3w47wPtSz7G58igfczuQ9X3zKhuxa", |
30 | | - { |
31 | | - host:'https://us.i.posthog.com' |
32 | | - } |
33 | | - ); |
34 | | - } |
35 | | - } |
36 | | - |
37 | | - private getAnonId(): string { |
38 | | - if (this.anonId) { |
39 | | - return this.anonId; |
40 | | - } |
41 | | - try { |
42 | | - if (!fs.existsSync(Telemetry.ANON_ID_PATH)) { |
43 | | - fs.mkdirSync(path.dirname(Telemetry.ANON_ID_PATH), { recursive: true }); |
44 | | - const anonIdFile = fs.openSync(Telemetry.ANON_ID_PATH, "w"); |
45 | | - this.anonId = uuid(); |
46 | | - fs.writeSync(anonIdFile, this.anonId as string); |
47 | | - fs.closeSync(anonIdFile); |
48 | | - } else { |
49 | | - const anonIdFile = fs.openSync(Telemetry.ANON_ID_PATH, "r"); |
50 | | - this.anonId = fs.readFileSync(anonIdFile, "utf8"); |
51 | | - fs.closeSync(anonIdFile); |
52 | | - } |
53 | | - return this.anonId || Telemetry.UNKNOWN_ANON_ID; |
54 | | - } catch (e) { |
55 | | - return Telemetry.UNKNOWN_ANON_ID; |
56 | | - } |
57 | | - } |
58 | | - |
59 | | - private getHoneyhiveVersion(): string { |
60 | | - try { |
61 | | - const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../package.json'), 'utf8')); |
62 | | - return packageJson.version; |
63 | | - } catch (e) { |
64 | | - return "Not installed"; |
65 | | - } |
66 | | - } |
67 | | - |
68 | | - private getContext(): Record<string, any> { |
69 | | - return { |
70 | | - sdk: "honeyhive", |
71 | | - sdk_version: this.getHoneyhiveVersion(), |
72 | | - language: { |
73 | | - name: "typescript", |
74 | | - version: process.version, |
75 | | - runtime: "Node.js", |
76 | | - }, |
77 | | - runtime: this.getRuntimeInfo(), |
78 | | - os: { |
79 | | - name: os.type(), |
80 | | - release: os.release(), |
81 | | - version: os.version(), |
82 | | - }, |
83 | | - chip: { |
84 | | - architecture: os.arch(), |
85 | | - processor: os.cpus()[0]?.model || "Unknown", |
86 | | - }, |
87 | | - user_agent: this.getUserAgent(), |
88 | | - service_provider_info: this.getServiceProviderInfo(), |
89 | | - notebook_info: this.getNotebookInfo(), |
90 | | - execution_info: this.getExecutionInfo(), |
91 | | - }; |
92 | | - } |
93 | | - |
94 | | - private getRuntimeInfo(): Record<string, string> { |
95 | | - const runtimeInfo: Record<string, string> = {}; |
96 | | - |
97 | | - if (process.env['AWS_LAMBDA_FUNCTION_NAME']) { |
98 | | - runtimeInfo['environment'] = 'AWS Lambda'; |
99 | | - } else if (process.env['AZURE_FUNCTIONS_ENVIRONMENT']) { |
100 | | - runtimeInfo['environment'] = 'Azure Functions'; |
101 | | - } else if (process.env['GOOGLE_CLOUD_PROJECT']) { |
102 | | - runtimeInfo['environment'] = 'Google Cloud Functions'; |
103 | | - } else { |
104 | | - runtimeInfo['environment'] = 'Unknown'; |
105 | | - } |
106 | | - |
107 | | - // You may want to add detection for server-side frameworks here |
108 | | - // This might require checking for specific packages in package.json |
109 | | - |
110 | | - return runtimeInfo; |
111 | | - } |
112 | | - |
113 | | - private getUserAgent(): string { |
114 | | - return `Node.js/${process.version}`; |
115 | | - } |
116 | | - |
117 | | - private getServiceProviderInfo(): Record<string, any> { |
118 | | - // In a real implementation, you might want to use a library like 'axios' to make an HTTP request |
119 | | - // to ipinfo.io. For this example, we'll return a placeholder. |
120 | | - return { note: "Service provider info not implemented in TypeScript version" }; |
121 | | - } |
122 | | - |
123 | | - private getNotebookInfo(): Record<string, any> { |
124 | | - // Detecting notebook environments in Node.js is not as straightforward as in Python |
125 | | - // You might want to check for specific environment variables or installed packages |
126 | | - return { in_notebook: false, environment: 'standard_nodejs' }; |
127 | | - } |
128 | | - |
129 | | - private getExecutionInfo(): Record<string, any> { |
130 | | - return { |
131 | | - executable: process.execPath, |
132 | | - argv: process.argv, |
133 | | - execution_method: this.getExecutionMethod(), |
134 | | - }; |
135 | | - } |
136 | | - |
137 | | - private getExecutionMethod(): string { |
138 | | - const execPath = process.argv[0]?.toLowerCase() ?? ''; |
139 | | - if (execPath.includes('node')) { |
140 | | - return 'nodejs'; |
141 | | - } else if (execPath.includes('npm')) { |
142 | | - return 'npm'; |
143 | | - } else if (execPath.includes('yarn')) { |
144 | | - return 'yarn'; |
145 | | - } else if (execPath.includes('ts-node')) { |
146 | | - return 'ts-node'; |
147 | | - } else { |
148 | | - return 'unknown'; |
149 | | - } |
150 | | - } |
151 | | - |
152 | | - public async capture(event: string, properties?: Record<string, any>): Promise<void> { |
153 | | - if (this.telemetryEnabled && this.posthog) { |
154 | | - const posthogPayload = { |
155 | | - distinctId: this.getAnonId(), |
156 | | - event, |
157 | | - properties: { |
158 | | - ...properties, |
159 | | - ...this.getContext(), |
160 | | - }, |
161 | | - }; |
162 | | - this.posthog.capture(posthogPayload); |
163 | | - await this.posthog.shutdown(); |
164 | | - } |
165 | | - } |
166 | | - |
167 | | - public logException(error: Error): void { |
168 | | - if (this.telemetryEnabled) { |
169 | | - this.capture("error", { error: error.message, stack: error.stack || "" }); |
170 | | - } |
171 | | - } |
172 | | -} |
| 1 | +// import * as os from "os"; |
| 2 | +// import * as fs from "fs"; |
| 3 | +// import * as path from "path"; |
| 4 | +// import { v4 as uuid } from "uuid"; |
| 5 | +// import { PostHog } from "posthog-node"; |
| 6 | +// import * as process from "process"; |
| 7 | + |
| 8 | +// export class Telemetry { |
| 9 | +// private static instance: Telemetry; |
| 10 | +// private static readonly ANON_ID_PATH = `${os.homedir()}/.cache/honeyhive/telemetry_anon_id`; |
| 11 | +// private static readonly UNKNOWN_ANON_ID = "UNKNOWN"; |
| 12 | +// private telemetryEnabled: boolean; |
| 13 | +// private posthog: PostHog | undefined; |
| 14 | +// private anonId: string | undefined; |
| 15 | + |
| 16 | +// public static getInstance(): Telemetry { |
| 17 | +// if (!Telemetry.instance) { |
| 18 | +// Telemetry.instance = new Telemetry(); |
| 19 | +// } |
| 20 | +// return Telemetry.instance; |
| 21 | +// } |
| 22 | + |
| 23 | +// private constructor() { |
| 24 | +// this.telemetryEnabled = |
| 25 | +// !process.env['HONEYHIVE_TELEMETRY'] || |
| 26 | +// process.env['HONEYHIVE_TELEMETRY']?.toLowerCase() === "true"; |
| 27 | +// if (this.telemetryEnabled) { |
| 28 | +// this.posthog = new PostHog( |
| 29 | +// "phc_yeqaIP07fjwZ5n3w47wPtSz7G58igfczuQ9X3zKhuxa", |
| 30 | +// { |
| 31 | +// host:'https://us.i.posthog.com' |
| 32 | +// } |
| 33 | +// ); |
| 34 | +// } |
| 35 | +// } |
| 36 | + |
| 37 | +// private getAnonId(): string { |
| 38 | +// if (this.anonId) { |
| 39 | +// return this.anonId; |
| 40 | +// } |
| 41 | +// try { |
| 42 | +// if (!fs.existsSync(Telemetry.ANON_ID_PATH)) { |
| 43 | +// fs.mkdirSync(path.dirname(Telemetry.ANON_ID_PATH), { recursive: true }); |
| 44 | +// const anonIdFile = fs.openSync(Telemetry.ANON_ID_PATH, "w"); |
| 45 | +// this.anonId = uuid(); |
| 46 | +// fs.writeSync(anonIdFile, this.anonId as string); |
| 47 | +// fs.closeSync(anonIdFile); |
| 48 | +// } else { |
| 49 | +// const anonIdFile = fs.openSync(Telemetry.ANON_ID_PATH, "r"); |
| 50 | +// this.anonId = fs.readFileSync(anonIdFile, "utf8"); |
| 51 | +// fs.closeSync(anonIdFile); |
| 52 | +// } |
| 53 | +// return this.anonId || Telemetry.UNKNOWN_ANON_ID; |
| 54 | +// } catch (e) { |
| 55 | +// return Telemetry.UNKNOWN_ANON_ID; |
| 56 | +// } |
| 57 | +// } |
| 58 | + |
| 59 | +// private getHoneyhiveVersion(): string { |
| 60 | +// try { |
| 61 | +// const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../package.json'), 'utf8')); |
| 62 | +// return packageJson.version; |
| 63 | +// } catch (e) { |
| 64 | +// return "Not installed"; |
| 65 | +// } |
| 66 | +// } |
| 67 | + |
| 68 | +// private getContext(): Record<string, any> { |
| 69 | +// return { |
| 70 | +// sdk: "honeyhive", |
| 71 | +// sdk_version: this.getHoneyhiveVersion(), |
| 72 | +// language: { |
| 73 | +// name: "typescript", |
| 74 | +// version: process.version, |
| 75 | +// runtime: "Node.js", |
| 76 | +// }, |
| 77 | +// runtime: this.getRuntimeInfo(), |
| 78 | +// os: { |
| 79 | +// name: os.type(), |
| 80 | +// release: os.release(), |
| 81 | +// version: os.version(), |
| 82 | +// }, |
| 83 | +// chip: { |
| 84 | +// architecture: os.arch(), |
| 85 | +// processor: os.cpus()[0]?.model || "Unknown", |
| 86 | +// }, |
| 87 | +// user_agent: this.getUserAgent(), |
| 88 | +// service_provider_info: this.getServiceProviderInfo(), |
| 89 | +// notebook_info: this.getNotebookInfo(), |
| 90 | +// execution_info: this.getExecutionInfo(), |
| 91 | +// }; |
| 92 | +// } |
| 93 | + |
| 94 | +// private getRuntimeInfo(): Record<string, string> { |
| 95 | +// const runtimeInfo: Record<string, string> = {}; |
| 96 | + |
| 97 | +// if (process.env['AWS_LAMBDA_FUNCTION_NAME']) { |
| 98 | +// runtimeInfo['environment'] = 'AWS Lambda'; |
| 99 | +// } else if (process.env['AZURE_FUNCTIONS_ENVIRONMENT']) { |
| 100 | +// runtimeInfo['environment'] = 'Azure Functions'; |
| 101 | +// } else if (process.env['GOOGLE_CLOUD_PROJECT']) { |
| 102 | +// runtimeInfo['environment'] = 'Google Cloud Functions'; |
| 103 | +// } else { |
| 104 | +// runtimeInfo['environment'] = 'Unknown'; |
| 105 | +// } |
| 106 | + |
| 107 | +// // You may want to add detection for server-side frameworks here |
| 108 | +// // This might require checking for specific packages in package.json |
| 109 | + |
| 110 | +// return runtimeInfo; |
| 111 | +// } |
| 112 | + |
| 113 | +// private getUserAgent(): string { |
| 114 | +// return `Node.js/${process.version}`; |
| 115 | +// } |
| 116 | + |
| 117 | +// private getServiceProviderInfo(): Record<string, any> { |
| 118 | +// // In a real implementation, you might want to use a library like 'axios' to make an HTTP request |
| 119 | +// // to ipinfo.io. For this example, we'll return a placeholder. |
| 120 | +// return { note: "Service provider info not implemented in TypeScript version" }; |
| 121 | +// } |
| 122 | + |
| 123 | +// private getNotebookInfo(): Record<string, any> { |
| 124 | +// // Detecting notebook environments in Node.js is not as straightforward as in Python |
| 125 | +// // You might want to check for specific environment variables or installed packages |
| 126 | +// return { in_notebook: false, environment: 'standard_nodejs' }; |
| 127 | +// } |
| 128 | + |
| 129 | +// private getExecutionInfo(): Record<string, any> { |
| 130 | +// return { |
| 131 | +// executable: process.execPath, |
| 132 | +// argv: process.argv, |
| 133 | +// execution_method: this.getExecutionMethod(), |
| 134 | +// }; |
| 135 | +// } |
| 136 | + |
| 137 | +// private getExecutionMethod(): string { |
| 138 | +// const execPath = process.argv[0]?.toLowerCase() ?? ''; |
| 139 | +// if (execPath.includes('node')) { |
| 140 | +// return 'nodejs'; |
| 141 | +// } else if (execPath.includes('npm')) { |
| 142 | +// return 'npm'; |
| 143 | +// } else if (execPath.includes('yarn')) { |
| 144 | +// return 'yarn'; |
| 145 | +// } else if (execPath.includes('ts-node')) { |
| 146 | +// return 'ts-node'; |
| 147 | +// } else { |
| 148 | +// return 'unknown'; |
| 149 | +// } |
| 150 | +// } |
| 151 | + |
| 152 | +// public async capture(event: string, properties?: Record<string, any>): Promise<void> { |
| 153 | +// if (this.telemetryEnabled && this.posthog) { |
| 154 | +// const posthogPayload = { |
| 155 | +// distinctId: this.getAnonId(), |
| 156 | +// event, |
| 157 | +// properties: { |
| 158 | +// ...properties, |
| 159 | +// ...this.getContext(), |
| 160 | +// }, |
| 161 | +// }; |
| 162 | +// this.posthog.capture(posthogPayload); |
| 163 | +// } |
| 164 | +// } |
| 165 | + |
| 166 | +// /** |
| 167 | +// * Call this method when you're done with telemetry and want to ensure all events are flushed |
| 168 | +// * This should typically only be called when your application is shutting down |
| 169 | +// */ |
| 170 | +// public async shutdown(): Promise<void> { |
| 171 | +// if (this.telemetryEnabled && this.posthog) { |
| 172 | +// await this.posthog.shutdown(); |
| 173 | +// } |
| 174 | +// } |
| 175 | + |
| 176 | +// public logException(error: Error): void { |
| 177 | +// if (this.telemetryEnabled) { |
| 178 | +// this.capture("error", { error: error.message, stack: error.stack || "" }); |
| 179 | +// } |
| 180 | +// } |
| 181 | +// } |
0 commit comments