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 logging; | |
nweiz
2012/12/05 23:56:54
It makes me sad that we're rolling our own logging
Bob Nystrom
2012/12/06 01:33:26
I spent some time integrating pkg/logging in first
| |
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. | |
nweiz
2012/12/05 23:56:54
Mention which levels are enabled by default and wh
Bob Nystrom
2012/12/06 01:33:26
Done.
| |
19 class Level { | |
20 /// An error occurred and an operation could not be completed. Usually shown | |
21 /// to the user on stderr. | |
22 static const ERROR = const Level("Error"); | |
23 | |
24 /// Something unexpected happened, but the program was able to continue, | |
25 /// though possibly in a degraded fashion. | |
26 static const WARNING = const Level("Warning"); | |
27 | |
28 /// A message intended specifically to be shown to the user. | |
29 static const MESSAGE = const Level("Message"); | |
30 | |
31 /// Some interaction with the external world occurred, such as a network | |
32 /// operation, process spawning, or file IO. | |
33 static const IO = const Level("IO"); | |
34 | |
35 /// Fine-grained and verbose additional information. Can be used to provide | |
36 /// program state context for other logs (such as what pub was doing when an | |
37 /// IO operation occurred) or just more detail for an operation. | |
38 static const FINE = const Level("FINE"); | |
39 | |
40 const Level(this.name); | |
nweiz
2012/12/05 23:56:54
This should probably be private.
Bob Nystrom
2012/12/06 01:33:26
Done.
| |
41 final String name; | |
42 | |
43 String toString() => name; | |
44 int get hashCode => name.hashCode; | |
45 } | |
46 | |
47 /// A single log entry. | |
48 class Entry { | |
nweiz
2012/12/05 23:56:54
I'm not sure this class is more useful than Pair<L
Bob Nystrom
2012/12/06 01:33:26
I like nice named types and Dart is pretty compact
| |
49 final Level level; | |
50 final String message; | |
51 | |
52 Entry(this.level, this.message); | |
53 } | |
54 | |
55 /// Logs [message] at [Level.ERROR]. | |
56 void error(message) => write(Level.ERROR, message); | |
57 | |
58 /// Logs [message] at [Level.WARNING]. | |
59 void warning(message) => write(Level.WARNING, message); | |
60 | |
61 /// Logs [message] at [Level.MESSAGE]. | |
62 void message(message) => write(Level.MESSAGE, message); | |
63 | |
64 /// Logs [message] at [Level.IO]. | |
65 void io(message) => write(Level.IO, message); | |
66 | |
67 /// Logs [message] at [Level.FINE]. | |
68 void fine(message) => write(Level.FINE, message); | |
69 | |
70 /// Logs [message] at [level]. | |
71 void write(Level level, message) { | |
72 if (_loggers.isEmpty) showNormal(); | |
73 | |
74 var logFn = _loggers[level]; | |
75 if (logFn != null) logFn(level, message); | |
76 | |
77 if (_transcript != null) { | |
78 _transcript.add(new Entry(level, '$message')); | |
79 } | |
80 } | |
81 | |
82 /// Logs an asynchronous IO operation. Logs [startMessage] before the operation | |
83 /// starts, then when [operation] completes, invokes [endMessage] with the | |
84 /// completion value and logs the result of that. Returns a future that | |
85 /// completes after the logging is done. | |
86 /// | |
87 /// If [endMessage] is omitted, then logs "Begin [startMessage]" before the | |
88 /// operation and "End [startMessage]" after it. | |
89 Future ioAsync(String startMessage, Future operation, | |
nweiz
2012/12/05 23:56:54
I'm not sure these arguments are in the right orde
Bob Nystrom
2012/12/06 01:33:26
I don't mind stuff coming before functions as much
nweiz
2012/12/06 19:40:02
But the future actually starts before either messa
| |
90 [String endMessage(value)]) { | |
91 if (endMessage == null) { | |
92 io("Begin $startMessage."); | |
93 } else { | |
94 io(startMessage); | |
95 } | |
96 | |
97 return operation.transform((result) { | |
98 if (endMessage == null) { | |
99 io("End $startMessage."); | |
100 } else { | |
101 io(endMessage(result)); | |
102 } | |
103 return result; | |
104 }); | |
105 } | |
106 | |
107 /// Logs the spawning of an [executable] process with [arguments] at [INFO] | |
nweiz
2012/12/05 23:56:54
"INFO" -> "IO"
Bob Nystrom
2012/12/06 01:33:26
Done.
| |
108 /// level. | |
109 void process(String executable, List<String> arguments) { | |
110 io("Spawning $executable ${Strings.join(arguments, ' ')}"); | |
111 } | |
112 | |
113 /// Logs the results of running [executable] with [arguments]. | |
114 void processResult(String executable, List<String> arguments, | |
nweiz
2012/12/05 23:56:54
"arguments" is unused.
Bob Nystrom
2012/12/06 01:33:26
Done.
| |
115 PubProcessResult result) { | |
116 io("Finished $executable. Exit code ${result.exitCode}."); | |
117 | |
118 dumpOutput(String name, List<String> output) { | |
119 if (output.length == 0) { | |
nweiz
2012/12/05 23:56:54
Add a sanity check for length.
Bob Nystrom
2012/12/06 01:33:26
Done.
| |
120 fine("Nothing output on $name."); | |
121 } else { | |
122 fine("$name:"); | |
123 output.forEach(fine); | |
nweiz
2012/12/05 23:56:54
Another good place to indent.
Bob Nystrom
2012/12/06 01:33:26
See other comments.
| |
124 } | |
125 } | |
126 | |
127 dumpOutput("stdout", result.stdout); | |
128 dumpOutput("stderr", result.stderr); | |
129 } | |
130 | |
131 /// Enables recording of log entries. | |
132 void recordTranscript() { | |
133 _transcript = <Entry>[]; | |
134 } | |
135 | |
136 /// If [recordTranscript()] was called, then prints the previously recorded log | |
137 /// transcript to stderr. | |
138 void dumpTranscript() { | |
139 if (_transcript == null) return; | |
140 | |
141 stderr.writeString('---- Log transcript ----\n'); | |
142 for (var entry in _transcript) { | |
143 _logToStderrWithLabel(entry.level, entry.message); | |
144 } | |
145 stderr.writeString('---- End log transcript ----\n'); | |
146 } | |
147 | |
148 /// Sets the verbosity to "normal", which shows errors, warnings, and messages. | |
149 void showNormal() { | |
150 _loggers[Level.ERROR] = _logToStderr; | |
151 _loggers[Level.WARNING] = _logToStderrWithLabel; | |
152 _loggers[Level.MESSAGE] = _logToStdout; | |
153 _loggers[Level.IO] = null; | |
154 _loggers[Level.FINE] = null; | |
155 } | |
156 | |
157 /// Sets the verbosity to "io", which shows errors, warnings, messages, and IO | |
158 /// event logs. | |
159 void showIO() { | |
160 _loggers[Level.ERROR] = _logToStderrWithLabel; | |
161 _loggers[Level.WARNING] = _logToStderrWithLabel; | |
162 _loggers[Level.MESSAGE] = _logToStdoutWithLabel; | |
163 _loggers[Level.IO] = _logToStderrWithLabel; | |
164 _loggers[Level.FINE] = null; | |
165 } | |
166 | |
167 /// Sets the verbosity to "all", which logs ALL the things. | |
168 void showAll() { | |
169 _loggers[Level.ERROR] = _logToStderrWithLabel; | |
170 _loggers[Level.WARNING] = _logToStderrWithLabel; | |
171 _loggers[Level.MESSAGE] = _logToStdoutWithLabel; | |
172 _loggers[Level.IO] = _logToStderrWithLabel; | |
173 _loggers[Level.FINE] = _logToStderrWithLabel; | |
174 } | |
175 | |
176 /// Log function that prints the message to stdout. | |
177 void _logToStdout(Level level, message) { | |
178 print('$message'); | |
nweiz
2012/12/05 23:56:54
You could automatically handle that indentation I'
Bob Nystrom
2012/12/06 01:33:26
See other comments. :)
| |
179 } | |
180 | |
181 /// Log function that prints the message to stdout with the level name. | |
182 void _logToStdoutWithLabel(Level level, message) { | |
183 print('$level: $message'); | |
184 } | |
185 | |
186 /// Log function that prints the message to stderr. | |
187 void _logToStderr(Level level, message) { | |
188 stderr.writeString('$message\n'); | |
189 } | |
190 | |
191 /// Log function that prints the message to stderr with the level name. | |
192 void _logToStderrWithLabel(Level level, message) { | |
193 stderr.writeString('$level: $message\n'); | |
194 } | |
OLD | NEW |