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

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

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

Powered by Google App Engine
This is Rietveld 408576698