mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-23 20:40:41 -07:00
Collect hardware details telemetry. (#16119)
This commit is contained in:
committed by
GitHub
parent
e9c9dd1d67
commit
6ef2a92233
68
package-lock.json
generated
68
package-lock.json
generated
@@ -2501,7 +2501,6 @@
|
||||
"integrity": "sha512-t54CUOsFMappY1Jbzb7fetWeO0n6K0k/4+/ZpkS+3Joz8I4VcvY9OiEBFRYISqaI2fq5sCiPtAjRDOzVYG8m+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^6.0.0",
|
||||
"@octokit/graphql": "^9.0.2",
|
||||
@@ -2682,7 +2681,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
|
||||
"integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
@@ -2716,7 +2714,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz",
|
||||
"integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@opentelemetry/semantic-conventions": "^1.29.0"
|
||||
},
|
||||
@@ -3085,7 +3082,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz",
|
||||
"integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@opentelemetry/core": "2.0.1",
|
||||
"@opentelemetry/semantic-conventions": "^1.29.0"
|
||||
@@ -3119,7 +3115,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz",
|
||||
"integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@opentelemetry/core": "2.0.1",
|
||||
"@opentelemetry/resources": "2.0.1"
|
||||
@@ -3172,7 +3167,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz",
|
||||
"integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@opentelemetry/core": "2.0.1",
|
||||
"@opentelemetry/resources": "2.0.1",
|
||||
@@ -4410,7 +4404,6 @@
|
||||
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
@@ -4688,7 +4681,6 @@
|
||||
"integrity": "sha512-6sMvZePQrnZH2/cJkwRpkT7DxoAWh+g6+GFRK6bV3YQo7ogi3SX5rgF6099r5Q53Ma5qeT7LGmOmuIutF4t3lA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.35.0",
|
||||
"@typescript-eslint/types": "8.35.0",
|
||||
@@ -5700,7 +5692,6 @@
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -6145,7 +6136,8 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/array-includes": {
|
||||
"version": "3.1.9",
|
||||
@@ -7433,6 +7425,7 @@
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"safe-buffer": "5.2.1"
|
||||
},
|
||||
@@ -8755,7 +8748,6 @@
|
||||
"integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
@@ -9360,6 +9352,7 @@
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
|
||||
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
@@ -9369,6 +9362,7 @@
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
@@ -9378,6 +9372,7 @@
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
@@ -9631,6 +9626,7 @@
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
|
||||
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"encodeurl": "~2.0.0",
|
||||
@@ -9649,6 +9645,7 @@
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
@@ -9657,13 +9654,15 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/finalhandler/node_modules/statuses": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
@@ -10947,7 +10946,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@jrichman/ink/-/ink-6.4.7.tgz",
|
||||
"integrity": "sha512-QHyxhNF5VonF5cRmdAJD/UPucB9nRx3FozWMjQrDGfBxfAL9lpyu72/MlFPgloS1TMTGsOt7YN6dTPPA6mh0Aw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@alcalzone/ansi-tokenize": "^0.2.1",
|
||||
"ansi-escapes": "^7.0.0",
|
||||
@@ -14136,7 +14134,8 @@
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/path-type": {
|
||||
"version": "3.0.0",
|
||||
@@ -14716,7 +14715,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
|
||||
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -14727,7 +14725,6 @@
|
||||
"integrity": "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"shell-quote": "^1.6.1",
|
||||
"ws": "^7"
|
||||
@@ -16547,6 +16544,32 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/systeminformation": {
|
||||
"version": "5.30.2",
|
||||
"resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.30.2.tgz",
|
||||
"integrity": "sha512-Rrt5oFTWluUVuPlbtn3o9ja+nvjdF3Um4DG0KxqfYvpzcx7Q9plZBTjJiJy9mAouua4+OI7IUGBaG9Zyt9NgxA==",
|
||||
"license": "MIT",
|
||||
"os": [
|
||||
"darwin",
|
||||
"linux",
|
||||
"win32",
|
||||
"freebsd",
|
||||
"openbsd",
|
||||
"netbsd",
|
||||
"sunos",
|
||||
"android"
|
||||
],
|
||||
"bin": {
|
||||
"systeminformation": "lib/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "Buy me a coffee",
|
||||
"url": "https://www.buymeacoffee.com/systeminfo"
|
||||
}
|
||||
},
|
||||
"node_modules/table": {
|
||||
"version": "6.9.0",
|
||||
"resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz",
|
||||
@@ -16972,7 +16995,6 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -17199,8 +17221,7 @@
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"dev": true,
|
||||
"license": "0BSD",
|
||||
"peer": true
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/tsx": {
|
||||
"version": "4.20.3",
|
||||
@@ -17208,7 +17229,6 @@
|
||||
"integrity": "sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "~0.25.0",
|
||||
"get-tsconfig": "^4.7.5"
|
||||
@@ -17392,7 +17412,6 @@
|
||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -17555,6 +17574,7 @@
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
@@ -17610,7 +17630,6 @@
|
||||
"integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.5.0",
|
||||
@@ -17727,7 +17746,6 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -17741,7 +17759,6 @@
|
||||
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/expect": "3.2.4",
|
||||
@@ -18448,7 +18465,6 @@
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
@@ -18923,6 +18939,7 @@
|
||||
"shell-quote": "^1.8.3",
|
||||
"simple-git": "^3.28.0",
|
||||
"strip-ansi": "^7.1.0",
|
||||
"systeminformation": "^5.25.11",
|
||||
"tree-sitter-bash": "^0.25.0",
|
||||
"undici": "^7.10.0",
|
||||
"uuid": "^13.0.0",
|
||||
@@ -19013,7 +19030,6 @@
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
"shell-quote": "^1.8.3",
|
||||
"simple-git": "^3.28.0",
|
||||
"strip-ansi": "^7.1.0",
|
||||
"systeminformation": "^5.25.11",
|
||||
"tree-sitter-bash": "^0.25.0",
|
||||
"undici": "^7.10.0",
|
||||
"uuid": "^13.0.0",
|
||||
|
||||
@@ -26,6 +26,7 @@ import { makeFakeConfig } from '../../test-utils/config.js';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
import { server } from '../../mocks/msw.js';
|
||||
import {
|
||||
StartSessionEvent,
|
||||
UserPromptEvent,
|
||||
makeChatCompressionEvent,
|
||||
ModelRoutingEvent,
|
||||
@@ -40,6 +41,9 @@ import { GIT_COMMIT_INFO, CLI_VERSION } from '../../generated/git-commit.js';
|
||||
import { UserAccountManager } from '../../utils/userAccountManager.js';
|
||||
import { InstallationManager } from '../../utils/installationManager.js';
|
||||
|
||||
import si from 'systeminformation';
|
||||
import type { Systeminformation } from 'systeminformation';
|
||||
|
||||
interface CustomMatchers<R = unknown> {
|
||||
toHaveMetadataValue: ([key, value]: [EventMetadataKey, string]) => R;
|
||||
toHaveEventName: (name: EventNames) => R;
|
||||
@@ -111,8 +115,24 @@ expect.extend({
|
||||
},
|
||||
});
|
||||
|
||||
vi.mock('node:os', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('node:os')>();
|
||||
return {
|
||||
...actual,
|
||||
cpus: vi.fn(() => [{ model: 'Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz' }]),
|
||||
totalmem: vi.fn(() => 32 * 1024 * 1024 * 1024),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('../../utils/userAccountManager.js');
|
||||
vi.mock('../../utils/installationManager.js');
|
||||
vi.mock('systeminformation', () => ({
|
||||
default: {
|
||||
graphics: vi.fn().mockResolvedValue({
|
||||
controllers: [{ model: 'Mock GPU' }],
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
const mockUserAccount = vi.mocked(UserAccountManager.prototype);
|
||||
const mockInstallMgr = vi.mocked(InstallationManager.prototype);
|
||||
@@ -204,6 +224,7 @@ describe('ClearcutLogger', () => {
|
||||
|
||||
afterEach(() => {
|
||||
ClearcutLogger.clearInstance();
|
||||
TEST_ONLY.resetCachedGpuInfoForTesting();
|
||||
vi.useRealTimers();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
@@ -238,7 +259,7 @@ describe('ClearcutLogger', () => {
|
||||
});
|
||||
|
||||
describe('createLogEvent', () => {
|
||||
it('logs the total number of google accounts', () => {
|
||||
it('logs the total number of google accounts', async () => {
|
||||
const { logger } = setup({
|
||||
lifetimeGoogleAccounts: 9001,
|
||||
});
|
||||
@@ -346,6 +367,73 @@ describe('ClearcutLogger', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('logs the GPU information (single GPU)', async () => {
|
||||
vi.mocked(si.graphics).mockResolvedValueOnce({
|
||||
controllers: [{ model: 'Single GPU' }],
|
||||
} as unknown as Systeminformation.GraphicsData);
|
||||
const { logger, loggerConfig } = setup({});
|
||||
|
||||
await logger?.logStartSessionEvent(new StartSessionEvent(loggerConfig));
|
||||
|
||||
const event = logger?.createLogEvent(EventNames.API_ERROR, []);
|
||||
|
||||
const gpuInfoEntry = event?.event_metadata[0].find(
|
||||
(item) => item.gemini_cli_key === EventMetadataKey.GEMINI_CLI_GPU_INFO,
|
||||
);
|
||||
expect(gpuInfoEntry).toBeDefined();
|
||||
expect(gpuInfoEntry?.value).toBe('Single GPU');
|
||||
});
|
||||
|
||||
it('logs multiple GPUs', async () => {
|
||||
vi.mocked(si.graphics).mockResolvedValueOnce({
|
||||
controllers: [{ model: 'GPU 1' }, { model: 'GPU 2' }],
|
||||
} as unknown as Systeminformation.GraphicsData);
|
||||
const { logger, loggerConfig } = setup({});
|
||||
|
||||
await logger?.logStartSessionEvent(new StartSessionEvent(loggerConfig));
|
||||
|
||||
const event = logger?.createLogEvent(EventNames.API_ERROR, []);
|
||||
const metadata = event?.event_metadata[0];
|
||||
|
||||
const gpuInfoEntry = metadata?.find(
|
||||
(m) => m.gemini_cli_key === EventMetadataKey.GEMINI_CLI_GPU_INFO,
|
||||
);
|
||||
expect(gpuInfoEntry?.value).toBe('GPU 1, GPU 2');
|
||||
});
|
||||
|
||||
it('logs NA when no GPUs are found', async () => {
|
||||
vi.mocked(si.graphics).mockResolvedValueOnce({
|
||||
controllers: [],
|
||||
} as unknown as Systeminformation.GraphicsData);
|
||||
const { logger, loggerConfig } = setup({});
|
||||
|
||||
await logger?.logStartSessionEvent(new StartSessionEvent(loggerConfig));
|
||||
|
||||
const event = logger?.createLogEvent(EventNames.API_ERROR, []);
|
||||
const metadata = event?.event_metadata[0];
|
||||
|
||||
const gpuInfoEntry = metadata?.find(
|
||||
(m) => m.gemini_cli_key === EventMetadataKey.GEMINI_CLI_GPU_INFO,
|
||||
);
|
||||
expect(gpuInfoEntry?.value).toBe('NA');
|
||||
});
|
||||
|
||||
it('logs FAILED when GPU detection fails', async () => {
|
||||
vi.mocked(si.graphics).mockRejectedValueOnce(
|
||||
new Error('Detection failed'),
|
||||
);
|
||||
const { logger, loggerConfig } = setup({});
|
||||
|
||||
await logger?.logStartSessionEvent(new StartSessionEvent(loggerConfig));
|
||||
|
||||
const event = logger?.createLogEvent(EventNames.API_ERROR, []);
|
||||
|
||||
expect(event?.event_metadata[0]).toContainEqual({
|
||||
gemini_cli_key: EventMetadataKey.GEMINI_CLI_GPU_INFO,
|
||||
value: 'FAILED',
|
||||
});
|
||||
});
|
||||
|
||||
type SurfaceDetectionTestCase = {
|
||||
name: string;
|
||||
env: Record<string, string | undefined>;
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
|
||||
import { createHash } from 'node:crypto';
|
||||
import * as os from 'node:os';
|
||||
import si from 'systeminformation';
|
||||
import { HttpsProxyAgent } from 'https-proxy-agent';
|
||||
import type {
|
||||
StartSessionEvent,
|
||||
@@ -57,6 +59,7 @@ import {
|
||||
isCloudShell,
|
||||
} from '../../ide/detect-ide.js';
|
||||
import { debugLogger } from '../../utils/debugLogger.js';
|
||||
import { getErrorMessage } from '../../utils/errors.js';
|
||||
|
||||
export enum EventNames {
|
||||
START_SESSION = 'start_session',
|
||||
@@ -190,6 +193,35 @@ const MAX_EVENTS = 1000;
|
||||
*/
|
||||
const MAX_RETRY_EVENTS = 100;
|
||||
|
||||
const NO_GPU = 'NA';
|
||||
|
||||
let cachedGpuInfo: string | undefined;
|
||||
|
||||
async function refreshGpuInfo(): Promise<void> {
|
||||
try {
|
||||
const graphics = await si.graphics();
|
||||
if (graphics.controllers && graphics.controllers.length > 0) {
|
||||
cachedGpuInfo = graphics.controllers.map((c) => c.model).join(', ');
|
||||
} else {
|
||||
cachedGpuInfo = NO_GPU;
|
||||
}
|
||||
} catch (error) {
|
||||
cachedGpuInfo = 'FAILED';
|
||||
debugLogger.error(
|
||||
'Failed to get GPU information for telemetry',
|
||||
getErrorMessage(error),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function getGpuInfo(): Promise<string> {
|
||||
if (!cachedGpuInfo) {
|
||||
await refreshGpuInfo();
|
||||
}
|
||||
|
||||
return cachedGpuInfo ?? NO_GPU;
|
||||
}
|
||||
|
||||
// Singleton class for batch posting log events to Clearcut. When a new event comes in, the elapsed time
|
||||
// is checked and events are flushed to Clearcut if at least a minute has passed since the last flush.
|
||||
export class ClearcutLogger {
|
||||
@@ -321,7 +353,6 @@ export class ClearcutLogger {
|
||||
const email = this.userAccountManager.getCachedGoogleAccount();
|
||||
const surface = determineSurface();
|
||||
const ghWorkflowName = determineGHWorkflowName();
|
||||
|
||||
const baseMetadata: EventValue[] = [
|
||||
...data,
|
||||
{
|
||||
@@ -475,7 +506,7 @@ export class ClearcutLogger {
|
||||
return result;
|
||||
}
|
||||
|
||||
logStartSessionEvent(event: StartSessionEvent): void {
|
||||
async logStartSessionEvent(event: StartSessionEvent): Promise<void> {
|
||||
const data: EventValue[] = [
|
||||
{
|
||||
gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_MODEL,
|
||||
@@ -564,6 +595,29 @@ export class ClearcutLogger {
|
||||
value: event.extension_ids.toString(),
|
||||
},
|
||||
];
|
||||
|
||||
// Add hardware information only to the start session event
|
||||
const cpus = os.cpus();
|
||||
data.push(
|
||||
{
|
||||
gemini_cli_key: EventMetadataKey.GEMINI_CLI_CPU_INFO,
|
||||
value: cpus[0].model,
|
||||
},
|
||||
{
|
||||
gemini_cli_key: EventMetadataKey.GEMINI_CLI_CPU_CORES,
|
||||
value: cpus.length.toString(),
|
||||
},
|
||||
{
|
||||
gemini_cli_key: EventMetadataKey.GEMINI_CLI_RAM_TOTAL_GB,
|
||||
value: (os.totalmem() / 1024 ** 3).toFixed(2).toString(),
|
||||
},
|
||||
);
|
||||
|
||||
const gpuInfo = await getGpuInfo();
|
||||
data.push({
|
||||
gemini_cli_key: EventMetadataKey.GEMINI_CLI_GPU_INFO,
|
||||
value: gpuInfo,
|
||||
});
|
||||
this.sessionData = data;
|
||||
|
||||
// Flush after experiments finish loading from CCPA server
|
||||
@@ -1533,4 +1587,8 @@ export class ClearcutLogger {
|
||||
export const TEST_ONLY = {
|
||||
MAX_RETRY_EVENTS,
|
||||
MAX_EVENTS,
|
||||
refreshGpuInfo,
|
||||
resetCachedGpuInfoForTesting: () => {
|
||||
cachedGpuInfo = undefined;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -517,4 +517,16 @@ export enum EventMetadataKey {
|
||||
|
||||
// Logs the exit code of the hook script (if applicable).
|
||||
GEMINI_CLI_HOOK_EXIT_CODE = 136,
|
||||
|
||||
// Logs CPU information of user machine.
|
||||
GEMINI_CLI_CPU_INFO = 137,
|
||||
|
||||
// Logs number of CPU cores of user machine.
|
||||
GEMINI_CLI_CPU_CORES = 138,
|
||||
|
||||
// Logs GPU information of user machine.
|
||||
GEMINI_CLI_GPU_INFO = 139,
|
||||
|
||||
// Logs total RAM in GB of user machine.
|
||||
GEMINI_CLI_RAM_TOTAL_GB = 140,
|
||||
}
|
||||
|
||||
@@ -111,6 +111,14 @@ import { UserAccountManager } from '../utils/userAccountManager.js';
|
||||
import { InstallationManager } from '../utils/installationManager.js';
|
||||
import { AgentTerminateMode } from '../agents/types.js';
|
||||
|
||||
vi.mock('systeminformation', () => ({
|
||||
default: {
|
||||
graphics: vi.fn().mockResolvedValue({
|
||||
controllers: [{ model: 'Mock GPU' }],
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('loggers', () => {
|
||||
const mockLogger = {
|
||||
emit: vi.fn(),
|
||||
|
||||
@@ -79,7 +79,7 @@ export function logCliConfiguration(
|
||||
config: Config,
|
||||
event: StartSessionEvent,
|
||||
): void {
|
||||
ClearcutLogger.getInstance(config)?.logStartSessionEvent(event);
|
||||
void ClearcutLogger.getInstance(config)?.logStartSessionEvent(event);
|
||||
bufferTelemetryEvent(() => {
|
||||
const logger = logs.getLogger(SERVICE_NAME);
|
||||
const logRecord: LogRecord = {
|
||||
|
||||
Reference in New Issue
Block a user