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

Unified 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: Created 8 years, 6 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tests/lib/logging/logging_test.dart » ('j') | tests/lib/logging/logging_test.dart » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/logging/logging.dart
diff --git a/lib/logging/logging.dart b/lib/logging/logging.dart
new file mode 100644
index 0000000000000000000000000000000000000000..d1f6abdeb8876118aeac9f11862cb671039cdd8d
--- /dev/null
+++ b/lib/logging/logging.dart
@@ -0,0 +1,287 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Provides APIs for debugging and error logging. This library introduces
+ * abstractions similar to those used in other languages, such as the Closure JS
+ * 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 :)
+ */
+#library('logging');
+
+/** 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...)
+typedef void LoggerHandler(LogRecord);
+
+/** Default level when none is set on a logger. */
+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
+
+
+/**
+ * Use a [Logger] to log debug messages. [Logger]s are named using a
+ * hierarchical dot-separated name convention.
+ */
+class Logger {
+ /** Simple name of this logger. */
+ 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.
+
+ /* 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.
+ String get fullName() =>
+ (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.
+
+ /** Parent of this logger in the hierarchy of loggers. */
+ 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
+
+ /** Logging [Level] used for entries generated on this logger. */
+ Level _level;
+
+ /** Children in the hierarchy of loggers, indexed by their simple names. */
+ Map<String, Logger> children;
+
+ /** Handlers used to process log entries in this logger. */
+ List<LoggerHandler> _handlers;
+
+
+ /**
+ * 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 :)
+ * actual instance whenever it is called with the same string name.
+ */
+ factory Logger(String name) {
+ 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.
+ if (_loggers.containsKey(name)) return _loggers[name];
+
+ // Split hierarchical names (separated with '.').
+ int dot = name.lastIndexOf('.');
+ 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.
+ String thisName;
+ if (dot == -1) {
+ parentName = name == '' ? null : '';
+ thisName = name;
+ } else {
+ parentName = name.substring(0, dot);
+ thisName = name.substring(dot + 1);
+ }
+ final res = new Logger._internal(thisName,
+ parentName == null ? null : new Logger(parentName));
+ _loggers[name] = res;
+ return res;
+ }
+
+ Logger._internal(this.name, this.parent) :
+ 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
+ if (parent != null) parent.children[name] = this;
+ }
+
+ /**
+ * Effective level considering the levels established in this logger's parents
+ * (when [enableHierarchyLogging] is true).
+ */
+ Level get level() {
+ if (enableHierarchyLogging) {
+ if (_level != null) return _level;
+ if (parent != null) return parent.level;
+ }
+ return _rootLevel;
+ }
+
+ /** Override the level for this particular [Logger] and its children. */
+ Level set level(value) {
+ if (enableHierarchyLogging && parent != null) {
+ _level = value;
+ } else {
+ 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
+ '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!
+ '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.
+ _rootLevel = value;
+ }
+ }
+
+ /** Adds a handler to listen whenever a log record is added to this logger. */
+ 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'
+ if (enableHierarchyLogging || parent == null) {
+ if (_handlers == null) {
+ _handlers = new List<LoggerHandler>();
+ }
+ _handlers.add(handler);
+ } else {
+ root.addHandler(handler);
+ }
+ }
+
+ /** 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
+ void removeHandler(LoggerHandler handler) {
+ if (enableHierarchyLogging || parent == null) {
+ if (_handlers == null) return;
+ int index = _handlers.indexOf(handler);
+ if (index != -1) _handlers.removeRange(index, 1);
+ } else {
+ root.removeHandler(handler);
+ }
+ }
+
+ /** Removes all handlers previously added to this logger. */
+ void clearHandlers() {
+ 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.
+ _handlers = null;
+ } else {
+ root.removeHandler(handler);
+ }
+ }
+
+ /** Whether a message for [value]'s level is loggable in this logger. */
+ 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
+
+ // TODO(sigmund): add support for logging exceptions.
+ 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.
+ if (isLoggable(logLevel)) {
+ var record = new LogRecord(logLevel, message, fullName);
+ if (enableHierarchyLogging) {
+ var target = this;
+ while (target != null) {
+ target._publish(record);
+ target = target.parent;
+ }
+ } else {
+ root._publish(record);
+ }
+ }
+ }
+
+ /** Log message at level [Level.FINEST]. */
+ 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!
+
+ /** Log message at level [Level.FINER]. */
+ void finer(Strnig message) => log(Level.FINER, message);
+
+ /** Log message at level [Level.FINE]. */
+ void fine(Strnig message) => log(Level.FINE, message);
+
+ /** Log message at level [Level.CONFIG]. */
+ void config(Strnig message) => log(Level.CONFIG, message);
+
+ /** Log message at level [Level.INFO]. */
+ void info(Strnig message) => log(Level.INFO, message);
+
+ /** Log message at level [Level.WARNING]. */
+ void warning(Strnig message) => log(Level.WARNING, message);
+
+ /** Log message at level [Level.SEVERE]. */
+ void severe(Strnig message) => log(Level.SEVERE, message);
+
+ /** Log message at level [Level.SHOUT]. */
+ void shout(Strnig message) => log(Level.SHOUT, message);
+
+ void _publish(LogRecord record) {
+ if (_handlers != null) {
+ _handlers.forEach((h) => h(record));
+ }
+ }
+
+ /** Top-level root [Logger]. */
+ static get root() => new Logger('');
+
+ /**
+ * Whether to allow fine-grain logging and configuration of loggers in a
+ * hierarchy. When false, all logging is merged in the root logger.
+ */
+ 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
+
+ /** All [Logger]s in the system. */
+ static Map<String, Logger> _loggers;
+}
+
+
+/**
+ * [Level]s to control logging output. Logging can be enabled to include all
+ * levels above certain [Level]. [Level]s are ordered using an integer
+ * value [Level.value]. The predefined [Level] constants below are sorted as
+ * follows (in descending order): [Level.SHOUT], [Level.SEVERE],
+ * [Level.WARNING], [Level.INFO], [Level.CONFIG], [Level.FINE], [Level.FINER],
+ * [Level.FINEST], and [Level.ALL].
+ *
+ * We recommend using one of the predefined logging levels. If you define your
+ * own level, make sure you use a value between those used in [Level.ALL] and
+ * [Level.OFF].
+ */
+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.
+ final String name;
+
+ /**
+ * Unique value for this level. Used to order levels, so filtering can exclude
+ * messages whose level is under certain value.
+ */
+ 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
+
+ const Level(this.name, this.value);
+
+ /** Special key to turn on logging for all levels ([value] = 0). */
+ static final Level ALL = const Level('ALL', 0);
+
+ /** Special key to turn off all logging ([value] = 2000). */
+ static final Level OFF = const Level('OFF', 2000);
+
+ /** Key for highly detailed tracing ([value] = 300). */
+ static final Level FINEST = const Level('FINEST', 300);
+
+ /** Key for fairly detailed tracing ([value] = 400). */
+ static final Level FINER = const Level('FINER', 400);
+
+ /** Key for tracing information ([value] = 500). */
+ static final Level FINE = const Level('FINE', 500);
+
+ /** Key for static configuration messages ([value] = 700). */
+ static final Level CONFIG = const Level('CONFIG', 700);
+
+ /** Key for informational messages ([value] = 800). */
+ static final Level INFO = const Level('INFO', 800);
+
+ /** Key for potential problems ([value] = 900). */
+ static final Level WARNING = const Level('WARNING', 900);
+
+ /** Key for serious failures ([value] = 1000). */
+ static final Level SEVERE = const Level('SEVERE', 1000);
+
+ /** Key for extra debugging loudness ([value] = 1200). */
+ static final Level SHOUT = const Level('SHOUT', 1200);
+
+ 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.
+ bool operator <(Level other) => value < other.value;
+ bool operator <=(Level other) => value <= other.value;
+ bool operator >(Level other) => value > other.value;
+ bool operator >=(Level other) => value >= other.value;
+
+ String toString() => name;
+}
+
+
+/**
+ * A log entry representation used to propagate information from [Logger] to
+ * individual [Handler]s.
+ */
+class LogRecord {
+ final Level level;
+ final String message;
+
+ /** Logger where this record is stored. */
+ final String loggerName;
+
+ /** Time when this record was created. */
+ final Date time;
+
+ /** Unique sequence number greater than all log records created before it. */
+ final int sequenceNumber;
+
+ static int _nextNumber = 0;
+
+ /** Associated exception (if any) when recording errors messages. */
+ Exception exception;
+
+ /** Associated exception message (if any) when recording errors messages. */
+ String exceptionText;
+
+ LogRecord(
+ this.level, this.message, this.loggerName,
+ [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
+ 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
+ this.sequenceNumber =
+ sequenceNumber == null ? LogRecord._nextNumber++ : sequenceNumber;
+}
« no previous file with comments | « no previous file | tests/lib/logging/logging_test.dart » ('j') | tests/lib/logging/logging_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698