1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | var os = require('os');
|
18 | var fs = require('fs');
|
19 | var crypto = require('crypto');
|
20 | var _appInsights = require('applicationinsights');
|
21 | var profile = require('./profile');
|
22 | var utilsCore = require('./utilsCore');
|
23 | var Constants = require('./constants');
|
24 | var userAgentCore = require('./userAgentCore');
|
25 |
|
26 | var _event;
|
27 | var _isEnabled = false;
|
28 | var _currentCommand;
|
29 | var _rawCommand;
|
30 | var _subscription;
|
31 |
|
32 | var _Data = (function() {
|
33 | var Data = function () {
|
34 | };
|
35 | return Data;
|
36 | })();
|
37 |
|
38 | var _PageViewData = (function() {
|
39 | var PageViewData = function () {
|
40 | this.ver = 2;
|
41 | this.properties = {};
|
42 | this.measurements = {};
|
43 | };
|
44 | return PageViewData;
|
45 | })();
|
46 |
|
47 | var _AzureCliQosEvent = function() {
|
48 | return {
|
49 | startTime: Date.now(),
|
50 | duration: 0,
|
51 | isSuccess: true,
|
52 | commandName: '',
|
53 | command: '',
|
54 | mode: '',
|
55 | nodeVersion: '',
|
56 | userId: '',
|
57 | userType: '',
|
58 | installationType: 'NONE',
|
59 | osType: os && os.type(),
|
60 | osVersion: os && os.release()
|
61 | };
|
62 | };
|
63 |
|
64 | var _getInstallationType = function (command) {
|
65 | var type = 'NONE';
|
66 | var osType = os.type();
|
67 | if (osType === 'Windows_NT') {
|
68 | if (command) {
|
69 | type = command.indexOf('Microsoft SDKs\\Azure') > -1 ? 'INSTALLER' : 'NPM';
|
70 | }
|
71 | } else if (osType === 'Darwin') {
|
72 | try {
|
73 |
|
74 |
|
75 | var lstat = fs.lstatSync('/usr/local/bin/azure');
|
76 | type = lstat.isSymbolicLink() ? 'NPM' : 'INSTALLER';
|
77 | } catch (e) {
|
78 |
|
79 | }
|
80 | } else {
|
81 |
|
82 | type = 'NPM';
|
83 | }
|
84 | return type;
|
85 | };
|
86 |
|
87 | var _getCurrentSubscription = function() {
|
88 | var thumbprint = function(cert) {
|
89 | if (!cert) {
|
90 |
|
91 | return 'none';
|
92 | }
|
93 | return crypto.createHash('sha1')
|
94 | .update(new Buffer(cert, 'base64').toString('binary'))
|
95 | .digest('hex');
|
96 | };
|
97 |
|
98 | var subscription = {
|
99 | id: 'none',
|
100 | user: {
|
101 | id: 'none',
|
102 | type: 'none'
|
103 | }
|
104 | };
|
105 |
|
106 | var sub;
|
107 | try {
|
108 | sub = profile.current.getSubscription();
|
109 | } catch (e) {
|
110 |
|
111 | }
|
112 |
|
113 | if (sub) {
|
114 | subscription.id = sub.id;
|
115 | if (sub.user) {
|
116 | subscription.user.id = crypto.createHash('sha256').update(sub.user.name).digest('hex');
|
117 | subscription.user.type = sub.user.type;
|
118 | } else if (sub.managementCertificate) {
|
119 | subscription.user.id = thumbprint(sub.managementCertificate.cert);
|
120 | subscription.user.type = 'managementCertificate';
|
121 | }
|
122 | }
|
123 | return subscription;
|
124 | };
|
125 |
|
126 | var _filterCommand = function (commandName, rawCommand) {
|
127 | var outCmd = '';
|
128 | if (rawCommand && commandName) {
|
129 | outCmd = commandName;
|
130 |
|
131 | var filterStartIndex = 2 + outCmd.split(/\s+/).length;
|
132 | for (var i = filterStartIndex; i < rawCommand.length; i++) {
|
133 | var token = rawCommand[i];
|
134 | if (!utilsCore.stringStartsWith(token, '-')) {
|
135 | token = (token.length > 40) ? '***' : token.replace(/./g, '*');
|
136 | }
|
137 | outCmd += ' ' + token;
|
138 | }
|
139 | }
|
140 | return outCmd;
|
141 | };
|
142 |
|
143 | var _stop = function (qosEvent) {
|
144 | if (qosEvent) {
|
145 | qosEvent.duration = Date.now() - qosEvent.startTime;
|
146 | }
|
147 | };
|
148 |
|
149 |
|
150 | var _msToTimeSpan = function (totalms) {
|
151 | if (isNaN(totalms) || totalms < 0) {
|
152 | totalms = 0;
|
153 | }
|
154 | var ms = '' + totalms % 1000;
|
155 | var sec = '' + Math.floor(totalms / 1000) % 60;
|
156 | var min = '' + Math.floor(totalms / (1000 * 60)) % 60;
|
157 | var hour = '' + Math.floor(totalms / (1000 * 60 * 60)) % 24;
|
158 | ms = ms.length === 1 ? '00' + ms : ms.length === 2 ? '0' + ms : ms;
|
159 | sec = sec.length < 2 ? '0' + sec : sec;
|
160 | min = min.length < 2 ? '0' + min : min;
|
161 | hour = hour.length < 2 ? '0' + hour : hour;
|
162 | return hour + ':' + min + ':' + sec + '.' + ms;
|
163 | };
|
164 |
|
165 | var _trackPageView = function (data) {
|
166 | var pageView = new _PageViewData();
|
167 | pageView.name = data.commandName;
|
168 | if (!isNaN(data.duration)) {
|
169 | pageView.duration = _msToTimeSpan(data.duration);
|
170 | }
|
171 | pageView.properties = data;
|
172 | var _data = new _Data();
|
173 | _data.baseType = 'PageViewData';
|
174 | _data.baseData = pageView;
|
175 | _appInsights.client.track(_data);
|
176 | };
|
177 |
|
178 | var _flush = function (callback) {
|
179 | if (_isEnabled) {
|
180 | _appInsights.client.sendPendingData(callback);
|
181 | }
|
182 | };
|
183 |
|
184 | var _stripUsername = function(str) {
|
185 | if (str) {
|
186 | var re = /(.*users[\\|\/])(.*?)([\\|\/].*)/gi;
|
187 | return str.replace(re, '$1***$3');
|
188 | } else {
|
189 | return str;
|
190 | }
|
191 | };
|
192 |
|
193 | |
194 |
|
195 |
|
196 |
|
197 |
|
198 | exports.init = function (isEnabled) {
|
199 | _isEnabled = isEnabled;
|
200 | _subscription = _getCurrentSubscription();
|
201 |
|
202 | if (_isEnabled) {
|
203 | _appInsights.setup(Constants.TELEMETRY_INSTRUMENTATION_KEY)
|
204 | .setAutoCollectRequests(false)
|
205 | .setAutoCollectPerformance(false)
|
206 | .setAutoCollectExceptions(false);
|
207 |
|
208 |
|
209 | var context = _appInsights.client.context;
|
210 | context.tags[context.keys.userId] = _subscription.user.id;
|
211 |
|
212 | _appInsights.start();
|
213 | }
|
214 | };
|
215 |
|
216 | exports.currentCommand = function (command) {
|
217 | if (command && typeof command === 'object') {
|
218 | _currentCommand = command;
|
219 |
|
220 | if (_event) {
|
221 | _event.commandName = command.fullName();
|
222 | _event.command = _filterCommand(_event.commandName, _rawCommand);
|
223 |
|
224 |
|
225 | userAgentCore.setCommandInfo(_event.commandName, _filterCommand(' ', _rawCommand));
|
226 | }
|
227 | }
|
228 | };
|
229 |
|
230 | |
231 |
|
232 |
|
233 |
|
234 | exports.start = function (command) {
|
235 | if (command) {
|
236 | _rawCommand = command;
|
237 | }
|
238 | _event = _AzureCliQosEvent();
|
239 | _event.installationType = _getInstallationType(command);
|
240 | _event.nodeVersion = process.version;
|
241 | _event['Azure.Subscription.Id'] = _subscription.id;
|
242 | _event.userId = _subscription.user.id;
|
243 | _event.userType = _subscription.user.type;
|
244 |
|
245 |
|
246 | userAgentCore.setUserAgentData(constructUserAgentData());
|
247 | };
|
248 |
|
249 | exports.setAppInsights = function (appInsights) {
|
250 | _appInsights = appInsights;
|
251 | };
|
252 |
|
253 | exports.setMode = function (mode) {
|
254 | if (_event) {
|
255 | _event.mode = mode;
|
256 |
|
257 |
|
258 | userAgentCore.setMode(mode);
|
259 | }
|
260 | };
|
261 |
|
262 | exports.onError = function (err, callback) {
|
263 | if (_isEnabled && _event) {
|
264 | _stop(_event);
|
265 | _event.isSuccess = false;
|
266 | _event.stacktrace = _stripUsername(err.stack);
|
267 | _event.errorCategory = err.statusCode ? 'HTTP_Error_' + err.statusCode : 'CLI_Error';
|
268 | _appInsights.client.trackEvent('CmdletError', _event);
|
269 | _flush(callback);
|
270 | } else {
|
271 | callback();
|
272 | }
|
273 | };
|
274 |
|
275 | |
276 |
|
277 |
|
278 | exports.onFinish = function (callback) {
|
279 | if (_isEnabled && _event) {
|
280 | _stop(_event);
|
281 | _trackPageView(_event);
|
282 | _flush(callback);
|
283 | } else {
|
284 | callback();
|
285 | }
|
286 | };
|
287 |
|
288 | |
289 |
|
290 |
|
291 | function constructUserAgentData() {
|
292 | if (_event) {
|
293 | return {
|
294 | osType: _event.osType,
|
295 | osVersion: _event.osVersion,
|
296 | nodeVersion: _event.nodeVersion,
|
297 | installationType: _event.installationType,
|
298 | userId: _event.userId,
|
299 | subscriptionId: _event['Azure.Subscription.Id'],
|
300 | userType: _event.userType
|
301 | };
|
302 | }
|
303 | }
|