Skip to content

Commit 9d64611

Browse files
committed
Add color output for SimplePrinter
Whether or not colored output is used is determined automatically. If you're not happy with the autodetect you can override it by setting the property `useColor`. This might happen when running in Tmux/screen in which Dart falsely claims the terminal does not support ANSI escape codes.
1 parent b73878d commit 9d64611

File tree

4 files changed

+67
-8
lines changed

4 files changed

+67
-8
lines changed

example/main.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ void demo() {
2424
logger.e("Error! Something bad happened", "Test Error");
2525

2626
loggerNoStack.v({"key": 5, "value": "something"});
27+
28+
Logger(printer: SimplePrinter()..useColor = true).v("boom");
2729
}

lib/src/printers/simple_printer.dart

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import 'dart:convert';
2+
import 'dart:io' as io;
3+
4+
import 'package:io/ansi.dart';
25

36
import 'package:logger/src/logger.dart';
47
import 'package:logger/src/log_printer.dart';
@@ -17,19 +20,42 @@ class SimplePrinter extends LogPrinter {
1720
Level.wtf: '[WTF]',
1821
};
1922

20-
final bool printTime;
23+
static final levelColors = {
24+
Level.verbose: darkGray,
25+
Level.debug: defaultForeground,
26+
Level.info: blue,
27+
Level.warning: yellow,
28+
Level.error: magenta,
29+
Level.wtf: red,
30+
};
31+
32+
bool printTime;
33+
34+
/// You can override the auto detected color support with this property. This
35+
/// is useful when Dart incorrectly reports a terminal not supporting colors.
36+
/// This happens, for example, when running the Dart program under Tmux or
37+
/// screen. See https://github.com/dart-lang/sdk/issues/31606.
38+
bool useColor;
2139

22-
SimplePrinter({this.printTime = false});
40+
SimplePrinter({this.printTime = false})
41+
: useColor = io.stdout.supportsAnsiEscapes;
2342

2443
@override
2544
List<String> log(LogEvent event) {
26-
var messageStr = stringifyMessage(event.message);
45+
var messageStr = _stringifyMessage(event.message);
2746
var errorStr = event.error != null ? " ERROR: ${event.error}" : "";
2847
var timeStr = printTime ? "TIME: ${DateTime.now().toIso8601String()}" : "";
29-
return ["${levelPrefixes[event.level]} $timeStr $messageStr$errorStr"];
48+
return ["${_labelFor(event.level)} $timeStr $messageStr$errorStr"];
49+
}
50+
51+
String _labelFor(Level level) {
52+
var prefix = levelPrefixes[level];
53+
var color = levelColors[level];
54+
55+
return overrideAnsiOutput(useColor, () => color.wrap(prefix));
3056
}
3157

32-
String stringifyMessage(dynamic message) {
58+
String _stringifyMessage(dynamic message) {
3359
if (message is Map || message is Iterable) {
3460
var encoder = JsonEncoder.withIndent(null);
3561
return encoder.convert(message);

pubspec.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ homepage: https://github.com/leisim/logger
77
environment:
88
sdk: ">=2.1.0 <3.0.0"
99

10+
dependencies:
11+
io: 0.3.3
12+
1013
dev_dependencies:
1114
test: any
1215
pedantic: ^1.9.0

test/printers/simple_printer_test.dart

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import 'package:test/test.dart';
22
import 'package:logger/logger.dart';
33

4+
const ansiEscapeLiteral = '\x1B';
5+
46
void main() {
57
LogEvent event = LogEvent(
68
Level.debug,
@@ -9,19 +11,45 @@ void main() {
911
StackTrace.current,
1012
);
1113

14+
var plainPrinter = SimplePrinter()
15+
..useColor = false
16+
..printTime = false;
17+
1218
test('represent event on a single line (ignoring stacktrace)', () {
13-
var outputs = SimplePrinter().log(event);
19+
var outputs = plainPrinter.log(event);
1420

1521
expect(outputs, hasLength(1));
1622
expect(outputs[0], '[D] some message ERROR: some error');
1723
});
1824

25+
group('color', () {
26+
test('print color', () {
27+
// `useColor` is detected but here we override it because we want to print
28+
// the ANSI control characters regardless for the test.
29+
var printer = SimplePrinter()..useColor = true;
30+
31+
expect(printer.log(event)[0], contains(ansiEscapeLiteral));
32+
});
33+
34+
test('toggle color', () {
35+
var printer = SimplePrinter()..useColor = false;
36+
37+
expect(printer.log(event)[0], isNot(contains(ansiEscapeLiteral)));
38+
});
39+
});
40+
1941
test('print time', () {
2042
var printer = SimplePrinter(printTime: true);
2143

2244
expect(printer.log(event)[0], contains('TIME'));
2345
});
2446

47+
test('toggle time', () {
48+
var printer = SimplePrinter(printTime: true)..printTime = false;
49+
50+
expect(printer.log(event)[0], isNot(contains('TIME')));
51+
});
52+
2553
test('omits error when null', () {
2654
LogEvent withoutError = LogEvent(
2755
Level.debug,
@@ -43,7 +71,7 @@ void main() {
4371
);
4472

4573
expect(
46-
SimplePrinter().log(withMap)[0],
74+
plainPrinter.log(withMap)[0],
4775
'[D] {"foo":123} ERROR: some error',
4876
);
4977
});
@@ -57,7 +85,7 @@ void main() {
5785
);
5886

5987
expect(
60-
SimplePrinter().log(withIterable)[0],
88+
plainPrinter.log(withIterable)[0],
6189
'[D] [1,2,3,4] ERROR: some error',
6290
);
6391
});

0 commit comments

Comments
 (0)