| 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 log; | 6 library log; |
| 7 | 7 |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 import 'io.dart'; | 9 import 'io.dart'; |
| 10 | 10 |
| 11 typedef LogFn(Level level, message); | 11 typedef LogFn(Entry entry); |
| 12 final Map<Level, LogFn> _loggers = new Map<Level, LogFn>(); | 12 final Map<Level, LogFn> _loggers = new Map<Level, LogFn>(); |
| 13 | 13 |
| 14 /// The list of recorded log messages. Will only be recorded if | 14 /// The list of recorded log messages. Will only be recorded if |
| 15 /// [recordTranscript()] is called. | 15 /// [recordTranscript()] is called. |
| 16 List<Entry> _transcript; | 16 List<Entry> _transcript; |
| 17 | 17 |
| 18 /// An enum type for defining the different logging levels. By default, [ERROR] | 18 /// An enum type for defining the different logging levels. By default, [ERROR] |
| 19 /// and [WARNING] messages are printed to sterr. [MESSAGE] messages are printed | 19 /// and [WARNING] messages are printed to sterr. [MESSAGE] messages are printed |
| 20 /// to stdout, and others are ignored. | 20 /// to stdout, and others are ignored. |
| 21 class Level { | 21 class Level { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 42 const Level._(this.name); | 42 const Level._(this.name); |
| 43 final String name; | 43 final String name; |
| 44 | 44 |
| 45 String toString() => name; | 45 String toString() => name; |
| 46 int get hashCode => name.hashCode; | 46 int get hashCode => name.hashCode; |
| 47 } | 47 } |
| 48 | 48 |
| 49 /// A single log entry. | 49 /// A single log entry. |
| 50 class Entry { | 50 class Entry { |
| 51 final Level level; | 51 final Level level; |
| 52 final String message; | 52 final List<String> lines; |
| 53 | 53 |
| 54 Entry(this.level, this.message); | 54 Entry(this.level, this.lines); |
| 55 } | 55 } |
| 56 | 56 |
| 57 /// Logs [message] at [Level.ERROR]. | 57 /// Logs [message] at [Level.ERROR]. |
| 58 void error(message) => write(Level.ERROR, message); | 58 void error(message) => write(Level.ERROR, message); |
| 59 | 59 |
| 60 /// Logs [message] at [Level.WARNING]. | 60 /// Logs [message] at [Level.WARNING]. |
| 61 void warning(message) => write(Level.WARNING, message); | 61 void warning(message) => write(Level.WARNING, message); |
| 62 | 62 |
| 63 /// Logs [message] at [Level.MESSAGE]. | 63 /// Logs [message] at [Level.MESSAGE]. |
| 64 void message(message) => write(Level.MESSAGE, message); | 64 void message(message) => write(Level.MESSAGE, message); |
| 65 | 65 |
| 66 /// Logs [message] at [Level.IO]. | 66 /// Logs [message] at [Level.IO]. |
| 67 void io(message) => write(Level.IO, message); | 67 void io(message) => write(Level.IO, message); |
| 68 | 68 |
| 69 /// Logs [message] at [Level.FINE]. | 69 /// Logs [message] at [Level.FINE]. |
| 70 void fine(message) => write(Level.FINE, message); | 70 void fine(message) => write(Level.FINE, message); |
| 71 | 71 |
| 72 /// Logs [message] at [level]. | 72 /// Logs [message] at [level]. |
| 73 void write(Level level, message) { | 73 void write(Level level, message) { |
| 74 if (_loggers.isEmpty) showNormal(); | 74 if (_loggers.isEmpty) showNormal(); |
| 75 | 75 |
| 76 var lines = message.toString().split(NEWLINE_PATTERN); |
| 77 var entry = new Entry(level, lines); |
| 78 |
| 76 var logFn = _loggers[level]; | 79 var logFn = _loggers[level]; |
| 77 if (logFn != null) logFn(level, message); | 80 if (logFn != null) logFn(entry); |
| 78 | 81 |
| 79 if (_transcript != null) { | 82 if (_transcript != null) _transcript.add(entry); |
| 80 _transcript.add(new Entry(level, '$message')); | |
| 81 } | |
| 82 } | 83 } |
| 83 | 84 |
| 84 /// Logs an asynchronous IO operation. Logs [startMessage] before the operation | 85 /// Logs an asynchronous IO operation. Logs [startMessage] before the operation |
| 85 /// starts, then when [operation] completes, invokes [endMessage] with the | 86 /// starts, then when [operation] completes, invokes [endMessage] with the |
| 86 /// completion value and logs the result of that. Returns a future that | 87 /// completion value and logs the result of that. Returns a future that |
| 87 /// completes after the logging is done. | 88 /// completes after the logging is done. |
| 88 /// | 89 /// |
| 89 /// If [endMessage] is omitted, then logs "Begin [startMessage]" before the | 90 /// If [endMessage] is omitted, then logs "Begin [startMessage]" before the |
| 90 /// operation and "End [startMessage]" after it. | 91 /// operation and "End [startMessage]" after it. |
| 91 Future ioAsync(String startMessage, Future operation, | 92 Future ioAsync(String startMessage, Future operation, |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 _transcript = <Entry>[]; | 148 _transcript = <Entry>[]; |
| 148 } | 149 } |
| 149 | 150 |
| 150 /// If [recordTranscript()] was called, then prints the previously recorded log | 151 /// If [recordTranscript()] was called, then prints the previously recorded log |
| 151 /// transcript to stderr. | 152 /// transcript to stderr. |
| 152 void dumpTranscript() { | 153 void dumpTranscript() { |
| 153 if (_transcript == null) return; | 154 if (_transcript == null) return; |
| 154 | 155 |
| 155 stderr.writeString('---- Log transcript ----\n'); | 156 stderr.writeString('---- Log transcript ----\n'); |
| 156 for (var entry in _transcript) { | 157 for (var entry in _transcript) { |
| 157 _logToStderrWithLabel(entry.level, entry.message); | 158 _logToStderrWithLabel(entry); |
| 158 } | 159 } |
| 159 stderr.writeString('---- End log transcript ----\n'); | 160 stderr.writeString('---- End log transcript ----\n'); |
| 160 } | 161 } |
| 161 | 162 |
| 162 /// Sets the verbosity to "normal", which shows errors, warnings, and messages. | 163 /// Sets the verbosity to "normal", which shows errors, warnings, and messages. |
| 163 void showNormal() { | 164 void showNormal() { |
| 164 _loggers[Level.ERROR] = _logToStderr; | 165 _loggers[Level.ERROR] = _logToStderr; |
| 165 _loggers[Level.WARNING] = _logToStderr; | 166 _loggers[Level.WARNING] = _logToStderr; |
| 166 _loggers[Level.MESSAGE] = _logToStdout; | 167 _loggers[Level.MESSAGE] = _logToStdout; |
| 167 _loggers[Level.IO] = null; | 168 _loggers[Level.IO] = null; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 181 /// Sets the verbosity to "all", which logs ALL the things. | 182 /// Sets the verbosity to "all", which logs ALL the things. |
| 182 void showAll() { | 183 void showAll() { |
| 183 _loggers[Level.ERROR] = _logToStderrWithLabel; | 184 _loggers[Level.ERROR] = _logToStderrWithLabel; |
| 184 _loggers[Level.WARNING] = _logToStderrWithLabel; | 185 _loggers[Level.WARNING] = _logToStderrWithLabel; |
| 185 _loggers[Level.MESSAGE] = _logToStdoutWithLabel; | 186 _loggers[Level.MESSAGE] = _logToStdoutWithLabel; |
| 186 _loggers[Level.IO] = _logToStderrWithLabel; | 187 _loggers[Level.IO] = _logToStderrWithLabel; |
| 187 _loggers[Level.FINE] = _logToStderrWithLabel; | 188 _loggers[Level.FINE] = _logToStderrWithLabel; |
| 188 } | 189 } |
| 189 | 190 |
| 190 /// Log function that prints the message to stdout. | 191 /// Log function that prints the message to stdout. |
| 191 void _logToStdout(Level level, message) { | 192 void _logToStdout(Entry entry) { |
| 192 print('$message'); | 193 _logToStream(stdout, entry, showLabel: false); |
| 193 } | 194 } |
| 194 | 195 |
| 195 /// Log function that prints the message to stdout with the level name. | 196 /// Log function that prints the message to stdout with the level name. |
| 196 void _logToStdoutWithLabel(Level level, message) { | 197 void _logToStdoutWithLabel(Entry entry) { |
| 197 print(_splitAndPrefix(level, message)); | 198 _logToStream(stdout, entry, showLabel: true); |
| 198 } | 199 } |
| 199 | 200 |
| 200 /// Log function that prints the message to stderr. | 201 /// Log function that prints the message to stderr. |
| 201 void _logToStderr(Level level, message) { | 202 void _logToStderr(Entry entry) { |
| 202 stderr.writeString('$message\n'); | 203 _logToStream(stderr, entry, showLabel: false); |
| 203 } | 204 } |
| 204 | 205 |
| 205 /// Log function that prints the message to stderr with the level name. | 206 /// Log function that prints the message to stderr with the level name. |
| 206 void _logToStderrWithLabel(Level level, message) { | 207 void _logToStderrWithLabel(Entry entry) { |
| 207 stderr.writeString(_splitAndPrefix(level, message)); | 208 _logToStream(stderr, entry, showLabel: true); |
| 208 stderr.writeString('\n'); | |
| 209 } | 209 } |
| 210 | 210 |
| 211 /// Add the level prefix to the first line of [message] and prefix subsequent | 211 void _logToStream(OutputStream stream, Entry entry, {bool showLabel}) { |
| 212 /// lines with "|". | 212 bool firstLine = true; |
| 213 String _splitAndPrefix(Level level, message) { | 213 for (var line in entry.lines) { |
| 214 // TODO(rnystrom): We're doing lots of splitting and joining in here. If that | 214 if (showLabel) { |
| 215 // becomes a performance problem, we can optimize this to write directly to | 215 if (firstLine) { |
| 216 // stdout/stderr a line at a time. | 216 stream.writeString(entry.level.name); |
| 217 return "$level: ${Strings.join(message.toString().split('\n'), '\n | ')}"; | 217 stream.writeString(': '); |
| 218 } else { |
| 219 stream.writeString(' | '); |
| 220 } |
| 221 } |
| 222 |
| 223 stream.writeString(line); |
| 224 stream.writeString('\n'); |
| 225 |
| 226 firstLine = false; |
| 227 } |
| 218 } | 228 } |
| OLD | NEW |