/
analytics.js
121 lines (110 loc) 路 3.35 KB
/
analytics.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// @flow strict-local
// flowlint-next-line untyped-import:off
import {analyticsClient, userTypes} from '@atlassiansox/analytics-node-client';
// flowlint-next-line untyped-import:off
import SegmentAnalytics from 'analytics-node';
import os from 'os';
import {hashString} from '@parcel/hash';
import getMachineModel from './getMachineModel';
const HASHED_EMAIL = hashString(`${os.userInfo().username}@${os.hostname()}`);
// Monkeypatch SegmentAnalytics not to create unhandled promise rejections.
// TODO: Remove when https://github.com/segmentio/analytics-node/issues/326
// is resolved
const originalSegmentAnalyticsFlush = SegmentAnalytics.prototype.flush;
SegmentAnalytics.prototype.flush = function flush(callback, ...rest) {
return originalSegmentAnalyticsFlush
.call(this, callback, ...rest)
.catch(err => {
callback(null, err);
});
};
let client;
if (
process.env.PARCEL_BUILD_ENV === 'production' &&
process.env.PARCEL_ANALYTICS_DISABLE == null
) {
client = analyticsClient({
env: 'prod',
product: 'parcel',
});
}
// This is inlined during the build process
const PARCEL_COMMIT = process.env.BITBUCKET_COMMIT;
const TOTAL_MEM = os.totalmem();
const CPUS = os.cpus();
const machineModelPromise = getMachineModel();
const analytics = {
track: async ({
action,
subject,
subjectId,
additionalAttributes,
}: {|
action: string,
subject: string,
subjectId?: ?string,
additionalAttributes: {[string]: mixed, ...},
|}): Promise<mixed> => {
const memoryUsage = process.memoryUsage();
const trackEvent = {
userId: HASHED_EMAIL,
userIdType: userTypes.HASHED_EMAIL,
trackEvent: {
source: 'analyticsReporter',
action,
actionSubject: subject,
actionSubjectId: subjectId,
attributes: {
...additionalAttributes,
timestamp: new Date(),
memoryRss: memoryUsage.rss,
memoryHeapTotal: memoryUsage.heapTotal,
memoryHeapUsed: memoryUsage.heapUsed,
memoryTotal: TOTAL_MEM,
parcelCommit: PARCEL_COMMIT ?? null,
machineModel: await machineModelPromise,
cpuCount: CPUS.length,
firstCpuModel: CPUS[0].model,
firstCpuSpeed: CPUS[0].speed,
},
},
os: {
name: os.platform(),
// $FlowFixMe[prop-missing] Added in Node 12.17.0
version: os.version(),
},
};
if (process.env.PARCEL_ANALYTICS_DEBUG != null) {
// eslint-disable-next-line no-console
console.log('analytics:track', trackEvent);
}
if (client != null) {
try {
await client.sendTrackEvent(trackEvent);
} catch (err) {
// Don't let a failure to report analytics crash Parcel
if (process.env.PARCEL_ANALYTICS_DEBUG != null) {
// eslint-disable-next-line no-console
console.error('Failed to send analytics', err);
}
}
}
},
trackSampled: (
sampleRate: number,
getEvent: () => {|
action: string,
subject: string,
subjectId: ?string,
additionalAttributes: {[string]: mixed, ...},
|},
): Promise<mixed> => {
if (Math.random() < 1 / sampleRate) {
const event = getEvent();
event.additionalAttributes.sampleRate = sampleRate;
return analytics.track(event);
}
return Promise.resolve();
},
};
export default analytics;