Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: lib/logging/logging.dart

Issue 10693042: first version of a logging library. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: addressing cl comments Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/lib/logging/logging_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 /**
6 * Provides APIs for debugging and error logging. This library introduces
7 * abstractions similar to those used in other languages, such as the Closure JS
8 * Logger and java.util.logging.Logger.
9 */
10 #library('logging');
11
12 /**
13 * Whether to allow fine-grain logging and configuration of loggers in a
14 * hierarchy. When false, all logging is merged in the root logger.
15 */
16 bool hierarchicalLoggingEnabled = false;
17
18 /**
19 * Level for the root-logger. This will be the level of all loggers if
20 * [hierarchicalLoggingEnabled] is false.
21 */
22 Level _rootLevel = Level.INFO;
23
24
25 /**
26 * Use a [Logger] to log debug messages. [Logger]s are named using a
27 * hierarchical dot-separated name convention.
28 */
29 class Logger {
30 /** Simple name of this logger. */
31 final String name;
32
33 /** The full name of this logger, which includes also the parent's names. */
gram 2012/06/29 19:55:21 Remove 'also'
Siggi Cherem (dart-lang) 2012/06/29 20:16:52 Done.
34 String get fullName() =>
35 (parent == null || parent.name == '') ? name : '${parent.fullName}.$name';
gram 2012/06/29 19:55:21 What is I have three levels A, B, C, and A is name
Siggi Cherem (dart-lang) 2012/06/29 20:16:52 as we discussed in person - this shouldn't be a pr
36
37 /** Parent of this logger in the hierarchy of loggers. */
38 final Logger parent;
39
40 /** Logging [Level] used for entries generated on this logger. */
41 Level _level;
42
43 /** Children in the hierarchy of loggers, indexed by their simple names. */
44 Map<String, Logger> children;
45
46 /** Handlers used to process log entries in this logger. */
47 List<LoggerHandler> _handlers;
48
49 /**
50 * Singleton constructor. Calling `new Logger(name)` will return the same
51 * actual instance whenever it is called with the same string name.
52 */
53 factory Logger(String name) {
54 if (_loggers == null) _loggers = <Logger>{};
55 if (_loggers.containsKey(name)) return _loggers[name];
gram 2012/06/29 19:55:21 you could have an "else" here.
Siggi Cherem (dart-lang) 2012/06/29 20:16:52 true. as we briefly discussed :), left as is to ma
56
57 // Split hierarchical names (separated with '.').
58 int dot = name.lastIndexOf('.');
59 Logger parent = null;
60 String thisName;
61 if (dot == -1) {
62 if (name != '') parent = new Logger('');
63 thisName = name;
64 } else {
65 parent = new Logger(name.substring(0, dot));
66 thisName = name.substring(dot + 1);
67 }
68 final res = new Logger._internal(thisName, parent);
69 _loggers[name] = res;
70 return res;
71 }
72
73 Logger._internal(this.name, this.parent)
74 : children = new Map<String, Logger>() {
75 if (parent != null) parent.children[name] = this;
76 }
77
78 /**
79 * Effective level considering the levels established in this logger's parents
80 * (when [hierarchicalLoggingEnabled] is true).
81 */
82 Level get level() {
83 if (hierarchicalLoggingEnabled) {
84 if (_level != null) return _level;
85 if (parent != null) return parent.level;
86 }
87 return _rootLevel;
88 }
89
90 /** Override the level for this particular [Logger] and its children. */
91 Level set level(value) {
92 if (hierarchicalLoggingEnabled && parent != null) {
93 _level = value;
94 } else {
95 if (parent != null) {
96 throw new UnsupportedOperationException(
97 'Please set "hierarchicalLoggingEnabled" to true if you want to '
98 'change the level on a non-root logger.');
99 }
100 _rootLevel = value;
101 }
102 }
103
104 /**
105 * Returns an event manager for this [Logger]. You can listen for log messages
106 * by adding a [LoggerHandler] to an event from the event manager, for
107 * instance:
108 * logger.on.record.add((record) { ... });
109 */
110 LoggerEvents get on() => new LoggerEvents(this);
111
112 /** Adds a handler to listen whenever a log record is added to this logger. */
113 void _addHandler(LoggerHandler handler) {
114 if (hierarchicalLoggingEnabled || parent == null) {
115 if (_handlers == null) {
116 _handlers = new List<LoggerHandler>();
117 }
118 _handlers.add(handler);
119 } else {
120 root._addHandler(handler);
121 }
122 }
123
124 /** Remove a previously added handler. */
125 void _removeHandler(LoggerHandler handler) {
126 if (hierarchicalLoggingEnabled || parent == null) {
127 if (_handlers == null) return;
128 int index = _handlers.indexOf(handler);
129 if (index != -1) _handlers.removeRange(index, 1);
130 } else {
131 root._removeHandler(handler);
132 }
133 }
134
135 /** Removes all handlers previously added to this logger. */
136 void _clearHandlers() {
137 if (hierarchicalLoggingEnabled || parent == null) {
138 _handlers = null;
139 } else {
140 root._clearHandlers();
141 }
142 }
143
144 /** Whether a message for [value]'s level is loggable in this logger. */
145 bool isLoggable(Level value) => (value >= level);
146
147 /**
148 * Adds a log record for a [message] at a particular [logLevel] if
149 * `isLoggable(logLevel)` is true. Use this method to create log entries for
150 * user-defined levels. To record a message at a predefined level (e.g.
151 * [Level.INFO], [Level.WARNING], etc) you can use their specialized methods
152 * instead (e.g. [info], [warning], etc).
153 */
154 // TODO(sigmund): add support for logging exceptions.
155 void log(Level logLevel, String message) {
156 if (isLoggable(logLevel)) {
157 var record = new LogRecord(logLevel, message, fullName);
158 if (hierarchicalLoggingEnabled) {
159 var target = this;
160 while (target != null) {
161 target._publish(record);
162 target = target.parent;
163 }
164 } else {
165 root._publish(record);
166 }
167 }
168 }
169
170 /** Log message at level [Level.FINEST]. */
171 void finest(String message) => log(Level.FINEST, message);
172
173 /** Log message at level [Level.FINER]. */
174 void finer(String message) => log(Level.FINER, message);
175
176 /** Log message at level [Level.FINE]. */
177 void fine(String message) => log(Level.FINE, message);
178
179 /** Log message at level [Level.CONFIG]. */
180 void config(String message) => log(Level.CONFIG, message);
181
182 /** Log message at level [Level.INFO]. */
183 void info(String message) => log(Level.INFO, message);
184
185 /** Log message at level [Level.WARNING]. */
186 void warning(String message) => log(Level.WARNING, message);
187
188 /** Log message at level [Level.SEVERE]. */
189 void severe(String message) => log(Level.SEVERE, message);
190
191 /** Log message at level [Level.SHOUT]. */
192 void shout(String message) => log(Level.SHOUT, message);
193
194 void _publish(LogRecord record) {
195 if (_handlers != null) {
196 _handlers.forEach((h) => h(record));
197 }
198 }
199
200 /** Top-level root [Logger]. */
201 static get root() => new Logger('');
202
203 /** All [Logger]s in the system. */
204 static Map<String, Logger> _loggers;
205 }
206
207
208 /** Handler callback to process log entries as they are added to a [Logger]. */
209 typedef void LoggerHandler(LogRecord);
210
211
212 /** Event manager for a [Logger] (holds events that a [Logger] can fire). */
213 class LoggerEvents {
214 final Logger _logger;
215
216 LoggerEvents(this._logger);
217
218 /** Event fired when a log record is added to a [Logger]. */
219 LoggerHandlerList get record() => new LoggerHandlerList(_logger);
220 }
221
222
223 /** List of handlers that will be called on a logger event. */
224 class LoggerHandlerList {
225 Logger _logger;
226
227 LoggerHandlerList(this._logger);
228
229 void add(LoggerHandler handler) => _logger._addHandler(handler);
230 void remove(LoggerHandler handler) => _logger._removeHandler(handler);
231 void clear() => _logger._clearHandlers();
232 }
233
234
235 /**
236 * [Level]s to control logging output. Logging can be enabled to include all
237 * levels above certain [Level]. [Level]s are ordered using an integer
238 * value [Level.value]. The predefined [Level] constants below are sorted as
239 * follows (in descending order): [Level.SHOUT], [Level.SEVERE],
240 * [Level.WARNING], [Level.INFO], [Level.CONFIG], [Level.FINE], [Level.FINER],
241 * [Level.FINEST], and [Level.ALL].
242 *
243 * We recommend using one of the predefined logging levels. If you define your
244 * own level, make sure you use a value between those used in [Level.ALL] and
245 * [Level.OFF].
246 */
247 class Level implements Comparable, Hashable {
248
249 // TODO(sigmund): mark name/value as 'const' when the language supports it.
250 final String name;
251
252 /**
253 * Unique value for this level. Used to order levels, so filtering can exclude
254 * messages whose level is under certain value.
255 */
256 final int value;
257
258 const Level(this.name, this.value);
259
260 /** Special key to turn on logging for all levels ([value] = 0). */
261 static final Level ALL = const Level('ALL', 0);
262
263 /** Special key to turn off all logging ([value] = 2000). */
264 static final Level OFF = const Level('OFF', 2000);
265
266 /** Key for highly detailed tracing ([value] = 300). */
267 static final Level FINEST = const Level('FINEST', 300);
268
269 /** Key for fairly detailed tracing ([value] = 400). */
270 static final Level FINER = const Level('FINER', 400);
271
272 /** Key for tracing information ([value] = 500). */
273 static final Level FINE = const Level('FINE', 500);
274
275 /** Key for static configuration messages ([value] = 700). */
276 static final Level CONFIG = const Level('CONFIG', 700);
277
278 /** Key for informational messages ([value] = 800). */
279 static final Level INFO = const Level('INFO', 800);
280
281 /** Key for potential problems ([value] = 900). */
282 static final Level WARNING = const Level('WARNING', 900);
283
284 /** Key for serious failures ([value] = 1000). */
285 static final Level SEVERE = const Level('SEVERE', 1000);
286
287 /** Key for extra debugging loudness ([value] = 1200). */
288 static final Level SHOUT = const Level('SHOUT', 1200);
289
290 bool operator ==(Level other) => other != null && value == other.value;
291 bool operator <(Level other) => value < other.value;
292 bool operator <=(Level other) => value <= other.value;
293 bool operator >(Level other) => value > other.value;
294 bool operator >=(Level other) => value >= other.value;
295 int compareTo(Level other) => value - other.value;
296 int hashCode() => value;
297 String toString() => name;
298 }
299
300
301 /**
302 * A log entry representation used to propagate information from [Logger] to
303 * individual [Handler]s.
304 */
305 class LogRecord {
306 final Level level;
307 final String message;
308
309 /** Logger where this record is stored. */
310 final String loggerName;
311
312 /** Time when this record was created. */
313 final Date time;
314
315 /** Unique sequence number greater than all log records created before it. */
316 final int sequenceNumber;
317
318 static int _nextNumber = 0;
319
320 /** Associated exception (if any) when recording errors messages. */
321 Exception exception;
322
323 /** Associated exception message (if any) when recording errors messages. */
324 String exceptionText;
325
326 LogRecord(
327 this.level, this.message, this.loggerName,
328 [time, this.exception, this.exceptionText]) :
329 this.time = (time == null) ? new Date.now() : time,
330 this.sequenceNumber = LogRecord._nextNumber++;
331 }
OLDNEW
« no previous file with comments | « no previous file | tests/lib/logging/logging_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698