UNPKG

6.38 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.TelemetryManager = exports.MetricName = void 0;
4const tslib_1 = require("tslib");
5const fslib_1 = require("@yarnpkg/fslib");
6const httpUtils = tslib_1.__importStar(require("./httpUtils"));
7const miscUtils = tslib_1.__importStar(require("./miscUtils"));
8var MetricName;
9(function (MetricName) {
10 MetricName["VERSION"] = "version";
11 MetricName["COMMAND_NAME"] = "commandName";
12 MetricName["PLUGIN_NAME"] = "pluginName";
13 MetricName["INSTALL_COUNT"] = "installCount";
14 MetricName["PROJECT_COUNT"] = "projectCount";
15 MetricName["WORKSPACE_COUNT"] = "workspaceCount";
16 MetricName["DEPENDENCY_COUNT"] = "dependencyCount";
17 MetricName["EXTENSION"] = "packageExtension";
18})(MetricName = exports.MetricName || (exports.MetricName = {}));
19class TelemetryManager {
20 constructor(configuration, accountId) {
21 this.values = new Map();
22 this.hits = new Map();
23 this.enumerators = new Map();
24 this.configuration = configuration;
25 const registryFile = this.getRegistryPath();
26 this.isNew = !fslib_1.xfs.existsSync(registryFile);
27 this.sendReport(accountId);
28 this.startBuffer();
29 }
30 reportVersion(value) {
31 this.reportValue(MetricName.VERSION, value);
32 }
33 reportCommandName(value) {
34 this.reportValue(MetricName.COMMAND_NAME, value || `<none>`);
35 }
36 reportPluginName(value) {
37 this.reportValue(MetricName.PLUGIN_NAME, value);
38 }
39 reportProject(cwd) {
40 this.reportEnumerator(MetricName.PROJECT_COUNT, cwd);
41 }
42 reportInstall(nodeLinker) {
43 this.reportHit(MetricName.INSTALL_COUNT, nodeLinker);
44 }
45 reportPackageExtension(value) {
46 this.reportValue(MetricName.EXTENSION, value);
47 }
48 reportWorkspaceCount(count) {
49 this.reportValue(MetricName.WORKSPACE_COUNT, String(count));
50 }
51 reportDependencyCount(count) {
52 this.reportValue(MetricName.DEPENDENCY_COUNT, String(count));
53 }
54 reportValue(metric, value) {
55 miscUtils.getSetWithDefault(this.values, metric).add(value);
56 }
57 reportEnumerator(metric, value) {
58 miscUtils.getSetWithDefault(this.enumerators, metric).add(value);
59 }
60 reportHit(metric, extra = `*`) {
61 const ns = miscUtils.getMapWithDefault(this.hits, metric);
62 const current = miscUtils.getFactoryWithDefault(ns, extra, () => 0);
63 ns.set(extra, current + 1);
64 }
65 getRegistryPath() {
66 const registryFile = this.configuration.get(`globalFolder`);
67 return fslib_1.ppath.join(registryFile, `telemetry.json`);
68 }
69 sendReport(accountId) {
70 var _a, _b, _c;
71 const registryFile = this.getRegistryPath();
72 let content;
73 try {
74 content = fslib_1.xfs.readJsonSync(registryFile);
75 }
76 catch (_d) {
77 content = {};
78 }
79 const now = Date.now();
80 const interval = this.configuration.get(`telemetryInterval`) * 24 * 60 * 60 * 1000;
81 const lastUpdate = (_a = content.lastUpdate) !== null && _a !== void 0 ? _a : now + interval + Math.floor(interval * Math.random());
82 const nextUpdate = lastUpdate + interval;
83 if (nextUpdate > now && content.lastUpdate != null)
84 return;
85 try {
86 fslib_1.xfs.mkdirSync(fslib_1.ppath.dirname(registryFile), { recursive: true });
87 fslib_1.xfs.writeJsonSync(registryFile, { lastUpdate: now });
88 }
89 catch (_e) {
90 // In some cases this location is read-only. Too bad 🤷‍♀️
91 return;
92 }
93 if (nextUpdate > now)
94 return;
95 if (!content.blocks)
96 return;
97 for (const [userId, block] of Object.entries((_b = content.blocks) !== null && _b !== void 0 ? _b : {})) {
98 if (Object.keys(block).length === 0)
99 continue;
100 const upload = block;
101 upload.userId = userId;
102 for (const key of Object.keys((_c = upload.enumerators) !== null && _c !== void 0 ? _c : {}))
103 upload.enumerators[key] = upload.enumerators[key].length;
104 const rawUrl = `https://browser-http-intake.logs.datadoghq.eu/v1/input/${accountId}?ddsource=yarn`;
105 httpUtils.post(rawUrl, upload, {
106 configuration: this.configuration,
107 }).catch(() => {
108 // Nothing we can do
109 });
110 }
111 }
112 applyChanges() {
113 var _a, _b, _c, _d, _e, _f, _g, _h, _j;
114 const registryFile = this.getRegistryPath();
115 let content;
116 try {
117 content = fslib_1.xfs.readJsonSync(registryFile);
118 }
119 catch (_k) {
120 content = {};
121 }
122 const userId = (_a = this.configuration.get(`telemetryUserId`)) !== null && _a !== void 0 ? _a : `*`;
123 const blocks = content.blocks = (_b = content.blocks) !== null && _b !== void 0 ? _b : {};
124 const block = blocks[userId] = (_c = blocks[userId]) !== null && _c !== void 0 ? _c : {};
125 for (const key of this.hits.keys()) {
126 const store = block.hits = (_d = block.hits) !== null && _d !== void 0 ? _d : {};
127 const ns = store[key] = (_e = store[key]) !== null && _e !== void 0 ? _e : {};
128 for (const [extra, value] of this.hits.get(key)) {
129 ns[extra] = ((_f = ns[extra]) !== null && _f !== void 0 ? _f : 0) + value;
130 }
131 }
132 for (const field of [`values`, `enumerators`]) {
133 for (const key of this[field].keys()) {
134 const store = block[field] = (_g = block[field]) !== null && _g !== void 0 ? _g : {};
135 store[key] = [...new Set([
136 ...(_h = store[key]) !== null && _h !== void 0 ? _h : [],
137 ...(_j = this[field].get(key)) !== null && _j !== void 0 ? _j : [],
138 ])];
139 }
140 }
141 fslib_1.xfs.mkdirSync(fslib_1.ppath.dirname(registryFile), { recursive: true });
142 fslib_1.xfs.writeJsonSync(registryFile, content);
143 }
144 startBuffer() {
145 process.on(`exit`, () => {
146 try {
147 this.applyChanges();
148 }
149 catch (_a) {
150 // Explicitly ignore errors
151 }
152 });
153 }
154}
155exports.TelemetryManager = TelemetryManager;