Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/debug/formatter.js
4515 views
1
/**
2
* @license
3
* Copyright The Closure Library Authors.
4
* SPDX-License-Identifier: Apache-2.0
5
*/
6
7
/**
8
* @fileoverview Definition of various formatters for logging. Please minimize
9
* dependencies this file has on other closure classes as any dependency it
10
* takes won't be able to use the logging infrastructure.
11
*/
12
13
goog.provide('goog.debug.Formatter');
14
goog.provide('goog.debug.HtmlFormatter');
15
goog.provide('goog.debug.TextFormatter');
16
goog.provide('goog.debug.formatter');
17
18
goog.require('goog.debug');
19
goog.require('goog.debug.RelativeTimeProvider');
20
goog.require('goog.html.SafeHtml');
21
goog.require('goog.html.SafeUrl');
22
goog.require('goog.html.uncheckedconversions');
23
goog.require('goog.log');
24
goog.require('goog.string.Const');
25
goog.requireType('goog.log.LogRecord');
26
27
28
/**
29
* Base class for Formatters. A Formatter is used to format a LogRecord into
30
* something that can be displayed to the user.
31
*
32
* @param {string=} opt_prefix The prefix to place before text records.
33
* @constructor
34
*/
35
goog.debug.formatter.Formatter = function(opt_prefix) {
36
'use strict';
37
this.prefix_ = opt_prefix || '';
38
39
/**
40
* A provider that returns the relative start time.
41
* @type {goog.debug.RelativeTimeProvider}
42
* @private
43
*/
44
this.startTimeProvider_ =
45
goog.debug.RelativeTimeProvider.getDefaultInstance();
46
};
47
48
49
/**
50
* Whether to append newlines to the end of formatted log records.
51
* @type {boolean}
52
*/
53
goog.debug.formatter.Formatter.prototype.appendNewline = true;
54
55
56
/**
57
* Whether to show absolute time in the DebugWindow.
58
* @type {boolean}
59
*/
60
goog.debug.formatter.Formatter.prototype.showAbsoluteTime = true;
61
62
63
/**
64
* Whether to show relative time in the DebugWindow.
65
* @type {boolean}
66
*/
67
goog.debug.formatter.Formatter.prototype.showRelativeTime = true;
68
69
70
/**
71
* Whether to show the logger name in the DebugWindow.
72
* @type {boolean}
73
*/
74
goog.debug.formatter.Formatter.prototype.showLoggerName = true;
75
76
77
/**
78
* Whether to show the logger exception text.
79
* @type {boolean}
80
*/
81
goog.debug.formatter.Formatter.prototype.showExceptionText = false;
82
83
84
/**
85
* Whether to show the severity level.
86
* @type {boolean}
87
*/
88
goog.debug.formatter.Formatter.prototype.showSeverityLevel = false;
89
90
91
/**
92
* Formats a record.
93
* @param {?goog.log.LogRecord} logRecord the logRecord to format.
94
* @return {string} The formatted string.
95
*/
96
goog.debug.formatter.Formatter.prototype.formatRecord = goog.abstractMethod;
97
98
99
/**
100
* Formats a record as SafeHtml.
101
* @param {?goog.log.LogRecord} logRecord the logRecord to format.
102
* @return {!goog.html.SafeHtml} The formatted string as SafeHtml.
103
*/
104
goog.debug.formatter.Formatter.prototype.formatRecordAsHtml =
105
goog.abstractMethod;
106
107
108
/**
109
* Sets the start time provider. By default, this is the default instance
110
* but can be changed.
111
* @param {goog.debug.RelativeTimeProvider} provider The provider to use.
112
*/
113
goog.debug.formatter.Formatter.prototype.setStartTimeProvider = function(
114
provider) {
115
'use strict';
116
this.startTimeProvider_ = provider;
117
};
118
119
120
/**
121
* Returns the start time provider. By default, this is the default instance
122
* but can be changed.
123
* @return {goog.debug.RelativeTimeProvider} The start time provider.
124
*/
125
goog.debug.formatter.Formatter.prototype.getStartTimeProvider = function() {
126
'use strict';
127
return this.startTimeProvider_;
128
};
129
130
131
/**
132
* Resets the start relative time.
133
*/
134
goog.debug.formatter.Formatter.prototype.resetRelativeTimeStart = function() {
135
'use strict';
136
this.startTimeProvider_.reset();
137
};
138
139
140
/**
141
* Returns a string for the time/date of the LogRecord.
142
* @param {?goog.log.LogRecord} logRecord The record to get a time stamp for.
143
* @return {string} A string representation of the time/date of the LogRecord.
144
* @private
145
*/
146
goog.debug.formatter.Formatter.getDateTimeStamp_ = function(logRecord) {
147
'use strict';
148
var time = new Date(logRecord.getMillis());
149
return goog.debug.formatter.Formatter.getTwoDigitString_(
150
(time.getFullYear() - 2000)) +
151
goog.debug.formatter.Formatter.getTwoDigitString_((time.getMonth() + 1)) +
152
goog.debug.formatter.Formatter.getTwoDigitString_(time.getDate()) + ' ' +
153
goog.debug.formatter.Formatter.getTwoDigitString_(time.getHours()) + ':' +
154
goog.debug.formatter.Formatter.getTwoDigitString_(time.getMinutes()) +
155
':' +
156
goog.debug.formatter.Formatter.getTwoDigitString_(time.getSeconds()) +
157
'.' +
158
goog.debug.formatter.Formatter.getTwoDigitString_(
159
Math.floor(time.getMilliseconds() / 10));
160
};
161
162
163
/**
164
* Returns the number as a two-digit string, meaning it prepends a 0 if the
165
* number if less than 10.
166
* @param {number} n The number to format.
167
* @return {string} A two-digit string representation of `n`.
168
* @private
169
*/
170
goog.debug.formatter.Formatter.getTwoDigitString_ = function(n) {
171
'use strict';
172
if (n < 10) {
173
return '0' + n;
174
}
175
return String(n);
176
};
177
178
179
/**
180
* Returns a string for the number of seconds relative to the start time.
181
* Prepads with spaces so that anything less than 1000 seconds takes up the
182
* same number of characters for better formatting.
183
* @param {?goog.log.LogRecord} logRecord The log to compare time to.
184
* @param {number} relativeTimeStart The start time to compare to.
185
* @return {string} The number of seconds of the LogRecord relative to the
186
* start time.
187
* @private
188
*/
189
goog.debug.formatter.Formatter.getRelativeTime_ = function(
190
logRecord, relativeTimeStart) {
191
'use strict';
192
var ms = logRecord.getMillis() - relativeTimeStart;
193
var sec = ms / 1000;
194
var str = sec.toFixed(3);
195
196
var spacesToPrepend = 0;
197
if (sec < 1) {
198
spacesToPrepend = 2;
199
} else {
200
while (sec < 100) {
201
spacesToPrepend++;
202
sec *= 10;
203
}
204
}
205
while (spacesToPrepend-- > 0) {
206
str = ' ' + str;
207
}
208
return str;
209
};
210
211
212
213
/**
214
* Formatter that returns formatted html. See formatRecord for the classes
215
* it uses for various types of formatted output.
216
*
217
* @param {string=} opt_prefix The prefix to place before text records.
218
* @constructor
219
* @extends {goog.debug.formatter.Formatter}
220
*/
221
goog.debug.formatter.HtmlFormatter = function(opt_prefix) {
222
'use strict';
223
goog.debug.formatter.Formatter.call(this, opt_prefix);
224
};
225
goog.inherits(
226
goog.debug.formatter.HtmlFormatter, goog.debug.formatter.Formatter);
227
228
229
/**
230
* Exposes an exception that has been caught by a try...catch and outputs the
231
* error as HTML with a stack trace.
232
*
233
* @param {*} err Error object or string.
234
* @param {?Function=} fn If provided, when collecting the stack trace all
235
* frames above the topmost call to this function, including that call,
236
* will be left out of the stack trace.
237
* @return {string} Details of exception, as HTML.
238
*/
239
goog.debug.formatter.HtmlFormatter.exposeException = function(err, fn) {
240
'use strict';
241
var html = goog.debug.formatter.HtmlFormatter.exposeExceptionAsHtml(err, fn);
242
return goog.html.SafeHtml.unwrap(html);
243
};
244
245
246
/**
247
* Exposes an exception that has been caught by a try...catch and outputs the
248
* error with a stack trace.
249
*
250
* @param {*} err Error object or string.
251
* @param {?Function=} fn If provided, when collecting the stack trace all
252
* frames above the topmost call to this function, including that call,
253
* will be left out of the stack trace.
254
* @return {!goog.html.SafeHtml} Details of exception.
255
*/
256
goog.debug.formatter.HtmlFormatter.exposeExceptionAsHtml = function(err, fn) {
257
'use strict';
258
try {
259
var e = goog.debug.normalizeErrorObject(err);
260
// Create the error message
261
var viewSourceUrl =
262
goog.debug.formatter.HtmlFormatter.createViewSourceUrl_(e.fileName);
263
var error = goog.html.SafeHtml.concat(
264
goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces(
265
'Message: ' + e.message + '\nUrl: '),
266
goog.html.SafeHtml.create(
267
'a', {href: viewSourceUrl, target: '_new'}, e.fileName),
268
goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces(
269
'\nLine: ' + e.lineNumber + '\n\nBrowser stack:\n' + e.stack +
270
'-> ' +
271
'[end]\n\nJS stack traversal:\n' + goog.debug.getStacktrace(fn) +
272
'-> '));
273
return error;
274
} catch (e2) {
275
return goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces(
276
'Exception trying to expose exception! You win, we lose. ' + e2);
277
}
278
};
279
280
281
/**
282
* @param {?string=} fileName
283
* @return {!goog.html.SafeUrl} SafeUrl with view-source scheme, pointing at
284
* fileName.
285
* @private
286
*/
287
goog.debug.formatter.HtmlFormatter.createViewSourceUrl_ = function(fileName) {
288
'use strict';
289
if (fileName == null) {
290
fileName = '';
291
}
292
if (!/^https?:\/\//i.test(fileName)) {
293
return goog.html.SafeUrl.fromConstant(
294
goog.string.Const.from('sanitizedviewsrc'));
295
}
296
var sanitizedFileName = goog.html.SafeUrl.sanitize(fileName);
297
return goog.html.uncheckedconversions
298
.safeUrlFromStringKnownToSatisfyTypeContract(
299
goog.string.Const.from('view-source scheme plus HTTP/HTTPS URL'),
300
'view-source:' + goog.html.SafeUrl.unwrap(sanitizedFileName));
301
};
302
303
304
305
/**
306
* Whether to show the logger exception text
307
* @type {boolean}
308
* @override
309
*/
310
goog.debug.formatter.HtmlFormatter.prototype.showExceptionText = true;
311
312
313
/**
314
* Formats a record
315
* @param {?goog.log.LogRecord} logRecord the logRecord to format.
316
* @return {string} The formatted string as html.
317
* @override
318
*/
319
goog.debug.formatter.HtmlFormatter.prototype.formatRecord = function(
320
logRecord) {
321
'use strict';
322
if (!logRecord) {
323
return '';
324
}
325
// OK not to use goog.html.SafeHtml.unwrap() here.
326
return this.formatRecordAsHtml(logRecord).getTypedStringValue();
327
};
328
329
330
/**
331
* Formats a record.
332
* @param {?goog.log.LogRecord} logRecord the logRecord to format.
333
* @return {!goog.html.SafeHtml} The formatted string as SafeHtml.
334
* @override
335
*/
336
goog.debug.formatter.HtmlFormatter.prototype.formatRecordAsHtml = function(
337
logRecord) {
338
'use strict';
339
if (!logRecord) {
340
return goog.html.SafeHtml.EMPTY;
341
}
342
343
var className;
344
switch (logRecord.getLevel().value) {
345
case goog.log.Level.SHOUT.value:
346
className = 'dbg-sh';
347
break;
348
case goog.log.Level.SEVERE.value:
349
className = 'dbg-sev';
350
break;
351
case goog.log.Level.WARNING.value:
352
className = 'dbg-w';
353
break;
354
case goog.log.Level.INFO.value:
355
className = 'dbg-i';
356
break;
357
case goog.log.Level.FINE.value:
358
default:
359
className = 'dbg-f';
360
break;
361
}
362
363
// HTML for user defined prefix, time, logger name, and severity.
364
var sb = [];
365
sb.push(this.prefix_, ' ');
366
if (this.showAbsoluteTime) {
367
sb.push(
368
'[', goog.debug.formatter.Formatter.getDateTimeStamp_(logRecord), '] ');
369
}
370
if (this.showRelativeTime) {
371
sb.push(
372
'[',
373
goog.debug.formatter.Formatter.getRelativeTime_(
374
logRecord, this.startTimeProvider_.get()),
375
's] ');
376
}
377
if (this.showLoggerName) {
378
sb.push('[', logRecord.getLoggerName(), '] ');
379
}
380
if (this.showSeverityLevel) {
381
sb.push('[', logRecord.getLevel().name, '] ');
382
}
383
var fullPrefixHtml =
384
goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces(sb.join(''));
385
386
// HTML for exception text and log record.
387
var exceptionHtml = goog.html.SafeHtml.EMPTY;
388
if (this.showExceptionText && logRecord.getException()) {
389
exceptionHtml = goog.html.SafeHtml.concat(
390
goog.html.SafeHtml.BR,
391
goog.debug.formatter.HtmlFormatter.exposeExceptionAsHtml(
392
logRecord.getException()));
393
}
394
var logRecordHtml = goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces(
395
logRecord.getMessage());
396
var recordAndExceptionHtml = goog.html.SafeHtml.create(
397
'span', {'class': className},
398
goog.html.SafeHtml.concat(logRecordHtml, exceptionHtml));
399
400
401
// Combine both pieces of HTML and, if needed, append a final newline.
402
var html;
403
if (this.appendNewline) {
404
html = goog.html.SafeHtml.concat(
405
fullPrefixHtml, recordAndExceptionHtml, goog.html.SafeHtml.BR);
406
} else {
407
html = goog.html.SafeHtml.concat(fullPrefixHtml, recordAndExceptionHtml);
408
}
409
return html;
410
};
411
412
413
414
/**
415
* Formatter that returns formatted plain text
416
*
417
* @param {string=} opt_prefix The prefix to place before text records.
418
* @constructor
419
* @extends {goog.debug.formatter.Formatter}
420
* @final
421
*/
422
goog.debug.formatter.TextFormatter = function(opt_prefix) {
423
'use strict';
424
goog.debug.formatter.Formatter.call(this, opt_prefix);
425
};
426
goog.inherits(
427
goog.debug.formatter.TextFormatter, goog.debug.formatter.Formatter);
428
429
430
/**
431
* Formats a record as text
432
* @param {?goog.log.LogRecord} logRecord the logRecord to format.
433
* @return {string} The formatted string.
434
* @override
435
*/
436
goog.debug.formatter.TextFormatter.prototype.formatRecord = function(
437
logRecord) {
438
'use strict';
439
var sb = [];
440
sb.push(this.prefix_, ' ');
441
if (this.showAbsoluteTime) {
442
sb.push(
443
'[', goog.debug.formatter.Formatter.getDateTimeStamp_(logRecord), '] ');
444
}
445
if (this.showRelativeTime) {
446
sb.push(
447
'[',
448
goog.debug.formatter.Formatter.getRelativeTime_(
449
logRecord, this.startTimeProvider_.get()),
450
's] ');
451
}
452
453
if (this.showLoggerName) {
454
sb.push('[', logRecord.getLoggerName(), '] ');
455
}
456
if (this.showSeverityLevel) {
457
sb.push('[', logRecord.getLevel().name, '] ');
458
}
459
sb.push(logRecord.getMessage());
460
if (this.showExceptionText) {
461
var exception = logRecord.getException();
462
if (exception !== undefined) {
463
var exceptionText =
464
exception instanceof Error ? exception.message : String(exception);
465
sb.push('\n', exceptionText);
466
}
467
}
468
if (this.appendNewline) {
469
sb.push('\n');
470
}
471
return sb.join('');
472
};
473
474
475
/**
476
* Formats a record as text
477
* @param {?goog.log.LogRecord} logRecord the logRecord to format.
478
* @return {!goog.html.SafeHtml} The formatted string as SafeHtml. This is
479
* just an HTML-escaped version of the text obtained from formatRecord().
480
* @override
481
*/
482
goog.debug.formatter.TextFormatter.prototype.formatRecordAsHtml = function(
483
logRecord) {
484
'use strict';
485
return goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces(
486
goog.debug.formatter.TextFormatter.prototype.formatRecord(logRecord));
487
};
488
489
// Aliases for the above formatters.
490
// TODO(user): Delete these aliases when there are no more usages.
491
492
/**
493
* @constructor
494
*/
495
goog.debug.Formatter = goog.debug.formatter.Formatter;
496
497
/**
498
* @constructor
499
*/
500
goog.debug.TextFormatter = goog.debug.formatter.TextFormatter;
501
502
/**
503
* @constructor
504
*/
505
goog.debug.HtmlFormatter = goog.debug.formatter.HtmlFormatter;
506
507