Skip to content

Commit 625c0dc

Browse files
committed
Add platform detection
Thanks @gmpassos
1 parent ae1b1b4 commit 625c0dc

File tree

9 files changed

+307
-19
lines changed

9 files changed

+307
-19
lines changed

README.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,20 @@ var logger = Logger(
9696
);
9797
```
9898

99-
### Auto detecting
99+
### Auto Detecting Platform
100100

101-
With the `io` package you can auto detect the `lineLength` and `colors` arguments.
102-
Assuming you have imported the `io` package with `import 'dart:io' as io;` you
103-
can auto detect `colors` with `io.stdout.supportsAnsiEscapes` and `lineLength`
104-
with `io.stdout.terminalColumns`.
101+
The class `LogPlatform` tries to automatically identify `lineLength` and `colors`
102+
support for console output, depending on the detected platform (VM or Web).
105103

106-
You should probably do this unless there's a good reason you don't want to
107-
import `io`, for example when using this library on the web.
104+
If in VM platform it uses `dart:io` (`colors` with `io.stdout.supportsAnsiEscapes`
105+
and `lineLength` with `io.stdout.terminalColumns`).
106+
107+
If you want to allow output in `stderr` (if present in the runtime platform),
108+
you should enable it:
109+
110+
```dart
111+
LogPlatform.enableSTDERR = true ;
112+
```
108113

109114
## LogFilter
110115

lib/logger.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ export 'src/printers/simple_printer.dart';
1717
export 'src/printers/hybrid_printer.dart';
1818
export 'src/printers/prefix_printer.dart';
1919

20+
export 'src/platform/platform.dart';
21+
2022
export 'src/log_output.dart'
2123
if (dart.library.io) 'src/outputs/file_output.dart';
2224

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import 'package:logger/src/logger.dart';
22
import 'package:logger/src/log_output.dart';
3+
import 'package:logger/src/platform/platform.dart';
34

45
/// Default implementation of [LogOutput].
56
///
67
/// It sends everything to the system console.
78
class ConsoleOutput extends LogOutput {
89
@override
910
void output(OutputEvent event) {
10-
event.lines.forEach(print);
11+
var allLines = LogPlatform.joinLines(event.lines, event.level);
12+
var printer = LogPlatform.getConsolePrinter(event.level);
13+
14+
printer(allLines);
1115
}
1216
}

lib/src/platform/platform.dart

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import 'package:logger/logger.dart';
2+
3+
import 'platform_standard.dart'
4+
if (dart.library.html) 'platform_web.dart'
5+
if (dart.library.io) 'platform_vm.dart';
6+
7+
typedef ConsolePrinter = void Function(String arg);
8+
9+
/// Runtime platform capabilities
10+
class LogPlatform {
11+
/// Returns [true] if running in Web platform (Browser).
12+
static bool get isWeb => isPlatformWebImpl();
13+
14+
/// Returns [true] if running in VM platform.
15+
static bool get isVM => isPlatformVMImpl();
16+
17+
/// Returns [true] if the platform console supports colors.
18+
static bool get consoleSupportsColors =>
19+
getPlatformConsoleAcceptsColorsImpl();
20+
21+
/// Returns console columns size.
22+
static int get consoleColumns => getPlatformConsoleColumnsImpl();
23+
24+
/// Returns [true] if the console supports emoji.
25+
static bool get consoleSupportsEmoji => isPlatformWebImpl();
26+
27+
static bool _enableSTDERR = false;
28+
29+
/// If set to [true], allows write of [Level.error] and
30+
/// [Level.wtf] to `stderr` (if present in the runtime platform).
31+
///
32+
/// Default to [false], to be backward compatible with previous versions.
33+
/// of this package.
34+
static bool get enableSTDERR => _enableSTDERR;
35+
36+
static set enableSTDERR(bool value) {
37+
_enableSTDERR = value ?? false;
38+
}
39+
40+
/// Returns a [ConsolePrinter] that is muted (won't print anything).
41+
static ConsolePrinter get consoleMutedPrinter => (arg) {};
42+
43+
/// Returns a [ConsolePrinter] for log events.
44+
static ConsolePrinter get consoleLogPrinter => getPlatformConsoleLogPrinter();
45+
46+
/// Returns a [ConsolePrinter] for info events.
47+
static ConsolePrinter get consoleInfoPrinter =>
48+
getPlatformConsoleInfoPrinter();
49+
50+
/// Returns a [ConsolePrinter] for warn events.
51+
static ConsolePrinter get consoleWarnPrinter =>
52+
getPlatformConsoleWarnPrinter();
53+
54+
/// Returns a [ConsolePrinter] for error events.
55+
static ConsolePrinter get consoleErrorPrinter =>
56+
getPlatformConsoleErrorPrinter();
57+
58+
/// Returns the [ConsolePrinter] for the [level].
59+
static ConsolePrinter getConsolePrinter(Level level) {
60+
switch (level) {
61+
case Level.verbose:
62+
case Level.debug:
63+
return consoleLogPrinter;
64+
case Level.info:
65+
return consoleInfoPrinter;
66+
case Level.warning:
67+
return consoleWarnPrinter;
68+
case Level.error:
69+
case Level.wtf:
70+
return consoleErrorPrinter;
71+
case Level.nothing:
72+
return consoleMutedPrinter;
73+
default:
74+
return consoleLogPrinter;
75+
}
76+
}
77+
78+
/// In some browsers, depending of the [ConsolePrinter] for some [level],
79+
/// the 1st line printed to the console is not vertically
80+
/// aligned (head indented) with the other lines.
81+
static bool isConsolePrinterHeadIndented(Level level) =>
82+
isPlatformConsolePrinterHeadIndented(level);
83+
84+
/// Join lines, to avoid multiple calls to printer.
85+
///
86+
/// In Web platform (browser), each call to printer, in case of `warnings` or
87+
/// `erros`, will associate a stack trace tree (visible and expandable
88+
/// in Browser console).
89+
///
90+
/// In VM platform, multiple calls to printer is less efficient, since will
91+
/// generate multiple IO calls.
92+
static String joinLines(List<String> lines, Level level) {
93+
if (lines == null) return '';
94+
final linesLength = lines.length;
95+
if (linesLength == 0) return '';
96+
97+
// Tries to avoid new [String] allocations:
98+
if (linesLength == 1) {
99+
return lines[0];
100+
}
101+
// Ensure that head line is vertical aligned with other lines
102+
// in the current console platform (if not, add a blank head line):
103+
else if (LogPlatform.isConsolePrinterHeadIndented(level)) {
104+
final buffer = StringBuffer();
105+
for (final line in lines) {
106+
buffer.write('\n');
107+
buffer.write(line);
108+
}
109+
return buffer.toString();
110+
} else {
111+
return lines.join('\n');
112+
}
113+
}
114+
115+
static final int DEFAULT_METHOD_COUNT = isWeb ? 2 : 3;
116+
117+
static final int DEFAULT_ERROR_METHOD_COUNT = isWeb ? 8 : 12;
118+
119+
static final int DEFAULT_LINE_LENGTH = consoleColumns;
120+
121+
static final bool DEFAULT_USE_COLORS = consoleSupportsColors;
122+
123+
static final bool DEFAULT_USE_EMOJI = consoleSupportsEmoji;
124+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import 'package:logger/logger.dart';
2+
3+
import 'platform.dart';
4+
5+
bool isPlatformWebImpl() => false;
6+
7+
bool isPlatformVMImpl() => false;
8+
9+
bool getPlatformConsoleAcceptsColorsImpl() => false;
10+
11+
int getPlatformConsoleColumnsImpl() => 120;
12+
13+
ConsolePrinter getPlatformConsoleLogPrinter() => (arg) => print(arg);
14+
15+
ConsolePrinter getPlatformConsoleInfoPrinter() => (arg) => print(arg);
16+
17+
ConsolePrinter getPlatformConsoleWarnPrinter() => (arg) => print(arg);
18+
19+
ConsolePrinter getPlatformConsoleErrorPrinter() => (arg) => print(arg);
20+
21+
bool isPlatformConsolePrinterHeadIndented(Level level) => false;

lib/src/platform/platform_vm.dart

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import 'dart:io' as io;
2+
3+
import 'package:logger/logger.dart';
4+
5+
import 'platform.dart';
6+
7+
bool isPlatformWebImpl() => false;
8+
9+
bool isPlatformVMImpl() => true;
10+
11+
bool _platformConsoleAcceptsColors;
12+
13+
bool getPlatformConsoleAcceptsColorsImpl() {
14+
if (_platformConsoleAcceptsColors == null) {
15+
try {
16+
_platformConsoleAcceptsColors = io.stdout.supportsAnsiEscapes;
17+
} catch (e) {
18+
_platformConsoleAcceptsColors = false;
19+
}
20+
}
21+
return _platformConsoleAcceptsColors;
22+
}
23+
24+
int _platformConsoleColumns;
25+
26+
int getPlatformConsoleColumnsImpl() {
27+
if (_platformConsoleColumns == null) {
28+
try {
29+
_platformConsoleColumns = io.stdout.terminalColumns;
30+
} catch (e) {
31+
_platformConsoleColumns = 120;
32+
}
33+
}
34+
35+
return _platformConsoleColumns;
36+
}
37+
38+
ConsolePrinter getPlatformConsoleLogPrinter() => _stdoutWriteln;
39+
40+
ConsolePrinter getPlatformConsoleInfoPrinter() => _stdoutWriteln;
41+
42+
ConsolePrinter getPlatformConsoleWarnPrinter() => _stdoutWriteln;
43+
44+
ConsolePrinter getPlatformConsoleErrorPrinter() =>
45+
LogPlatform.enableSTDERR ? _stderrWriteln : _stdoutWriteln;
46+
47+
void _stdoutWriteln(String arg) => io.stdout.writeln(arg);
48+
49+
void _stderrWriteln(String arg) => io.stderr.writeln(arg);
50+
51+
bool isPlatformConsolePrinterHeadIndented(Level level) => false;

lib/src/platform/platform_web.dart

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import 'dart:html';
2+
3+
import 'package:logger/logger.dart';
4+
5+
import 'platform.dart';
6+
7+
bool isPlatformWebImpl() => true;
8+
9+
bool isPlatformVMImpl() => false;
10+
11+
bool getPlatformConsoleAcceptsColorsImpl() => false;
12+
13+
int getPlatformConsoleColumnsImpl() => 80;
14+
15+
ConsolePrinter getPlatformConsoleLogPrinter() =>
16+
(arg) => window.console.log(arg);
17+
18+
ConsolePrinter getPlatformConsoleInfoPrinter() =>
19+
(arg) => window.console.info(arg);
20+
21+
ConsolePrinter getPlatformConsoleWarnPrinter() =>
22+
(arg) => window.console.warn(arg);
23+
24+
ConsolePrinter getPlatformConsoleErrorPrinter() =>
25+
(arg) => window.console.error(arg);
26+
27+
bool isPlatformConsolePrinterHeadIndented(Level level) {
28+
if (_isChrome()) {
29+
return level == Level.warning || level == Level.error || level == Level.wtf;
30+
}
31+
return false;
32+
}
33+
34+
bool _chrome;
35+
36+
bool _isChrome() {
37+
_chrome ??= _getUserAgent().contains('chrome');
38+
return _chrome;
39+
}
40+
41+
String _userAgent;
42+
43+
String _getUserAgent() {
44+
if (_userAgent == null) {
45+
String userAgent;
46+
try {
47+
userAgent = window.navigator.userAgent;
48+
} catch (e) {
49+
userAgent = '';
50+
}
51+
_userAgent = (userAgent ?? '').toLowerCase();
52+
}
53+
return _userAgent;
54+
}

lib/src/printers/pretty_printer.dart

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import 'dart:convert';
22

3+
import 'package:logger/src/ansi_color.dart';
34
import 'package:logger/src/logger.dart';
45
import 'package:logger/src/log_printer.dart';
5-
import 'package:logger/src/ansi_color.dart';
6+
import 'package:logger/src/platform/platform.dart';
67

78
/// Default implementation of [LogPrinter].
89
///
9-
/// Outut looks like this:
10+
/// Output looks like this:
1011
/// ```
1112
/// ┌──────────────────────────
1213
/// │ Error info
@@ -56,30 +57,52 @@ class PrettyPrinter extends LogPrinter {
5657

5758
static DateTime _startTime;
5859

60+
/// Amount of [StackTrace] lines to show with message (non-error log).
61+
/// Defaults to LogPlatform.DEFAULT_METHOD_COUNT.
5962
final int methodCount;
63+
64+
/// Amount of error [StackTrace] lines to show with message.
65+
/// Defaults to LogPlatform.DEFAULT_ERROR_METHOD_COUNT.
6066
final int errorMethodCount;
67+
68+
/// Columns length to format log.
69+
/// Defaults to LogPlatform.DEFAULT_LINE_LENGTH.
6170
final int lineLength;
71+
72+
/// If [true] uses colors for logging.
73+
/// Defaults to LogPlatform.DEFAULT_USE_COLORS.
6274
final bool colors;
75+
76+
/// If [true] uses emojis to identify logging types.
77+
/// Defaults to LogPlatform.DEFAULT_USE_EMOJI.
6378
final bool printEmojis;
79+
80+
/// If [true] shows a line with log event time.
81+
/// Defaults to false.
6482
final bool printTime;
6583

6684
String _topBorder = '';
6785
String _middleBorder = '';
6886
String _bottomBorder = '';
6987

7088
PrettyPrinter({
71-
this.methodCount = 2,
72-
this.errorMethodCount = 8,
73-
this.lineLength = 120,
74-
this.colors = true,
75-
this.printEmojis = true,
89+
int methodCount,
90+
int errorMethodCount,
91+
int lineLength,
92+
bool colors,
93+
bool printEmojis,
7694
this.printTime = false,
77-
}) {
95+
}) : methodCount = methodCount ?? LogPlatform.DEFAULT_METHOD_COUNT,
96+
errorMethodCount =
97+
errorMethodCount ?? LogPlatform.DEFAULT_ERROR_METHOD_COUNT,
98+
lineLength = lineLength ?? LogPlatform.DEFAULT_LINE_LENGTH,
99+
colors = colors ?? LogPlatform.DEFAULT_USE_COLORS,
100+
printEmojis = printEmojis ?? LogPlatform.DEFAULT_USE_EMOJI {
78101
_startTime ??= DateTime.now();
79102

80103
var doubleDividerLine = StringBuffer();
81104
var singleDividerLine = StringBuffer();
82-
for (var i = 0; i < lineLength - 1; i++) {
105+
for (var i = 0; i < this.lineLength - 1; i++) {
83106
doubleDividerLine.write(doubleDivider);
84107
singleDividerLine.write(singleDivider);
85108
}

0 commit comments

Comments
 (0)