-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtracking.js
175 lines (145 loc) · 3.85 KB
/
tracking.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/**
* tracking - powered by google analytics setup to work on desktop
*
* TODO extract to own module
*/
"use strict";
const uuid = require('uuid');
const config = require("./persistentConfig");
const _ = require("lodash");
const universal = require("./universal");
const PREFIX = process.env.DEVELOPMENT ? "debug/" : "";
const debug = require("debug")("tracking");
var clientId;
var settings = require("./settings");
var setup = {
version: "unknown",
};
exports.start = function(setupTo) {
setup = setupTo;
}
exports.error = function(err) {
return send({
// type
t: "exception",
// description
exd: err.message + cleansedStackTrack(err),
// is it fatal or not?
exf: 0,
});
};
exports.pageView = function(page) {
return send({
// host name
dh: settings.analyticsPhonyDomain(),
// page
dp: cleanPage(page),
});
};
function cleanPage(page) {
return page.replace(/&?path=[^&=]+/g, "");
}
exports.angularIntegration = function($rootScope) {
$rootScope.$on('$viewContentLoaded', function() {
exports.pageView(getCurrentPage());
});
};
exports.event = function(category, action, options){
options = options || {};
const params = {
// type
t: "event",
// category
ec: category,
// action
ea: action,
};
if(options.label) {
params.el = options.label;
}
return send(params);
};
function getCurrentPage() {
return location.hash.slice(1);
}
function send(params) {
const completeParams = _.defaults({
tid: settings.googleAnalyticsUa(),
v: 1,
// anonymously id the client
cid: getClientId(),
// custom dimensions:
// cd1 = version
cd1: setup.version,
}, params);
return sendRequest(`https://www.google-analytics.com/${PREFIX}collect`, completeParams)
// the production measurement API does not supply error codes,
// so only errors we get in production are connect issues (I guess)
.then(function(res) {
if(!process.env.DEVELOPMENT) {
return;
}
// we're only sending 1 hit
const result = res.data.hitParsingResult[0];
if(result.valid) {
return;
} else {
debug("could not send analytics: " + JSON.stringify(result, null, 4));
throw new Error(JSON.stringify(result.parserMessage));
}
})
.catch(function(e) {
// nothing too problematic if we can't send analytics
debug("failed to send analytics: " + e.message);
});
}
function getClientId() {
if(clientId) {
return clientId;
}
clientId = config.get("clientId");
if(!clientId) {
clientId = uuid();
config.set("clientId", clientId);
}
return clientId;
}
exports._cleansedStackTrack = cleansedStackTrack;
function cleansedStackTrack(err) {
// remove users file paths from trace (also squishes more into it)
const stack = err.stack;
if(!stack) {
return "";
}
return stack
// squish whitespace
.replace(/ +/g, " ")
// save space for ats
.replace(/\bat /g, "@")
// browser code - bundle, give bundle name
.replace(/file:\/\/\/\S+?\/app\/browser\/dist\/bundle/g, "bundle")
// everything else, leave only lastDirectoryName/basename
.replace(/file:\/\/\/\S+(\/\S+\/)/g, "$1")
// backend code - remove as much as poss
.replace(/\S+(?=\/app\/)/g, "")
// v8 @Context etc, not that useful
.replace(/@\S+/g, "")
// google drops everything after 150 bytes; do it here simply to make limit clear
// and to avoid confusion if we don't see > 150 bytes sent to goog but <= 150 inside
.slice(0, 150);
}
function sendRequest(url, queryParams) {
if(universal.isRenderer()) {
const url = new URL(url);
_.each(queryParams, function(v, k) {
url.searchParams.append(k, v);
});
return fetch(url)
.then(function(resp) {
return resp.json();
});
} else {
const axios = require("axios");
return axios.get(url, { params: queryParams });
}
}