OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// Message logging. | 5 /// Message logging. |
6 library pub.log; | 6 library pub.log; |
7 | 7 |
8 import 'dart:async'; | 8 import 'dart:async'; |
9 import 'dart:convert'; | 9 import 'dart:convert'; |
10 import 'dart:io'; | 10 import 'dart:io'; |
(...skipping 30 matching lines...) Expand all Loading... | |
41 | 41 |
42 /// The list of recorded log messages. Will only be recorded if | 42 /// The list of recorded log messages. Will only be recorded if |
43 /// [recordTranscript()] is called. | 43 /// [recordTranscript()] is called. |
44 Transcript<Entry> _transcript; | 44 Transcript<Entry> _transcript; |
45 | 45 |
46 /// The currently-animated progress indicator, if any. | 46 /// The currently-animated progress indicator, if any. |
47 /// | 47 /// |
48 /// This will also be in [_progresses]. | 48 /// This will also be in [_progresses]. |
49 Progress _animatedProgress; | 49 Progress _animatedProgress; |
50 | 50 |
51 _Collapser _collapser; | |
52 | |
51 final _cyan = getSpecial('\u001b[36m'); | 53 final _cyan = getSpecial('\u001b[36m'); |
52 final _green = getSpecial('\u001b[32m'); | 54 final _green = getSpecial('\u001b[32m'); |
53 final _magenta = getSpecial('\u001b[35m'); | 55 final _magenta = getSpecial('\u001b[35m'); |
54 final _red = getSpecial('\u001b[31m'); | 56 final _red = getSpecial('\u001b[31m'); |
55 final _yellow = getSpecial('\u001b[33m'); | 57 final _yellow = getSpecial('\u001b[33m'); |
56 final _gray = getSpecial('\u001b[1;30m'); | 58 final _gray = getSpecial('\u001b[1;30m'); |
57 final _none = getSpecial('\u001b[0m'); | 59 final _none = getSpecial('\u001b[0m'); |
58 final _noColor = getSpecial('\u001b[39m'); | 60 final _noColor = getSpecial('\u001b[39m'); |
59 final _bold = getSpecial('\u001b[1m'); | 61 final _bold = getSpecial('\u001b[1m'); |
60 | 62 |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
202 void io(message) => write(Level.IO, message); | 204 void io(message) => write(Level.IO, message); |
203 | 205 |
204 /// Logs [message] at [Level.SOLVER]. | 206 /// Logs [message] at [Level.SOLVER]. |
205 void solver(message) => write(Level.SOLVER, message); | 207 void solver(message) => write(Level.SOLVER, message); |
206 | 208 |
207 /// Logs [message] at [Level.FINE]. | 209 /// Logs [message] at [Level.FINE]. |
208 void fine(message) => write(Level.FINE, message); | 210 void fine(message) => write(Level.FINE, message); |
209 | 211 |
210 /// Logs [message] at [level]. | 212 /// Logs [message] at [level]. |
211 void write(Level level, message) { | 213 void write(Level level, message) { |
214 // Don't allow interleaving collapsible messages with other kinds. | |
215 if (_collapser != null) _collapser.end(); | |
216 | |
212 message = message.toString(); | 217 message = message.toString(); |
213 var lines = splitLines(message); | 218 var lines = splitLines(message); |
214 | 219 |
215 // Discard a trailing newline. This is useful since StringBuffers often end | 220 // Discard a trailing newline. This is useful since StringBuffers often end |
216 // up with an extra newline at the end from using [writeln]. | 221 // up with an extra newline at the end from using [writeln]. |
217 if (lines.isNotEmpty && lines.last == "") { | 222 if (lines.isNotEmpty && lines.last == "") { |
218 lines.removeLast(); | 223 lines.removeLast(); |
219 } | 224 } |
220 | 225 |
221 var entry = new Entry(level, lines.map(format).toList()); | 226 var entry = new Entry(level, lines.map(format).toList()); |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
402 _numMutes++; | 407 _numMutes++; |
403 } | 408 } |
404 | 409 |
405 /// Resumes animating any ongoing progress once all calls to [muteProgress] | 410 /// Resumes animating any ongoing progress once all calls to [muteProgress] |
406 /// have made their matching [unmuteProgress]. | 411 /// have made their matching [unmuteProgress]. |
407 void unmuteProgress() { | 412 void unmuteProgress() { |
408 assert(_numMutes > 0); | 413 assert(_numMutes > 0); |
409 _numMutes--; | 414 _numMutes--; |
410 } | 415 } |
411 | 416 |
417 /// Logs a collapsible [message]. | |
418 /// | |
419 /// If a number of collapsible messages are printed in short succession, they | |
420 /// are collapsed to just showing [template] with "##" replaced with the number | |
421 /// of collapsed messages. Avoids spamming the output with not-very-interesting | |
422 /// output. | |
423 void collapsible(String message, String template) { | |
424 // Only collapse messages when the output is not verbose. | |
425 if (verbosity._loggers[Level.MESSAGE] != _logToStdout) { | |
426 write(Level.MESSAGE, message); | |
427 return; | |
428 } | |
429 | |
430 // If this is a different set of collapsed messages, end the previous ones. | |
431 if (_collapser != null && _collapser._template != template) { | |
432 _collapser.end(); | |
433 } | |
434 | |
435 if (_collapser != null) { | |
436 _collapser.increment(); | |
437 } else { | |
438 _collapser = new _Collapser(message, template); | |
439 } | |
440 } | |
441 | |
412 /// Wraps [text] in the ANSI escape codes to make it bold when on a platform | 442 /// Wraps [text] in the ANSI escape codes to make it bold when on a platform |
413 /// that supports that. | 443 /// that supports that. |
414 /// | 444 /// |
415 /// Use this to highlight the most important piece of a long chunk of text. | 445 /// Use this to highlight the most important piece of a long chunk of text. |
416 /// | 446 /// |
417 /// This is disabled under [withPrejudice] since all text is bold with | 447 /// This is disabled under [withPrejudice] since all text is bold with |
418 /// prejudice. | 448 /// prejudice. |
419 String bold(text) => withPrejudice ? text : "$_bold$text$_none"; | 449 String bold(text) => withPrejudice ? text : "$_bold$text$_none"; |
420 | 450 |
421 /// Wraps [text] in the ANSI escape codes to make it gray when on a platform | 451 /// Wraps [text] in the ANSI escape codes to make it gray when on a platform |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
538 this.message(errorJson); | 568 this.message(errorJson); |
539 } | 569 } |
540 | 570 |
541 /// Encodes [message] to JSON and prints it if JSON output is enabled. | 571 /// Encodes [message] to JSON and prints it if JSON output is enabled. |
542 void message(message) { | 572 void message(message) { |
543 if (!enabled) return; | 573 if (!enabled) return; |
544 | 574 |
545 print(JSON.encode(message)); | 575 print(JSON.encode(message)); |
546 } | 576 } |
547 } | 577 } |
578 | |
579 /// Collapses a series of collapsible messages into a single line of output if | |
580 /// they happen within a short window of time. | |
581 class _Collapser { | |
582 /// The window of time where a series of calls to [collapsible] will be | |
583 /// collapsed to a single message. | |
584 static final _window = new Duration(milliseconds: 100); | |
585 | |
586 /// The Timer used to coalesce a number of collapsible messages. | |
587 /// | |
588 /// This is `null` if no collapsible messages are waiting to be displayed. | |
589 Timer _timer; | |
590 | |
591 /// The first collapsible message waiting to be displayed. | |
592 String _firstMessage; | |
593 | |
594 /// The template used to display the number of collapsed messages when more | |
595 /// than one collapsible message is logged within the window of time. | |
596 /// | |
597 /// Inside the template, "##" will be replaced with the number of collapsed | |
598 /// messages. | |
599 String _template; | |
600 | |
601 /// The number of collapsible messages that are waiting to be logged. | |
602 int _count = 1; | |
603 | |
604 _Collapser(this._firstMessage, this._template) { | |
605 _initTimer(); | |
606 } | |
607 | |
608 void increment() { | |
609 // Reset the timer. | |
610 _timer.cancel(); | |
611 _initTimer(); | |
612 | |
613 _count++; | |
614 } | |
615 | |
616 void end() { | |
617 // Clear this first so we don't stack overflow when we call message() below. | |
618 _collapser = null; | |
619 | |
620 _timer.cancel(); | |
621 if (_count == 1) { | |
622 message(_firstMessage); | |
623 } else { | |
624 message(_template.replaceAll("##", _count.toString())); | |
nweiz
2015/08/05 22:57:14
I'd still really like to have this dynamically upd
Bob Nystrom
2015/08/05 23:49:23
Leaving as-is per our discussion.
| |
625 } | |
626 } | |
627 | |
628 void _initTimer() { | |
629 _timer = new Timer(_window, end); | |
630 } | |
631 } | |
OLD | NEW |