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

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

Issue 46233002: pkg/logging: added stackTrace support (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: better tests Created 7 years, 1 month 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 | pkg/logging/pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 /** 5 /**
6 * Support for debugging and error logging. 6 * Support for debugging and error logging.
7 * 7 *
8 * This library introduces abstractions similar to 8 * This library introduces abstractions similar to those used in other
9 * those used in other languages, such as the Closure JS 9 * languages, such as the Closure JS Logger and java.util.logging.Logger.
10 * Logger and java.util.logging.Logger.
11 * 10 *
12 * For information on installing and importing this library, see the 11 * For information on installing and importing this library, see the
13 * [logging package on pub.dartlang.org] 12 * [logging package on pub.dartlang.org]
14 * (http://pub.dartlang.org/packages/logging). 13 * (http://pub.dartlang.org/packages/logging).
15 */ 14 */
16 library logging; 15 library logging;
17 16
18 import 'dart:async'; 17 import 'dart:async';
18 import 'package:meta/meta.dart';
19 import 'package:unmodifiable_collection/unmodifiable_collection.dart';
19 20
20 /** 21 /**
21 * Whether to allow fine-grain logging and configuration of loggers in a 22 * Whether to allow fine-grain logging and configuration of loggers in a
22 * hierarchy. When false, all logging is merged in the root logger. 23 * hierarchy. When false, all logging is merged in the root logger.
23 */ 24 */
24 bool hierarchicalLoggingEnabled = false; 25 bool hierarchicalLoggingEnabled = false;
25 26
26 /** 27 /**
27 * Level for the root-logger. This will be the level of all loggers if 28 * Level for the root-logger. This will be the level of all loggers if
28 * [hierarchicalLoggingEnabled] is false. 29 * [hierarchicalLoggingEnabled] is false.
(...skipping 12 matching lines...) Expand all
41 /** The full name of this logger, which includes the parent's full name. */ 42 /** The full name of this logger, which includes the parent's full name. */
42 String get fullName => 43 String get fullName =>
43 (parent == null || parent.name == '') ? name : '${parent.fullName}.$name'; 44 (parent == null || parent.name == '') ? name : '${parent.fullName}.$name';
44 45
45 /** Parent of this logger in the hierarchy of loggers. */ 46 /** Parent of this logger in the hierarchy of loggers. */
46 final Logger parent; 47 final Logger parent;
47 48
48 /** Logging [Level] used for entries generated on this logger. */ 49 /** Logging [Level] used for entries generated on this logger. */
49 Level _level; 50 Level _level;
50 51
52 final Map<String, Logger> _children;
53
51 /** Children in the hierarchy of loggers, indexed by their simple names. */ 54 /** Children in the hierarchy of loggers, indexed by their simple names. */
52 Map<String, Logger> children; 55 final Map<String, Logger> children;
53 56
54 /** Controller used to notify when log entries are added to this logger. */ 57 /** Controller used to notify when log entries are added to this logger. */
55 StreamController<LogRecord> _controller; 58 StreamController<LogRecord> _controller;
56 59
57 /** The broadcast stream associated with the controller. */
58 Stream _stream;
59
60 /** 60 /**
61 * Singleton constructor. Calling `new Logger(name)` will return the same 61 * Singleton constructor. Calling `new Logger(name)` will return the same
62 * actual instance whenever it is called with the same string name. 62 * actual instance whenever it is called with the same string name.
63 */ 63 */
64 factory Logger(String name) { 64 factory Logger(String name) {
65 return _loggers.putIfAbsent(name, () => new Logger._named(name));
66 }
67
68 factory Logger._named(String name) {
65 if (name.startsWith('.')) { 69 if (name.startsWith('.')) {
66 throw new ArgumentError("name shouldn't start with a '.'"); 70 throw new ArgumentError("name shouldn't start with a '.'");
67 } 71 }
68 if (_loggers == null) _loggers = <String, Logger>{};
69 if (_loggers.containsKey(name)) return _loggers[name];
70
71 // Split hierarchical names (separated with '.'). 72 // Split hierarchical names (separated with '.').
72 int dot = name.lastIndexOf('.'); 73 int dot = name.lastIndexOf('.');
73 Logger parent = null; 74 Logger parent = null;
74 String thisName; 75 String thisName;
75 if (dot == -1) { 76 if (dot == -1) {
76 if (name != '') parent = new Logger(''); 77 if (name != '') parent = new Logger('');
77 thisName = name; 78 thisName = name;
78 } else { 79 } else {
79 parent = new Logger(name.substring(0, dot)); 80 parent = new Logger(name.substring(0, dot));
80 thisName = name.substring(dot + 1); 81 thisName = name.substring(dot + 1);
81 } 82 }
82 final res = new Logger._internal(thisName, parent); 83 return new Logger._internal(thisName, parent, new Map<String, Logger>());
83 _loggers[name] = res;
84 return res;
85 } 84 }
86 85
87 Logger._internal(this.name, this.parent) 86 Logger._internal(this.name, this.parent, Map<String, Logger> children) :
88 : children = new Map<String, Logger>() { 87 this._children = children,
89 if (parent != null) parent.children[name] = this; 88 this.children = new UnmodifiableMapView(children) {
89 if (parent != null) parent._children[name] = this;
90 } 90 }
91 91
92 /** 92 /**
93 * Effective level considering the levels established in this logger's parents 93 * Effective level considering the levels established in this logger's parents
94 * (when [hierarchicalLoggingEnabled] is true). 94 * (when [hierarchicalLoggingEnabled] is true).
95 */ 95 */
96 Level get level { 96 Level get level {
97 if (hierarchicalLoggingEnabled) { 97 if (hierarchicalLoggingEnabled) {
98 if (_level != null) return _level; 98 if (_level != null) return _level;
99 if (parent != null) return parent.level; 99 if (parent != null) return parent.level;
100 } 100 }
101 return _rootLevel; 101 return _rootLevel;
102 } 102 }
103 103
104 /** Override the level for this particular [Logger] and its children. */ 104 /** Override the level for this particular [Logger] and its children. */
105 set level(Level value) { 105 void set level(Level value) {
106 if (hierarchicalLoggingEnabled && parent != null) { 106 if (hierarchicalLoggingEnabled && parent != null) {
107 _level = value; 107 _level = value;
108 } else { 108 } else {
109 if (parent != null) { 109 if (parent != null) {
110 throw new UnsupportedError( 110 throw new UnsupportedError(
111 'Please set "hierarchicalLoggingEnabled" to true if you want to ' 111 'Please set "hierarchicalLoggingEnabled" to true if you want to '
112 'change the level on a non-root logger.'); 112 'change the level on a non-root logger.');
113 } 113 }
114 _rootLevel = value; 114 _rootLevel = value;
115 } 115 }
(...skipping 15 matching lines...) Expand all
131 } else { 131 } else {
132 root.clearListeners(); 132 root.clearListeners();
133 } 133 }
134 } 134 }
135 135
136 /** Whether a message for [value]'s level is loggable in this logger. */ 136 /** Whether a message for [value]'s level is loggable in this logger. */
137 bool isLoggable(Level value) => (value >= level); 137 bool isLoggable(Level value) => (value >= level);
138 138
139 /** 139 /**
140 * Adds a log record for a [message] at a particular [logLevel] if 140 * Adds a log record for a [message] at a particular [logLevel] if
141 * `isLoggable(logLevel)` is true. Use this method to create log entries for 141 * `isLoggable(logLevel)` is true.
142 * user-defined levels. To record a message at a predefined level (e.g. 142 *
143 * [Level.INFO], [Level.WARNING], etc) you can use their specialized methods 143 * Use this method to create log entries for user-defined levels. To record a
144 * instead (e.g. [info], [warning], etc). 144 * message at a predefined level (e.g. [Level.INFO], [Level.WARNING], etc) you
145 * can use their specialized methods instead (e.g. [info], [warning], etc).
145 */ 146 */
146 void log(Level logLevel, String message, [exception]) { 147 void log(Level logLevel, String message, [Object error,
148 StackTrace stackTrace]) {
147 if (isLoggable(logLevel)) { 149 if (isLoggable(logLevel)) {
148 var record = new LogRecord(logLevel, message, fullName, exception); 150 var record = new LogRecord(logLevel, message, fullName, error,
151 stackTrace);
152
149 if (hierarchicalLoggingEnabled) { 153 if (hierarchicalLoggingEnabled) {
150 var target = this; 154 var target = this;
151 while (target != null) { 155 while (target != null) {
152 target._publish(record); 156 target._publish(record);
153 target = target.parent; 157 target = target.parent;
154 } 158 }
155 } else { 159 } else {
156 root._publish(record); 160 root._publish(record);
157 } 161 }
158 } 162 }
159 } 163 }
160 164
161 /** Log message at level [Level.FINEST]. */ 165 /** Log message at level [Level.FINEST]. */
162 void finest(String message, [exception]) => 166 void finest(String message, [Object error, StackTrace stackTrace]) =>
163 log(Level.FINEST, message, exception); 167 log(Level.FINEST, message, error, stackTrace);
164 168
165 /** Log message at level [Level.FINER]. */ 169 /** Log message at level [Level.FINER]. */
166 void finer(String message, [exception]) => 170 void finer(String message, [Object error, StackTrace stackTrace]) =>
167 log(Level.FINER, message, exception); 171 log(Level.FINER, message, error, stackTrace);
168 172
169 /** Log message at level [Level.FINE]. */ 173 /** Log message at level [Level.FINE]. */
170 void fine(String message, [exception]) => 174 void fine(String message, [Object error, StackTrace stackTrace]) =>
171 log(Level.FINE, message, exception); 175 log(Level.FINE, message, error, stackTrace);
172 176
173 /** Log message at level [Level.CONFIG]. */ 177 /** Log message at level [Level.CONFIG]. */
174 void config(String message, [exception]) => 178 void config(String message, [Object error, StackTrace stackTrace]) =>
175 log(Level.CONFIG, message, exception); 179 log(Level.CONFIG, message, error, stackTrace);
176 180
177 /** Log message at level [Level.INFO]. */ 181 /** Log message at level [Level.INFO]. */
178 void info(String message, [exception]) => 182 void info(String message, [Object error, StackTrace stackTrace]) =>
179 log(Level.INFO, message, exception); 183 log(Level.INFO, message, error, stackTrace);
180 184
181 /** Log message at level [Level.WARNING]. */ 185 /** Log message at level [Level.WARNING]. */
182 void warning(String message, [exception]) => 186 void warning(String message, [Object error, StackTrace stackTrace]) =>
183 log(Level.WARNING, message, exception); 187 log(Level.WARNING, message, error, stackTrace);
184 188
185 /** Log message at level [Level.SEVERE]. */ 189 /** Log message at level [Level.SEVERE]. */
186 void severe(String message, [exception]) => 190 void severe(String message, [Object error, StackTrace stackTrace]) =>
187 log(Level.SEVERE, message, exception); 191 log(Level.SEVERE, message, error, stackTrace);
188 192
189 /** Log message at level [Level.SHOUT]. */ 193 /** Log message at level [Level.SHOUT]. */
190 void shout(String message, [exception]) => 194 void shout(String message, [Object error, StackTrace stackTrace]) =>
191 log(Level.SHOUT, message, exception); 195 log(Level.SHOUT, message, error, stackTrace);
192 196
193 Stream<LogRecord> _getStream() { 197 Stream<LogRecord> _getStream() {
194 if (hierarchicalLoggingEnabled || parent == null) { 198 if (hierarchicalLoggingEnabled || parent == null) {
195 if (_controller == null) { 199 if (_controller == null) {
196 _controller = new StreamController<LogRecord>.broadcast(sync: true); 200 _controller = new StreamController<LogRecord>.broadcast(sync: true);
197 _stream = _controller.stream;
198 } 201 }
199 return _stream; 202 return _controller.stream;
200 } else { 203 } else {
201 return root._getStream(); 204 return root._getStream();
202 } 205 }
203 } 206 }
204 207
205 void _publish(LogRecord record) { 208 void _publish(LogRecord record) {
206 if (_controller != null) { 209 if (_controller != null) {
207 _controller.add(record); 210 _controller.add(record);
208 } 211 }
209 } 212 }
210 213
211 /** Top-level root [Logger]. */ 214 /** Top-level root [Logger]. */
212 static Logger get root => new Logger(''); 215 static Logger get root => new Logger('');
213 216
214 /** All [Logger]s in the system. */ 217 /** All [Logger]s in the system. */
215 static Map<String, Logger> _loggers; 218 static final Map<String, Logger> _loggers = <String, Logger>{};
216 } 219 }
217 220
218 221
219 /** Handler callback to process log entries as they are added to a [Logger]. */ 222 /** Handler callback to process log entries as they are added to a [Logger]. */
220 typedef void LoggerHandler(LogRecord); 223 typedef void LoggerHandler(LogRecord);
221 224
222 /** 225 /**
223 * [Level]s to control logging output. Logging can be enabled to include all 226 * [Level]s to control logging output. Logging can be enabled to include all
224 * levels above certain [Level]. [Level]s are ordered using an integer 227 * levels above certain [Level]. [Level]s are ordered using an integer
225 * value [Level.value]. The predefined [Level] constants below are sorted as 228 * value [Level.value]. The predefined [Level] constants below are sorted as
226 * follows (in descending order): [Level.SHOUT], [Level.SEVERE], 229 * follows (in descending order): [Level.SHOUT], [Level.SEVERE],
227 * [Level.WARNING], [Level.INFO], [Level.CONFIG], [Level.FINE], [Level.FINER], 230 * [Level.WARNING], [Level.INFO], [Level.CONFIG], [Level.FINE], [Level.FINER],
228 * [Level.FINEST], and [Level.ALL]. 231 * [Level.FINEST], and [Level.ALL].
229 * 232 *
230 * We recommend using one of the predefined logging levels. If you define your 233 * We recommend using one of the predefined logging levels. If you define your
231 * own level, make sure you use a value between those used in [Level.ALL] and 234 * own level, make sure you use a value between those used in [Level.ALL] and
232 * [Level.OFF]. 235 * [Level.OFF].
233 */ 236 */
234 class Level implements Comparable<Level> { 237 class Level implements Comparable<Level> {
235 238
236 // TODO(sigmund): mark name/value as 'const' when the language supports it.
237 final String name; 239 final String name;
238 240
239 /** 241 /**
240 * Unique value for this level. Used to order levels, so filtering can exclude 242 * Unique value for this level. Used to order levels, so filtering can exclude
241 * messages whose level is under certain value. 243 * messages whose level is under certain value.
242 */ 244 */
243 final int value; 245 final int value;
244 246
245 const Level(this.name, this.value); 247 const Level(this.name, this.value);
246 248
(...skipping 20 matching lines...) Expand all
267 269
268 /** Key for potential problems ([value] = 900). */ 270 /** Key for potential problems ([value] = 900). */
269 static const Level WARNING = const Level('WARNING', 900); 271 static const Level WARNING = const Level('WARNING', 900);
270 272
271 /** Key for serious failures ([value] = 1000). */ 273 /** Key for serious failures ([value] = 1000). */
272 static const Level SEVERE = const Level('SEVERE', 1000); 274 static const Level SEVERE = const Level('SEVERE', 1000);
273 275
274 /** Key for extra debugging loudness ([value] = 1200). */ 276 /** Key for extra debugging loudness ([value] = 1200). */
275 static const Level SHOUT = const Level('SHOUT', 1200); 277 static const Level SHOUT = const Level('SHOUT', 1200);
276 278
277 bool operator ==(Level other) => other != null && value == other.value; 279 bool operator ==(Object other) => other is Level && value == other.value;
278 bool operator <(Level other) => value < other.value; 280 bool operator <(Level other) => value < other.value;
279 bool operator <=(Level other) => value <= other.value; 281 bool operator <=(Level other) => value <= other.value;
280 bool operator >(Level other) => value > other.value; 282 bool operator >(Level other) => value > other.value;
281 bool operator >=(Level other) => value >= other.value; 283 bool operator >=(Level other) => value >= other.value;
282 int compareTo(Level other) => value - other.value; 284 int compareTo(Level other) => value - other.value;
283 int get hashCode => value; 285 int get hashCode => value;
284 String toString() => name; 286 String toString() => name;
285 } 287 }
286 288
287 289
288 /** 290 /**
289 * A log entry representation used to propagate information from [Logger] to 291 * A log entry representation used to propagate information from [Logger] to
290 * individual [Handler]s. 292 * individual [Handler]s.
291 */ 293 */
292 class LogRecord { 294 class LogRecord {
293 final Level level; 295 final Level level;
294 final String message; 296 final String message;
295 297
296 /** Logger where this record is stored. */ 298 /** Logger where this record is stored. */
297 final String loggerName; 299 final String loggerName;
298 300
299 /** Time when this record was created. */ 301 /** Time when this record was created. */
300 final DateTime time; 302 final DateTime time;
301 303
302 /** Unique sequence number greater than all log records created before it. */ 304 /** Unique sequence number greater than all log records created before it. */
303 final int sequenceNumber; 305 final int sequenceNumber;
304 306
305 static int _nextNumber = 0; 307 static int _nextNumber = 0;
306 308
307 /** Associated exception (if any) when recording errors messages. */ 309 /** Associated error (if any) when recording errors messages. */
308 var exception; 310 final Object error;
309 311
310 LogRecord(this.level, this.message, this.loggerName, [this.exception]) 312 // TODO(kevmoo) - remove before V1
313 /**
314 * DEPRECATED. Use [error] instead.
315 */
316 @deprecated
317 Object get exception => error;
318
319 /** Associated stackTrace (if any) when recording errors messages. */
320 final StackTrace stackTrace;
321
322 LogRecord(this.level, this.message, this.loggerName, [this.error,
323 this.stackTrace])
311 : time = new DateTime.now(), 324 : time = new DateTime.now(),
312 sequenceNumber = LogRecord._nextNumber++; 325 sequenceNumber = LogRecord._nextNumber++;
313 326
314 String toString() => '[${level.name}] $loggerName: $message'; 327 String toString() => '[${level.name}] $loggerName: $message';
315 } 328 }
OLDNEW
« no previous file with comments | « no previous file | pkg/logging/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698