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

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

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 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
« no previous file with comments | « intl/pubspec.yaml ('k') | 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
(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 */
7 library logging;
8
9 import 'dart:async';
10 import 'dart:collection';
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 * Automatically record stack traces for any message of this level or above.
20 * Because this is expensive, this is off by default.
21 */
22 Level recordStackTraceAtLevel = Level.OFF;
23
24 /**
25 * Level for the root-logger. This will be the level of all loggers if
26 * [hierarchicalLoggingEnabled] is false.
27 */
28 Level _rootLevel = Level.INFO;
29
30 /**
31 * Use a [Logger] to log debug messages. [Logger]s are named using a
32 * hierarchical dot-separated name convention.
33 */
34 class Logger {
35 /** Simple name of this logger. */
36 final String name;
37
38 /** The full name of this logger, which includes the parent's full name. */
39 String get fullName =>
40 (parent == null || parent.name == '') ? name : '${parent.fullName}.$name';
41
42 /** Parent of this logger in the hierarchy of loggers. */
43 final Logger parent;
44
45 /** Logging [Level] used for entries generated on this logger. */
46 Level _level;
47
48 final Map<String, Logger> _children;
49
50 /** Children in the hierarchy of loggers, indexed by their simple names. */
51 final Map<String, Logger> children;
52
53 /** Controller used to notify when log entries are added to this logger. */
54 StreamController<LogRecord> _controller;
55
56 /**
57 * Singleton constructor. Calling `new Logger(name)` will return the same
58 * actual instance whenever it is called with the same string name.
59 */
60 factory Logger(String name) {
61 return _loggers.putIfAbsent(name, () => new Logger._named(name));
62 }
63
64 factory Logger._named(String name) {
65 if (name.startsWith('.')) {
66 throw new ArgumentError("name shouldn't start with a '.'");
67 }
68 // Split hierarchical names (separated with '.').
69 int dot = name.lastIndexOf('.');
70 Logger parent = null;
71 String thisName;
72 if (dot == -1) {
73 if (name != '') parent = new Logger('');
74 thisName = name;
75 } else {
76 parent = new Logger(name.substring(0, dot));
77 thisName = name.substring(dot + 1);
78 }
79 return new Logger._internal(thisName, parent, new Map<String, Logger>());
80 }
81
82 Logger._internal(this.name, this.parent, Map<String, Logger> children)
83 : this._children = children,
84 this.children = new UnmodifiableMapView(children) {
85 if (parent != null) parent._children[name] = this;
86 }
87
88 /**
89 * Effective level considering the levels established in this logger's parents
90 * (when [hierarchicalLoggingEnabled] is true).
91 */
92 Level get level {
93 if (hierarchicalLoggingEnabled) {
94 if (_level != null) return _level;
95 if (parent != null) return parent.level;
96 }
97 return _rootLevel;
98 }
99
100 /** Override the level for this particular [Logger] and its children. */
101 void set level(Level value) {
102 if (hierarchicalLoggingEnabled && parent != null) {
103 _level = value;
104 } else {
105 if (parent != null) {
106 throw new UnsupportedError(
107 'Please set "hierarchicalLoggingEnabled" to true if you want to '
108 'change the level on a non-root logger.');
109 }
110 _rootLevel = value;
111 }
112 }
113
114 /**
115 * Returns an stream of messages added to this [Logger]. You can listen for
116 * messages using the standard stream APIs, for instance:
117 * logger.onRecord.listen((record) { ... });
118 */
119 Stream<LogRecord> get onRecord => _getStream();
120
121 void clearListeners() {
122 if (hierarchicalLoggingEnabled || parent == null) {
123 if (_controller != null) {
124 _controller.close();
125 _controller = null;
126 }
127 } else {
128 root.clearListeners();
129 }
130 }
131
132 /** Whether a message for [value]'s level is loggable in this logger. */
133 bool isLoggable(Level value) => (value >= level);
134
135 /**
136 * Adds a log record for a [message] at a particular [logLevel] if
137 * `isLoggable(logLevel)` is true.
138 *
139 * Use this method to create log entries for user-defined levels. To record a
140 * message at a predefined level (e.g. [Level.INFO], [Level.WARNING], etc) you
141 * can use their specialized methods instead (e.g. [info], [warning], etc).
142 *
143 * If [message] is a [Function], it will be lazy evaluated. Additionally, if
144 * [message] or its evaluated value is not a [String], then 'toString()' will
145 * be called on it and the result will be logged.
146 *
147 * The log record will contain a field for the zone in which this call was
148 * made.
149 * This can be advantagous if a log listener wants to handle records of
150 * different zones differently (e.g. group log records by http-request if each
151 * http-request handler runs in it's own zone).
152 */
153 void log(Level logLevel, message,
154 [Object error, StackTrace stackTrace, Zone zone]) {
155 if (isLoggable(logLevel)) {
156 if (message is Function) message = message();
157 if (message is! String) message = message.toString();
158 if (stackTrace == null && logLevel >= recordStackTraceAtLevel) {
159 try {
160 throw "autogenerated stack trace for $logLevel $message";
161 } catch (e, t) {
162 stackTrace = t;
163 if (error == null) error = e;
164 }
165 }
166 if (zone == null) zone = Zone.current;
167
168 var record =
169 new LogRecord(logLevel, message, fullName, error, stackTrace, zone);
170
171 if (hierarchicalLoggingEnabled) {
172 var target = this;
173 while (target != null) {
174 target._publish(record);
175 target = target.parent;
176 }
177 } else {
178 root._publish(record);
179 }
180 }
181 }
182
183 /** Log message at level [Level.FINEST]. */
184 void finest(message, [Object error, StackTrace stackTrace]) =>
185 log(Level.FINEST, message, error, stackTrace);
186
187 /** Log message at level [Level.FINER]. */
188 void finer(message, [Object error, StackTrace stackTrace]) =>
189 log(Level.FINER, message, error, stackTrace);
190
191 /** Log message at level [Level.FINE]. */
192 void fine(message, [Object error, StackTrace stackTrace]) =>
193 log(Level.FINE, message, error, stackTrace);
194
195 /** Log message at level [Level.CONFIG]. */
196 void config(message, [Object error, StackTrace stackTrace]) =>
197 log(Level.CONFIG, message, error, stackTrace);
198
199 /** Log message at level [Level.INFO]. */
200 void info(message, [Object error, StackTrace stackTrace]) =>
201 log(Level.INFO, message, error, stackTrace);
202
203 /** Log message at level [Level.WARNING]. */
204 void warning(message, [Object error, StackTrace stackTrace]) =>
205 log(Level.WARNING, message, error, stackTrace);
206
207 /** Log message at level [Level.SEVERE]. */
208 void severe(message, [Object error, StackTrace stackTrace]) =>
209 log(Level.SEVERE, message, error, stackTrace);
210
211 /** Log message at level [Level.SHOUT]. */
212 void shout(message, [Object error, StackTrace stackTrace]) =>
213 log(Level.SHOUT, message, error, stackTrace);
214
215 Stream<LogRecord> _getStream() {
216 if (hierarchicalLoggingEnabled || parent == null) {
217 if (_controller == null) {
218 _controller = new StreamController<LogRecord>.broadcast(sync: true);
219 }
220 return _controller.stream;
221 } else {
222 return root._getStream();
223 }
224 }
225
226 void _publish(LogRecord record) {
227 if (_controller != null) {
228 _controller.add(record);
229 }
230 }
231
232 /** Top-level root [Logger]. */
233 static final Logger root = new Logger('');
234
235 /** All [Logger]s in the system. */
236 static final Map<String, Logger> _loggers = <String, Logger>{};
237 }
238
239 /** Handler callback to process log entries as they are added to a [Logger]. */
240 typedef void LoggerHandler(LogRecord);
241
242 /**
243 * [Level]s to control logging output. Logging can be enabled to include all
244 * levels above certain [Level]. [Level]s are ordered using an integer
245 * value [Level.value]. The predefined [Level] constants below are sorted as
246 * follows (in descending order): [Level.SHOUT], [Level.SEVERE],
247 * [Level.WARNING], [Level.INFO], [Level.CONFIG], [Level.FINE], [Level.FINER],
248 * [Level.FINEST], and [Level.ALL].
249 *
250 * We recommend using one of the predefined logging levels. If you define your
251 * own level, make sure you use a value between those used in [Level.ALL] and
252 * [Level.OFF].
253 */
254 class Level implements Comparable<Level> {
255 final String name;
256
257 /**
258 * Unique value for this level. Used to order levels, so filtering can exclude
259 * messages whose level is under certain value.
260 */
261 final int value;
262
263 const Level(this.name, this.value);
264
265 /** Special key to turn on logging for all levels ([value] = 0). */
266 static const Level ALL = const Level('ALL', 0);
267
268 /** Special key to turn off all logging ([value] = 2000). */
269 static const Level OFF = const Level('OFF', 2000);
270
271 /** Key for highly detailed tracing ([value] = 300). */
272 static const Level FINEST = const Level('FINEST', 300);
273
274 /** Key for fairly detailed tracing ([value] = 400). */
275 static const Level FINER = const Level('FINER', 400);
276
277 /** Key for tracing information ([value] = 500). */
278 static const Level FINE = const Level('FINE', 500);
279
280 /** Key for static configuration messages ([value] = 700). */
281 static const Level CONFIG = const Level('CONFIG', 700);
282
283 /** Key for informational messages ([value] = 800). */
284 static const Level INFO = const Level('INFO', 800);
285
286 /** Key for potential problems ([value] = 900). */
287 static const Level WARNING = const Level('WARNING', 900);
288
289 /** Key for serious failures ([value] = 1000). */
290 static const Level SEVERE = const Level('SEVERE', 1000);
291
292 /** Key for extra debugging loudness ([value] = 1200). */
293 static const Level SHOUT = const Level('SHOUT', 1200);
294
295 static const List<Level> LEVELS = const [
296 ALL,
297 FINEST,
298 FINER,
299 FINE,
300 CONFIG,
301 INFO,
302 WARNING,
303 SEVERE,
304 SHOUT,
305 OFF
306 ];
307
308 bool operator ==(other) => other is Level && value == other.value;
309 bool operator <(Level other) => value < other.value;
310 bool operator <=(Level other) => value <= other.value;
311 bool operator >(Level other) => value > other.value;
312 bool operator >=(Level other) => value >= other.value;
313 int compareTo(Level other) => value - other.value;
314 int get hashCode => value;
315 String toString() => name;
316 }
317
318 /**
319 * A log entry representation used to propagate information from [Logger] to
320 * individual [Handler]s.
321 */
322 class LogRecord {
323 final Level level;
324 final String message;
325
326 /** Logger where this record is stored. */
327 final String loggerName;
328
329 /** Time when this record was created. */
330 final DateTime time;
331
332 /** Unique sequence number greater than all log records created before it. */
333 final int sequenceNumber;
334
335 static int _nextNumber = 0;
336
337 /** Associated error (if any) when recording errors messages. */
338 final Object error;
339
340 /** Associated stackTrace (if any) when recording errors messages. */
341 final StackTrace stackTrace;
342
343 /** Zone of the calling code which resulted in this LogRecord. */
344 final Zone zone;
345
346 LogRecord(this.level, this.message, this.loggerName,
347 [this.error, this.stackTrace, this.zone])
348 : time = new DateTime.now(),
349 sequenceNumber = LogRecord._nextNumber++;
350
351 String toString() => '[${level.name}] $loggerName: $message';
352 }
OLDNEW
« no previous file with comments | « intl/pubspec.yaml ('k') | logging/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698