OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 /// Message logging. | |
6 library log; | |
7 | |
8 import 'dart:io'; | |
9 import 'io.dart'; | |
10 | |
11 typedef LogFn(Level level, message); | |
12 final Map<Level, LogFn> _loggers = new Map<Level, LogFn>(); | |
13 | |
14 /// The list of recorded log messages. Will only be recorded if | |
15 /// [recordTranscript()] is called. | |
16 List<Entry> _transcript; | |
17 | |
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 | |
20 /// to stdout, and others are ignored. | |
21 class Level { | |
22 /// An error occurred and an operation could not be completed. Usually shown | |
23 /// to the user on stderr. | |
24 static const ERROR = const Level._("ERR "); | |
25 | |
26 /// Something unexpected happened, but the program was able to continue, | |
27 /// though possibly in a degraded fashion. | |
28 static const WARNING = const Level._("WARN"); | |
29 | |
30 /// A message intended specifically to be shown to the user. | |
31 static const MESSAGE = const Level._("MSG "); | |
32 | |
33 /// Some interaction with the external world occurred, such as a network | |
34 /// operation, process spawning, or file IO. | |
35 static const IO = const Level._("IO "); | |
36 | |
37 /// Fine-grained and verbose additional information. Can be used to provide | |
38 /// program state context for other logs (such as what pub was doing when an | |
39 /// IO operation occurred) or just more detail for an operation. | |
40 static const FINE = const Level._("FINE"); | |
41 | |
42 const Level._(this.name); | |
43 final String name; | |
44 | |
45 String toString() => name; | |
46 int get hashCode => name.hashCode; | |
47 } | |
48 | |
49 /// A single log entry. | |
50 class Entry { | |
51 final Level level; | |
52 final String message; | |
53 | |
54 Entry(this.level, this.message); | |
55 } | |
56 | |
57 /// Logs [message] at [Level.ERROR]. | |
58 void error(message) => write(Level.ERROR, message); | |
59 | |
60 /// Logs [message] at [Level.WARNING]. | |
61 void warning(message) => write(Level.WARNING, message); | |
62 | |
63 /// Logs [message] at [Level.MESSAGE]. | |
64 void message(message) => write(Level.MESSAGE, message); | |
65 | |
66 /// Logs [message] at [Level.IO]. | |
67 void io(message) => write(Level.IO, message); | |
68 | |
69 /// Logs [message] at [Level.FINE]. | |
70 void fine(message) => write(Level.FINE, message); | |
71 | |
72 /// Logs [message] at [level]. | |
73 void write(Level level, message) { | |
74 if (_loggers.isEmpty) showNormal(); | |
75 | |
76 var logFn = _loggers[level]; | |
77 if (logFn != null) logFn(level, message); | |
78 | |
79 if (_transcript != null) { | |
80 _transcript.add(new Entry(level, '$message')); | |
81 } | |
82 } | |
83 | |
84 /// Logs an asynchronous IO operation. Logs [startMessage] before the operation | |
85 /// starts, then when [operation] completes, invokes [endMessage] with the | |
86 /// completion value and logs the result of that. Returns a future that | |
87 /// completes after the logging is done. | |
88 /// | |
89 /// If [endMessage] is omitted, then logs "Begin [startMessage]" before the | |
90 /// operation and "End [startMessage]" after it. | |
91 Future ioAsync(String startMessage, Future operation, | |
92 [String endMessage(value)]) { | |
93 if (endMessage == null) { | |
94 io("Begin $startMessage."); | |
95 } else { | |
96 io(startMessage); | |
97 } | |
98 | |
99 return operation.transform((result) { | |
100 if (endMessage == null) { | |
101 io("End $startMessage."); | |
102 } else { | |
103 io(endMessage(result)); | |
104 } | |
105 return result; | |
106 }); | |
107 } | |
108 | |
109 /// Logs the spawning of an [executable] process with [arguments] at [IO] | |
110 /// level. | |
111 void process(String executable, List<String> arguments) { | |
112 io("Spawning $executable ${Strings.join(arguments, ' ')}"); | |
113 } | |
114 | |
115 /// Logs the results of running [executable]. | |
116 void processResult(String executable, PubProcessResult result) { | |
117 // Log it all as one message so that it shows up as a single unit in the logs. | |
118 var buffer = new StringBuffer(); | |
119 buffer.add("Finished $executable. Exit code ${result.exitCode}."); | |
120 | |
121 dumpOutput(String name, List<String> output) { | |
122 if (output.length == 0) { | |
123 buffer.add("Nothing output on $name."); | |
124 } else { | |
125 buffer.add("$name:"); | |
126 var numLines = 0; | |
127 for (var line in output) { | |
128 if (++numLines > 1000) { | |
129 buffer.add('[${output.length - 1000}] more lines of output truncated.. .]'); | |
nweiz
2012/12/07 21:47:06
Long line.
Bob Nystrom
2012/12/07 22:19:56
Done.
| |
130 break; | |
131 } | |
132 | |
133 buffer.add(line); | |
134 } | |
135 } | |
136 } | |
137 | |
138 dumpOutput("stdout", result.stdout); | |
139 dumpOutput("stderr", result.stderr); | |
140 | |
141 io(buffer.toString()); | |
142 } | |
143 | |
144 /// Enables recording of log entries. | |
145 void recordTranscript() { | |
146 _transcript = <Entry>[]; | |
147 } | |
148 | |
149 /// If [recordTranscript()] was called, then prints the previously recorded log | |
150 /// transcript to stderr. | |
151 void dumpTranscript() { | |
152 if (_transcript == null) return; | |
153 | |
154 stderr.writeString('---- Log transcript ----\n'); | |
155 for (var entry in _transcript) { | |
156 _logToStderrWithLabel(entry.level, entry.message); | |
157 } | |
158 stderr.writeString('---- End log transcript ----\n'); | |
159 } | |
160 | |
161 /// Sets the verbosity to "normal", which shows errors, warnings, and messages. | |
162 void showNormal() { | |
163 _loggers[Level.ERROR] = _logToStderr; | |
164 _loggers[Level.WARNING] = _logToStderr; | |
165 _loggers[Level.MESSAGE] = _logToStdout; | |
166 _loggers[Level.IO] = null; | |
167 _loggers[Level.FINE] = null; | |
168 } | |
169 | |
170 /// Sets the verbosity to "io", which shows errors, warnings, messages, and IO | |
171 /// event logs. | |
172 void showIO() { | |
173 _loggers[Level.ERROR] = _logToStderrWithLabel; | |
174 _loggers[Level.WARNING] = _logToStderrWithLabel; | |
175 _loggers[Level.MESSAGE] = _logToStdoutWithLabel; | |
176 _loggers[Level.IO] = _logToStderrWithLabel; | |
177 _loggers[Level.FINE] = null; | |
178 } | |
179 | |
180 /// Sets the verbosity to "all", which logs ALL the things. | |
181 void showAll() { | |
182 _loggers[Level.ERROR] = _logToStderrWithLabel; | |
183 _loggers[Level.WARNING] = _logToStderrWithLabel; | |
184 _loggers[Level.MESSAGE] = _logToStdoutWithLabel; | |
185 _loggers[Level.IO] = _logToStderrWithLabel; | |
186 _loggers[Level.FINE] = _logToStderrWithLabel; | |
187 } | |
188 | |
189 /// Log function that prints the message to stdout. | |
190 void _logToStdout(Level level, message) { | |
191 print('$message'); | |
192 } | |
193 | |
194 /// Log function that prints the message to stdout with the level name. | |
195 void _logToStdoutWithLabel(Level level, message) { | |
196 print(_splitAndPrefix(level, message)); | |
197 } | |
198 | |
199 /// Log function that prints the message to stderr. | |
200 void _logToStderr(Level level, message) { | |
201 stderr.writeString('$message\n'); | |
202 } | |
203 | |
204 /// Log function that prints the message to stderr with the level name. | |
205 void _logToStderrWithLabel(Level level, message) { | |
206 stderr.writeString(_splitAndPrefix(level, message)); | |
207 stderr.writeString('\n'); | |
208 } | |
209 | |
210 /// Add the level prefix to the first line of [message] and prefix subsequent | |
211 /// lines with "|". | |
212 String _splitAndPrefix(Level level, message) { | |
213 // TODO(rnystrom): We're doing lots of splitting and joining in here. If that | |
214 // becomes a performance problem, we can optimize this to write directly to | |
215 // stdout/stderr a line at a time. | |
216 return "$level: ${Strings.join(message.toString().split('\n'), '\n | ')}"; | |
217 } | |
OLD | NEW |