Chromium Code Reviews| 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 /** | |
| 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 * library and java.util.logging. | |
|
Jennifer Messerly
2012/06/29 03:47:45
did you mean: "such as the Closure JS Logger"
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Done :)
| |
| 9 */ | |
| 10 #library('logging'); | |
| 11 | |
| 12 /** A handler that process log entries in of a [Logger]. */ | |
|
gram
2012/06/29 16:38:25
Grammar? I can't parse this sentence.
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Done (also moved further down...)
| |
| 13 typedef void LoggerHandler(LogRecord); | |
| 14 | |
| 15 /** Default level when none is set on a logger. */ | |
| 16 Level _rootLevel = Level.INFO; | |
|
gram
2012/06/29 16:38:25
Shouldn't this be called _defaultLevel then?
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
rephrased doc
| |
| 17 | |
| 18 | |
| 19 /** | |
| 20 * Use a [Logger] to log debug messages. [Logger]s are named using a | |
| 21 * hierarchical dot-separated name convention. | |
| 22 */ | |
| 23 class Logger { | |
| 24 /** Simple name of this logger. */ | |
| 25 String name; | |
|
Jennifer Messerly
2012/06/29 03:47:45
should this be final? It seems like changing the n
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Good point. Done.
| |
| 26 | |
| 27 /* The full name of this logger, which includes also the parent's names. */ | |
|
Jennifer Messerly
2012/06/29 03:47:45
/**
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Done.
| |
| 28 String get fullName() => | |
| 29 (parent == null || parent.name == '') ? name : '${parent.fullName}.$name'; | |
|
Jennifer Messerly
2012/06/29 03:47:45
If I'm understanding this correctly: every logger
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Correct.
| |
| 30 | |
| 31 /** Parent of this logger in the hierarchy of loggers. */ | |
| 32 Logger parent; | |
|
Jennifer Messerly
2012/06/29 03:47:45
should this be final too? as well as the other fie
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Done. _handlers and children are not final so we a
| |
| 33 | |
| 34 /** Logging [Level] used for entries generated on this logger. */ | |
| 35 Level _level; | |
| 36 | |
| 37 /** Children in the hierarchy of loggers, indexed by their simple names. */ | |
| 38 Map<String, Logger> children; | |
| 39 | |
| 40 /** Handlers used to process log entries in this logger. */ | |
| 41 List<LoggerHandler> _handlers; | |
| 42 | |
| 43 | |
| 44 /** | |
| 45 * Singleton constructor. Calling [:new Logger(name) :] will return the same | |
|
Jennifer Messerly
2012/06/29 03:47:45
nit, use backticks: `new Logger(name)`
http://dari
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
done, but [: :] is the dart doc way :)
| |
| 46 * actual instance whenever it is called with the same string name. | |
| 47 */ | |
| 48 factory Logger(String name) { | |
| 49 if (_loggers == null) _loggers = new Map<String, Logger>(); | |
|
Jennifer Messerly
2012/06/29 03:47:45
you could use "<Logger>{}" instead of "new Map<Str
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Done.
| |
| 50 if (_loggers.containsKey(name)) return _loggers[name]; | |
| 51 | |
| 52 // Split hierarchical names (separated with '.'). | |
| 53 int dot = name.lastIndexOf('.'); | |
| 54 String parentName; | |
|
Jennifer Messerly
2012/06/29 03:47:45
I think I would've understood this quicker if the
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
I like it, very nice suggestion. Done.
| |
| 55 String thisName; | |
| 56 if (dot == -1) { | |
| 57 parentName = name == '' ? null : ''; | |
| 58 thisName = name; | |
| 59 } else { | |
| 60 parentName = name.substring(0, dot); | |
| 61 thisName = name.substring(dot + 1); | |
| 62 } | |
| 63 final res = new Logger._internal(thisName, | |
| 64 parentName == null ? null : new Logger(parentName)); | |
| 65 _loggers[name] = res; | |
| 66 return res; | |
| 67 } | |
| 68 | |
| 69 Logger._internal(this.name, this.parent) : | |
| 70 children = new Map<String, Logger>() { | |
|
Jennifer Messerly
2012/06/29 03:47:45
nit: indent 4 from Logger then ": children = " ...
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Nice - I had forgotten, the style guide has the st
| |
| 71 if (parent != null) parent.children[name] = this; | |
| 72 } | |
| 73 | |
| 74 /** | |
| 75 * Effective level considering the levels established in this logger's parents | |
| 76 * (when [enableHierarchyLogging] is true). | |
| 77 */ | |
| 78 Level get level() { | |
| 79 if (enableHierarchyLogging) { | |
| 80 if (_level != null) return _level; | |
| 81 if (parent != null) return parent.level; | |
| 82 } | |
| 83 return _rootLevel; | |
| 84 } | |
| 85 | |
| 86 /** Override the level for this particular [Logger] and its children. */ | |
| 87 Level set level(value) { | |
| 88 if (enableHierarchyLogging && parent != null) { | |
| 89 _level = value; | |
| 90 } else { | |
| 91 if (parent != null) throw new Exception( | |
|
Jennifer Messerly
2012/06/29 03:47:45
UnsupportedOperationException
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Done
| |
| 92 'Cannot set level on a non-root logger when hierarchycal logging ' | |
|
Jennifer Messerly
2012/06/29 03:47:45
typo: should be "hierarchical"
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Done, thanks!
| |
| 93 'is not enabled'); | |
|
Jennifer Messerly
2012/06/29 03:47:45
Maybe reword this message as:
"Please set Logger.e
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Done.
| |
| 94 _rootLevel = value; | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 /** Adds a handler to listen whenever a log record is added to this logger. */ | |
| 99 void addHandler(LoggerHandler handler) { | |
|
Jennifer Messerly
2012/06/29 03:47:45
hmmm. This is just begging to use an event pattern
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Done - added the pattern, yippie! Used 'on.record'
| |
| 100 if (enableHierarchyLogging || parent == null) { | |
| 101 if (_handlers == null) { | |
| 102 _handlers = new List<LoggerHandler>(); | |
| 103 } | |
| 104 _handlers.add(handler); | |
| 105 } else { | |
| 106 root.addHandler(handler); | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 /** Remove an previously added handler. */ | |
|
gram
2012/06/29 16:38:25
Remove a ...
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
thx. done
| |
| 111 void removeHandler(LoggerHandler handler) { | |
| 112 if (enableHierarchyLogging || parent == null) { | |
| 113 if (_handlers == null) return; | |
| 114 int index = _handlers.indexOf(handler); | |
| 115 if (index != -1) _handlers.removeRange(index, 1); | |
| 116 } else { | |
| 117 root.removeHandler(handler); | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 /** Removes all handlers previously added to this logger. */ | |
| 122 void clearHandlers() { | |
| 123 if (enableHierarchyLogging || parent == null) { | |
|
gram
2012/06/29 16:38:25
Can this be called 'hierarchicalLoggingEnabled' in
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Done.
| |
| 124 _handlers = null; | |
| 125 } else { | |
| 126 root.removeHandler(handler); | |
| 127 } | |
| 128 } | |
| 129 | |
| 130 /** Whether a message for [value]'s level is loggable in this logger. */ | |
| 131 bool isLoggable(Level value) => (value >= level); | |
|
Jennifer Messerly
2012/06/29 03:47:45
nit: redundant parens.
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
I actually did this on purpose, it just looks real
| |
| 132 | |
| 133 // TODO(sigmund): add support for logging exceptions. | |
| 134 void log(Level logLevel, String message) { | |
|
Jennifer Messerly
2012/06/29 03:47:45
This could use a doc comment too, like the other e
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Done.
| |
| 135 if (isLoggable(logLevel)) { | |
| 136 var record = new LogRecord(logLevel, message, fullName); | |
| 137 if (enableHierarchyLogging) { | |
| 138 var target = this; | |
| 139 while (target != null) { | |
| 140 target._publish(record); | |
| 141 target = target.parent; | |
| 142 } | |
| 143 } else { | |
| 144 root._publish(record); | |
| 145 } | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 /** Log message at level [Level.FINEST]. */ | |
| 150 void finest(Strnig message) => log(Level.FINEST, message); | |
|
gram
2012/06/29 16:38:25
Typo, here and elsewhere: Strnig
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
wow!
running tests in checked mode -- checked!
| |
| 151 | |
| 152 /** Log message at level [Level.FINER]. */ | |
| 153 void finer(Strnig message) => log(Level.FINER, message); | |
| 154 | |
| 155 /** Log message at level [Level.FINE]. */ | |
| 156 void fine(Strnig message) => log(Level.FINE, message); | |
| 157 | |
| 158 /** Log message at level [Level.CONFIG]. */ | |
| 159 void config(Strnig message) => log(Level.CONFIG, message); | |
| 160 | |
| 161 /** Log message at level [Level.INFO]. */ | |
| 162 void info(Strnig message) => log(Level.INFO, message); | |
| 163 | |
| 164 /** Log message at level [Level.WARNING]. */ | |
| 165 void warning(Strnig message) => log(Level.WARNING, message); | |
| 166 | |
| 167 /** Log message at level [Level.SEVERE]. */ | |
| 168 void severe(Strnig message) => log(Level.SEVERE, message); | |
| 169 | |
| 170 /** Log message at level [Level.SHOUT]. */ | |
| 171 void shout(Strnig message) => log(Level.SHOUT, message); | |
| 172 | |
| 173 void _publish(LogRecord record) { | |
| 174 if (_handlers != null) { | |
| 175 _handlers.forEach((h) => h(record)); | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 /** Top-level root [Logger]. */ | |
| 180 static get root() => new Logger(''); | |
| 181 | |
| 182 /** | |
| 183 * Whether to allow fine-grain logging and configuration of loggers in a | |
| 184 * hierarchy. When false, all logging is merged in the root logger. | |
| 185 */ | |
| 186 static bool enableHierarchyLogging = false; | |
|
Jennifer Messerly
2012/06/29 03:47:45
does this need to be configurable?
might be worth
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Not sure - I was inclined to always have it enable
| |
| 187 | |
| 188 /** All [Logger]s in the system. */ | |
| 189 static Map<String, Logger> _loggers; | |
| 190 } | |
| 191 | |
| 192 | |
| 193 /** | |
| 194 * [Level]s to control logging output. Logging can be enabled to include all | |
| 195 * levels above certain [Level]. [Level]s are ordered using an integer | |
| 196 * value [Level.value]. The predefined [Level] constants below are sorted as | |
| 197 * follows (in descending order): [Level.SHOUT], [Level.SEVERE], | |
| 198 * [Level.WARNING], [Level.INFO], [Level.CONFIG], [Level.FINE], [Level.FINER], | |
| 199 * [Level.FINEST], and [Level.ALL]. | |
| 200 * | |
| 201 * We recommend using one of the predefined logging levels. If you define your | |
| 202 * own level, make sure you use a value between those used in [Level.ALL] and | |
| 203 * [Level.OFF]. | |
| 204 */ | |
| 205 class Level { | |
|
Jennifer Messerly
2012/06/29 03:47:45
implements Comparable, Hashable
and add methods:
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Done.
| |
| 206 final String name; | |
| 207 | |
| 208 /** | |
| 209 * Unique value for this level. Used to order levels, so filtering can exclude | |
| 210 * messages whose level is under certain value. | |
| 211 */ | |
| 212 final int value; | |
|
Jennifer Messerly
2012/06/29 03:47:45
TODO: this should be "const" when that modifier is
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Done
| |
| 213 | |
| 214 const Level(this.name, this.value); | |
| 215 | |
| 216 /** Special key to turn on logging for all levels ([value] = 0). */ | |
| 217 static final Level ALL = const Level('ALL', 0); | |
| 218 | |
| 219 /** Special key to turn off all logging ([value] = 2000). */ | |
| 220 static final Level OFF = const Level('OFF', 2000); | |
| 221 | |
| 222 /** Key for highly detailed tracing ([value] = 300). */ | |
| 223 static final Level FINEST = const Level('FINEST', 300); | |
| 224 | |
| 225 /** Key for fairly detailed tracing ([value] = 400). */ | |
| 226 static final Level FINER = const Level('FINER', 400); | |
| 227 | |
| 228 /** Key for tracing information ([value] = 500). */ | |
| 229 static final Level FINE = const Level('FINE', 500); | |
| 230 | |
| 231 /** Key for static configuration messages ([value] = 700). */ | |
| 232 static final Level CONFIG = const Level('CONFIG', 700); | |
| 233 | |
| 234 /** Key for informational messages ([value] = 800). */ | |
| 235 static final Level INFO = const Level('INFO', 800); | |
| 236 | |
| 237 /** Key for potential problems ([value] = 900). */ | |
| 238 static final Level WARNING = const Level('WARNING', 900); | |
| 239 | |
| 240 /** Key for serious failures ([value] = 1000). */ | |
| 241 static final Level SEVERE = const Level('SEVERE', 1000); | |
| 242 | |
| 243 /** Key for extra debugging loudness ([value] = 1200). */ | |
| 244 static final Level SHOUT = const Level('SHOUT', 1200); | |
| 245 | |
| 246 bool operator ==(Level other) => this === other; | |
|
Jennifer Messerly
2012/06/29 03:47:45
do you need to define this?
Jennifer Messerly
2012/06/29 17:37:13
as gram mentioned later, maybe this should be "val
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
gone
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
agreed - done.
| |
| 247 bool operator <(Level other) => value < other.value; | |
| 248 bool operator <=(Level other) => value <= other.value; | |
| 249 bool operator >(Level other) => value > other.value; | |
| 250 bool operator >=(Level other) => value >= other.value; | |
| 251 | |
| 252 String toString() => name; | |
| 253 } | |
| 254 | |
| 255 | |
| 256 /** | |
| 257 * A log entry representation used to propagate information from [Logger] to | |
| 258 * individual [Handler]s. | |
| 259 */ | |
| 260 class LogRecord { | |
| 261 final Level level; | |
| 262 final String message; | |
| 263 | |
| 264 /** Logger where this record is stored. */ | |
| 265 final String loggerName; | |
| 266 | |
| 267 /** Time when this record was created. */ | |
| 268 final Date time; | |
| 269 | |
| 270 /** Unique sequence number greater than all log records created before it. */ | |
| 271 final int sequenceNumber; | |
| 272 | |
| 273 static int _nextNumber = 0; | |
| 274 | |
| 275 /** Associated exception (if any) when recording errors messages. */ | |
| 276 Exception exception; | |
| 277 | |
| 278 /** Associated exception message (if any) when recording errors messages. */ | |
| 279 String exceptionText; | |
| 280 | |
| 281 LogRecord( | |
| 282 this.level, this.message, this.loggerName, | |
| 283 [time, sequenceNumber, this.exception, this.exceptionText]) : | |
|
gram
2012/06/29 16:38:25
Is it really necessary to support passing in an ex
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
Removed from now. Just made this as similar as pos
| |
| 284 this.time = time == null ? new Date.now() : time, | |
|
Jennifer Messerly
2012/06/29 03:47:45
nit, put ":" on next line and indent everything 4
gram
2012/06/29 16:38:25
If find the this.time= time == null scans very poo
Siggi Cherem (dart-lang)
2012/06/29 18:34:48
agreed. same motivation I had for the other extra
| |
| 285 this.sequenceNumber = | |
| 286 sequenceNumber == null ? LogRecord._nextNumber++ : sequenceNumber; | |
| 287 } | |
| OLD | NEW |