Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/debug/errorreporter.js
2868 views
1
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview Definition of the ErrorReporter class, which creates an error
17
* handler that reports any errors raised to a URL.
18
*
19
*/
20
21
goog.provide('goog.debug.ErrorReporter');
22
goog.provide('goog.debug.ErrorReporter.ExceptionEvent');
23
24
goog.require('goog.asserts');
25
goog.require('goog.debug');
26
goog.require('goog.debug.Error');
27
goog.require('goog.debug.ErrorHandler');
28
goog.require('goog.debug.entryPointRegistry');
29
goog.require('goog.events');
30
goog.require('goog.events.Event');
31
goog.require('goog.events.EventTarget');
32
goog.require('goog.log');
33
goog.require('goog.net.XhrIo');
34
goog.require('goog.object');
35
goog.require('goog.string');
36
goog.require('goog.uri.utils');
37
goog.require('goog.userAgent');
38
39
40
41
/**
42
* Constructs an error reporter. Internal Use Only. To install an error
43
* reporter see the {@see #install} method below.
44
*
45
* @param {string} handlerUrl The URL to which all errors will be reported.
46
* @param {function(!Error, !Object<string, string>)=}
47
* opt_contextProvider When a report is to be sent to the server,
48
* this method will be called, and given an opportunity to modify the
49
* context object before submission to the server.
50
* @param {boolean=} opt_noAutoProtect Whether to automatically add handlers for
51
* onerror and to protect entry points. If apps have other error reporting
52
* facilities, it may make sense for them to set these up themselves and use
53
* the ErrorReporter just for transmission of reports.
54
* @constructor
55
* @extends {goog.events.EventTarget}
56
*/
57
goog.debug.ErrorReporter = function(
58
handlerUrl, opt_contextProvider, opt_noAutoProtect) {
59
goog.debug.ErrorReporter.base(this, 'constructor');
60
61
/**
62
* Context provider, if one was provided.
63
* @type {?function(!Error, !Object<string, string>)}
64
* @private
65
*/
66
this.contextProvider_ = opt_contextProvider || null;
67
68
/**
69
* The string prefix of any optional context parameters logged with the error.
70
* @private {string}
71
*/
72
this.contextPrefix_ = 'context.';
73
74
/**
75
* The number of bytes after which the ErrorReporter truncates the POST body.
76
* If null, the ErrorReporter won't truncate the body.
77
* @private {?number}
78
*/
79
this.truncationLimit_ = null;
80
81
/**
82
* Additional arguments to append to URL before sending XHR.
83
* @private {!Object<string,string>}
84
*/
85
this.additionalArguments_ = {};
86
87
/**
88
* XHR sender.
89
* @type {function(string, string, string, (Object|goog.structs.Map)=)}
90
* @private
91
*/
92
this.xhrSender_ = goog.debug.ErrorReporter.defaultXhrSender;
93
94
/**
95
* The URL at which all errors caught by this handler will be logged.
96
*
97
* @type {string}
98
* @private
99
*/
100
this.handlerUrl_ = handlerUrl;
101
102
if (goog.debug.ErrorReporter.ALLOW_AUTO_PROTECT) {
103
if (!opt_noAutoProtect) {
104
/**
105
* The internal error handler used to catch all errors.
106
*
107
* @private {goog.debug.ErrorHandler}
108
*/
109
this.errorHandler_ = null;
110
111
this.setup_();
112
}
113
} else if (!opt_noAutoProtect) {
114
goog.asserts.fail(
115
'opt_noAutoProtect cannot be false while ' +
116
'goog.debug.ErrorReporter.ALLOW_AUTO_PROTECT is false. Setting ' +
117
'ALLOW_AUTO_PROTECT to false removes the necessary auto-protect code ' +
118
'in compiled/optimized mode.');
119
}
120
};
121
goog.inherits(goog.debug.ErrorReporter, goog.events.EventTarget);
122
123
124
/**
125
* @define {boolean} If true, the code that provides additional entry point
126
* protection and setup is exposed in this file. Set to false to avoid
127
* bringing in a lot of code from ErrorHandler and entryPointRegistry in
128
* compiled mode.
129
*/
130
goog.define('goog.debug.ErrorReporter.ALLOW_AUTO_PROTECT', true);
131
132
133
134
/**
135
* Event broadcast when an exception is logged.
136
* @param {Error} error The exception that was was reported.
137
* @param {!Object<string, string>} context The context values sent to the
138
* server alongside this error.
139
* @constructor
140
* @extends {goog.events.Event}
141
* @final
142
*/
143
goog.debug.ErrorReporter.ExceptionEvent = function(error, context) {
144
goog.events.Event.call(this, goog.debug.ErrorReporter.ExceptionEvent.TYPE);
145
146
/**
147
* The error that was reported.
148
* @type {Error}
149
*/
150
this.error = error;
151
152
/**
153
* Context values sent to the server alongside this report.
154
* @type {!Object<string, string>}
155
*/
156
this.context = context;
157
};
158
goog.inherits(goog.debug.ErrorReporter.ExceptionEvent, goog.events.Event);
159
160
161
/**
162
* Event type for notifying of a logged exception.
163
* @type {string}
164
*/
165
goog.debug.ErrorReporter.ExceptionEvent.TYPE =
166
goog.events.getUniqueId('exception');
167
168
169
/**
170
* Extra headers for the error-reporting XHR.
171
* @type {Object|goog.structs.Map|undefined}
172
* @private
173
*/
174
goog.debug.ErrorReporter.prototype.extraHeaders_;
175
176
177
/**
178
* Logging object.
179
*
180
* @type {goog.log.Logger}
181
* @private
182
*/
183
goog.debug.ErrorReporter.logger_ =
184
goog.log.getLogger('goog.debug.ErrorReporter');
185
186
187
/**
188
* Installs an error reporter to catch all JavaScript errors raised.
189
*
190
* @param {string} loggingUrl The URL to which the errors caught will be
191
* reported.
192
* @param {function(!Error, !Object<string, string>)=}
193
* opt_contextProvider When a report is to be sent to the server,
194
* this method will be called, and given an opportunity to modify the
195
* context object before submission to the server.
196
* @param {boolean=} opt_noAutoProtect Whether to automatically add handlers for
197
* onerror and to protect entry points. If apps have other error reporting
198
* facilities, it may make sense for them to set these up themselves and use
199
* the ErrorReporter just for transmission of reports.
200
* @return {!goog.debug.ErrorReporter} The error reporter.
201
*/
202
goog.debug.ErrorReporter.install = function(
203
loggingUrl, opt_contextProvider, opt_noAutoProtect) {
204
var instance = new goog.debug.ErrorReporter(
205
loggingUrl, opt_contextProvider, opt_noAutoProtect);
206
return instance;
207
};
208
209
210
/**
211
* Default implementation of XHR sender interface.
212
*
213
* @param {string} uri URI to make request to.
214
* @param {string} method Send method.
215
* @param {string} content Post data.
216
* @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the
217
* request.
218
*/
219
goog.debug.ErrorReporter.defaultXhrSender = function(
220
uri, method, content, opt_headers) {
221
goog.net.XhrIo.send(uri, null, method, content, opt_headers);
222
};
223
224
225
/**
226
* Installs exception protection for an entry point function in addition
227
* to those that are protected by default.
228
* Has no effect in IE because window.onerror is used for reporting
229
* exceptions in that case.
230
*
231
* @this {goog.debug.ErrorReporter}
232
* @param {Function} fn An entry point function to be protected.
233
* @return {Function} A protected wrapper function that calls the entry point
234
* function or null if the entry point could not be protected.
235
*/
236
goog.debug.ErrorReporter.prototype.protectAdditionalEntryPoint =
237
goog.debug.ErrorReporter.ALLOW_AUTO_PROTECT ? function(fn) {
238
if (this.errorHandler_) {
239
return this.errorHandler_.protectEntryPoint(fn);
240
}
241
return null;
242
} : function(fn) {
243
goog.asserts.fail(
244
'Cannot call protectAdditionalEntryPoint while ALLOW_AUTO_PROTECT ' +
245
'is false. If ALLOW_AUTO_PROTECT is false, the necessary ' +
246
'auto-protect code in compiled/optimized mode is removed.');
247
return null;
248
};
249
250
251
if (goog.debug.ErrorReporter.ALLOW_AUTO_PROTECT) {
252
/**
253
* Sets up the error reporter.
254
*
255
* @private
256
*/
257
goog.debug.ErrorReporter.prototype.setup_ = function() {
258
if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('10')) {
259
// Use "onerror" because caught exceptions in IE don't provide line
260
// number.
261
goog.debug.catchErrors(
262
goog.bind(this.handleException, this), false, null);
263
} else {
264
// "onerror" doesn't work with FF2 or Chrome
265
this.errorHandler_ =
266
new goog.debug.ErrorHandler(goog.bind(this.handleException, this));
267
268
this.errorHandler_.protectWindowSetTimeout();
269
this.errorHandler_.protectWindowSetInterval();
270
this.errorHandler_.protectWindowRequestAnimationFrame();
271
goog.debug.entryPointRegistry.monitorAll(this.errorHandler_);
272
}
273
};
274
}
275
276
277
/**
278
* Add headers to the logging url.
279
* @param {Object|goog.structs.Map} loggingHeaders Extra headers to send
280
* to the logging URL.
281
*/
282
goog.debug.ErrorReporter.prototype.setLoggingHeaders = function(
283
loggingHeaders) {
284
this.extraHeaders_ = loggingHeaders;
285
};
286
287
288
/**
289
* Set the function used to send error reports to the server.
290
* @param {function(string, string, string, (Object|goog.structs.Map)=)}
291
* xhrSender If provided, this will be used to send a report to the
292
* server instead of the default method. The function will be given the URI,
293
* HTTP method request content, and (optionally) request headers to be
294
* added.
295
*/
296
goog.debug.ErrorReporter.prototype.setXhrSender = function(xhrSender) {
297
this.xhrSender_ = xhrSender;
298
};
299
300
301
/**
302
* Handler for caught exceptions. Sends report to the LoggingServlet and
303
* notifies any listeners.
304
*
305
* @param {Object} e The exception.
306
* @param {!Object<string, string>=} opt_context Context values to optionally
307
* include in the error report.
308
*/
309
goog.debug.ErrorReporter.prototype.handleException = function(e, opt_context) {
310
var error = /** @type {!Error} */ (goog.debug.normalizeErrorObject(e));
311
312
// Construct the context, possibly from the one provided in the argument, and
313
// pass it to the context provider if there is one.
314
var context = opt_context ? goog.object.clone(opt_context) : {};
315
if (this.contextProvider_) {
316
try {
317
this.contextProvider_(error, context);
318
} catch (err) {
319
goog.log.error(
320
goog.debug.ErrorReporter.logger_,
321
'Context provider threw an exception: ' + err.message);
322
}
323
}
324
// Truncate message to a reasonable length, since it will be sent in the URL.
325
// The entire URL length historically needed to be 2,083 or less, so leave
326
// some room for the rest of the URL.
327
var message = error.message.substring(0, 1900);
328
if (!(e instanceof goog.debug.Error) || e.reportErrorToServer) {
329
this.sendErrorReport(
330
message, error.fileName, error.lineNumber, error.stack, context);
331
}
332
333
try {
334
this.dispatchEvent(
335
new goog.debug.ErrorReporter.ExceptionEvent(error, context));
336
} catch (ex) {
337
// Swallow exception to avoid infinite recursion.
338
}
339
};
340
341
342
/**
343
* Sends an error report to the logging URL. This will not consult the context
344
* provider, the report will be sent exactly as specified.
345
*
346
* @param {string} message Error description.
347
* @param {string} fileName URL of the JavaScript file with the error.
348
* @param {number} line Line number of the error.
349
* @param {string=} opt_trace Call stack trace of the error.
350
* @param {!Object<string, string>=} opt_context Context information to include
351
* in the request.
352
*/
353
goog.debug.ErrorReporter.prototype.sendErrorReport = function(
354
message, fileName, line, opt_trace, opt_context) {
355
try {
356
// Create the logging URL.
357
var requestUrl = goog.uri.utils.appendParams(
358
this.handlerUrl_, 'script', fileName, 'error', message, 'line', line);
359
360
if (!goog.object.isEmpty(this.additionalArguments_)) {
361
requestUrl = goog.uri.utils.appendParamsFromMap(
362
requestUrl, this.additionalArguments_);
363
}
364
365
var queryMap = {};
366
queryMap['trace'] = opt_trace;
367
368
// Copy context into query data map
369
if (opt_context) {
370
for (var entry in opt_context) {
371
queryMap[this.contextPrefix_ + entry] = opt_context[entry];
372
}
373
}
374
375
// Copy query data map into request.
376
var queryData = goog.uri.utils.buildQueryDataFromMap(queryMap);
377
378
// Truncate if truncationLimit set.
379
if (goog.isNumber(this.truncationLimit_)) {
380
queryData = queryData.substring(0, this.truncationLimit_);
381
}
382
383
// Send the request with the contents of the error.
384
this.xhrSender_(requestUrl, 'POST', queryData, this.extraHeaders_);
385
} catch (e) {
386
var logMessage = goog.string.buildString(
387
'Error occurred in sending an error report.\n\n', 'script:', fileName,
388
'\n', 'line:', line, '\n', 'error:', message, '\n', 'trace:',
389
opt_trace);
390
goog.log.info(goog.debug.ErrorReporter.logger_, logMessage);
391
}
392
};
393
394
395
/**
396
* @param {string} prefix The prefix to appear prepended to all context
397
* variables in the error report body.
398
*/
399
goog.debug.ErrorReporter.prototype.setContextPrefix = function(prefix) {
400
this.contextPrefix_ = prefix;
401
};
402
403
404
/**
405
* @param {?number} limit Size in bytes to begin truncating POST body. Set to
406
* null to prevent truncation. The limit must be >= 0.
407
*/
408
goog.debug.ErrorReporter.prototype.setTruncationLimit = function(limit) {
409
goog.asserts.assert(
410
!goog.isNumber(limit) || limit >= 0,
411
'Body limit must be valid number >= 0 or null');
412
this.truncationLimit_ = limit;
413
};
414
415
416
/**
417
* @param {!Object<string,string>} urlArgs Set of key-value pairs to append
418
* to handlerUrl_ before sending XHR.
419
*/
420
goog.debug.ErrorReporter.prototype.setAdditionalArguments = function(urlArgs) {
421
this.additionalArguments_ = urlArgs;
422
};
423
424
425
/** @override */
426
goog.debug.ErrorReporter.prototype.disposeInternal = function() {
427
if (goog.debug.ErrorReporter.ALLOW_AUTO_PROTECT) {
428
goog.dispose(this.errorHandler_);
429
}
430
goog.debug.ErrorReporter.base(this, 'disposeInternal');
431
};
432
433