Skip to content

Commit 49669c4

Browse files
authored
Refactor into mini-libraries (flutter#64)
1 parent c0c7f3f commit 49669c4

File tree

4 files changed

+376
-358
lines changed

4 files changed

+376
-358
lines changed

lib/logging.dart

+6-358
Original file line numberDiff line numberDiff line change
@@ -2,365 +2,13 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
library logging;
5+
import 'src/log_record.dart';
6+
import 'src/logger.dart';
67

7-
import 'dart:async';
8-
import 'dart:collection';
9-
10-
/// Whether to allow fine-grain logging and configuration of loggers in a
11-
/// hierarchy.
12-
///
13-
/// When false, all logging is merged in the root logger.
14-
bool hierarchicalLoggingEnabled = false;
15-
16-
/// Automatically record stack traces for any message of this level or above.
17-
///
18-
/// Because this is expensive, this is off by default.
19-
Level recordStackTraceAtLevel = Level.OFF;
20-
21-
/// Level for the root-logger.
22-
///
23-
/// This will be the level of all loggers if [hierarchicalLoggingEnabled] is
24-
/// false.
25-
Level _rootLevel = Level.INFO;
26-
27-
/// Use a [Logger] to log debug messages.
28-
///
29-
/// [Logger]s are named using a hierarchical dot-separated name convention.
30-
class Logger {
31-
/// Simple name of this logger.
32-
final String name;
33-
34-
/// The full name of this logger, which includes the parent's full name.
35-
String get fullName =>
36-
(parent == null || parent.name == '') ? name : '${parent.fullName}.$name';
37-
38-
/// Parent of this logger in the hierarchy of loggers.
39-
final Logger parent;
40-
41-
/// Logging [Level] used for entries generated on this logger.
42-
Level _level;
43-
44-
final Map<String, Logger> _children;
45-
46-
/// Children in the hierarchy of loggers, indexed by their simple names.
47-
final Map<String, Logger> children;
48-
49-
/// Controller used to notify when log entries are added to this logger.
50-
StreamController<LogRecord> _controller;
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-
factory Logger(String name) =>
55-
_loggers.putIfAbsent(name, () => Logger._named(name));
56-
57-
/// Creates a new detached [Logger].
58-
///
59-
/// Returns a new [Logger] instance (unlike `new Logger`, which returns a
60-
/// [Logger] singleton), which doesn't have any parent or children,
61-
/// and is not a part of the global hierarchical loggers structure.
62-
///
63-
/// It can be useful when you just need a local short-living logger,
64-
/// which you'd like to be garbage-collected later.
65-
factory Logger.detached(String name) =>
66-
Logger._internal(name, null, <String, Logger>{});
67-
68-
factory Logger._named(String name) {
69-
if (name.startsWith('.')) {
70-
throw ArgumentError("name shouldn't start with a '.'");
71-
}
72-
// Split hierarchical names (separated with '.').
73-
var dot = name.lastIndexOf('.');
74-
Logger parent;
75-
String thisName;
76-
if (dot == -1) {
77-
if (name != '') parent = Logger('');
78-
thisName = name;
79-
} else {
80-
parent = Logger(name.substring(0, dot));
81-
thisName = name.substring(dot + 1);
82-
}
83-
return Logger._internal(thisName, parent, <String, Logger>{});
84-
}
85-
86-
Logger._internal(this.name, this.parent, Map<String, Logger> children)
87-
: _children = children,
88-
children = UnmodifiableMapView(children) {
89-
if (parent != null) parent._children[name] = this;
90-
}
91-
92-
/// Effective level considering the levels established in this logger's
93-
/// parents (when [hierarchicalLoggingEnabled] is true).
94-
Level get level {
95-
if (hierarchicalLoggingEnabled) {
96-
if (_level != null) return _level;
97-
if (parent != null) return parent.level;
98-
}
99-
return _rootLevel;
100-
}
101-
102-
/// Override the level for this particular [Logger] and its children.
103-
set level(Level value) {
104-
if (hierarchicalLoggingEnabled && parent != null) {
105-
_level = value;
106-
} else {
107-
if (parent != null) {
108-
throw UnsupportedError(
109-
'Please set "hierarchicalLoggingEnabled" to true if you want to '
110-
'change the level on a non-root logger.');
111-
}
112-
_rootLevel = value;
113-
}
114-
}
115-
116-
/// Returns a stream of messages added to this [Logger].
117-
///
118-
/// You can listen for messages using the standard stream APIs, for instance:
119-
///
120-
/// ```dart
121-
/// logger.onRecord.listen((record) { ... });
122-
/// ```
123-
Stream<LogRecord> get onRecord => _getStream();
124-
125-
void clearListeners() {
126-
if (hierarchicalLoggingEnabled || parent == null) {
127-
if (_controller != null) {
128-
_controller.close();
129-
_controller = null;
130-
}
131-
} else {
132-
root.clearListeners();
133-
}
134-
}
135-
136-
/// Whether a message for [value]'s level is loggable in this logger.
137-
bool isLoggable(Level value) => (value >= level);
138-
139-
/// Adds a log record for a [message] at a particular [logLevel] if
140-
/// `isLoggable(logLevel)` is true.
141-
///
142-
/// Use this method to create log entries for user-defined levels. To record a
143-
/// message at a predefined level (e.g. [Level.INFO], [Level.WARNING], etc)
144-
/// you can use their specialized methods instead (e.g. [info], [warning],
145-
/// etc).
146-
///
147-
/// If [message] is a [Function], it will be lazy evaluated. Additionally, if
148-
/// [message] or its evaluated value is not a [String], then 'toString()' will
149-
/// be called on the object and the result will be logged. The log record will
150-
/// contain a field holding the original object.
151-
///
152-
/// The log record will also contain a field for the zone in which this call
153-
/// was made. This can be advantageous if a log listener wants to handler
154-
/// records of different zones differently (e.g. group log records by HTTP
155-
/// request if each HTTP request handler runs in it's own zone).
156-
void log(Level logLevel, message,
157-
[Object error, StackTrace stackTrace, Zone zone]) {
158-
Object object;
159-
if (isLoggable(logLevel)) {
160-
if (message is Function) {
161-
message = message();
162-
}
163-
164-
String msg;
165-
if (message is String) {
166-
msg = message;
167-
} else {
168-
msg = message.toString();
169-
object = message;
170-
}
171-
172-
if (stackTrace == null && logLevel >= recordStackTraceAtLevel) {
173-
stackTrace = StackTrace.current;
174-
error ??= 'autogenerated stack trace for $logLevel $msg';
175-
}
176-
zone ??= Zone.current;
177-
178-
var record =
179-
LogRecord(logLevel, msg, fullName, error, stackTrace, zone, object);
180-
181-
if (hierarchicalLoggingEnabled) {
182-
var target = this;
183-
while (target != null) {
184-
target._publish(record);
185-
target = target.parent;
186-
}
187-
} else {
188-
root._publish(record);
189-
}
190-
}
191-
}
192-
193-
/// Log message at level [Level.FINEST].
194-
void finest(message, [Object error, StackTrace stackTrace]) =>
195-
log(Level.FINEST, message, error, stackTrace);
196-
197-
/// Log message at level [Level.FINER].
198-
void finer(message, [Object error, StackTrace stackTrace]) =>
199-
log(Level.FINER, message, error, stackTrace);
200-
201-
/// Log message at level [Level.FINE].
202-
void fine(message, [Object error, StackTrace stackTrace]) =>
203-
log(Level.FINE, message, error, stackTrace);
204-
205-
/// Log message at level [Level.CONFIG].
206-
void config(message, [Object error, StackTrace stackTrace]) =>
207-
log(Level.CONFIG, message, error, stackTrace);
208-
209-
/// Log message at level [Level.INFO].
210-
void info(message, [Object error, StackTrace stackTrace]) =>
211-
log(Level.INFO, message, error, stackTrace);
212-
213-
/// Log message at level [Level.WARNING].
214-
void warning(message, [Object error, StackTrace stackTrace]) =>
215-
log(Level.WARNING, message, error, stackTrace);
216-
217-
/// Log message at level [Level.SEVERE].
218-
void severe(message, [Object error, StackTrace stackTrace]) =>
219-
log(Level.SEVERE, message, error, stackTrace);
220-
221-
/// Log message at level [Level.SHOUT].
222-
void shout(message, [Object error, StackTrace stackTrace]) =>
223-
log(Level.SHOUT, message, error, stackTrace);
224-
225-
Stream<LogRecord> _getStream() {
226-
if (hierarchicalLoggingEnabled || parent == null) {
227-
_controller ??= StreamController<LogRecord>.broadcast(sync: true);
228-
return _controller.stream;
229-
} else {
230-
return root._getStream();
231-
}
232-
}
233-
234-
void _publish(LogRecord record) {
235-
if (_controller != null) {
236-
_controller.add(record);
237-
}
238-
}
239-
240-
/// Top-level root [Logger].
241-
static final Logger root = Logger('');
242-
243-
/// All [Logger]s in the system.
244-
static final Map<String, Logger> _loggers = <String, Logger>{};
245-
}
8+
export 'src/level.dart';
9+
export 'src/log_record.dart';
10+
export 'src/logger.dart';
24611

24712
/// Handler callback to process log entries as they are added to a [Logger].
248-
@deprecated
13+
@Deprecated('Will be removed in 1.0.0')
24914
typedef LoggerHandler = void Function(LogRecord record);
250-
251-
/// [Level]s to control logging output. Logging can be enabled to include all
252-
/// levels above certain [Level]. [Level]s are ordered using an integer
253-
/// value [Level.value]. The predefined [Level] constants below are sorted as
254-
/// follows (in descending order): [Level.SHOUT], [Level.SEVERE],
255-
/// [Level.WARNING], [Level.INFO], [Level.CONFIG], [Level.FINE], [Level.FINER],
256-
/// [Level.FINEST], and [Level.ALL].
257-
///
258-
/// We recommend using one of the predefined logging levels. If you define your
259-
/// own level, make sure you use a value between those used in [Level.ALL] and
260-
/// [Level.OFF].
261-
class Level implements Comparable<Level> {
262-
final String name;
263-
264-
/// Unique value for this level. Used to order levels, so filtering can
265-
/// exclude messages whose level is under certain value.
266-
final int value;
267-
268-
const Level(this.name, this.value);
269-
270-
/// Special key to turn on logging for all levels ([value] = 0).
271-
static const Level ALL = Level('ALL', 0);
272-
273-
/// Special key to turn off all logging ([value] = 2000).
274-
static const Level OFF = Level('OFF', 2000);
275-
276-
/// Key for highly detailed tracing ([value] = 300).
277-
static const Level FINEST = Level('FINEST', 300);
278-
279-
/// Key for fairly detailed tracing ([value] = 400).
280-
static const Level FINER = Level('FINER', 400);
281-
282-
/// Key for tracing information ([value] = 500).
283-
static const Level FINE = Level('FINE', 500);
284-
285-
/// Key for static configuration messages ([value] = 700).
286-
static const Level CONFIG = Level('CONFIG', 700);
287-
288-
/// Key for informational messages ([value] = 800).
289-
static const Level INFO = Level('INFO', 800);
290-
291-
/// Key for potential problems ([value] = 900).
292-
static const Level WARNING = Level('WARNING', 900);
293-
294-
/// Key for serious failures ([value] = 1000).
295-
static const Level SEVERE = Level('SEVERE', 1000);
296-
297-
/// Key for extra debugging loudness ([value] = 1200).
298-
static const Level SHOUT = Level('SHOUT', 1200);
299-
300-
static const List<Level> LEVELS = [
301-
ALL,
302-
FINEST,
303-
FINER,
304-
FINE,
305-
CONFIG,
306-
INFO,
307-
WARNING,
308-
SEVERE,
309-
SHOUT,
310-
OFF
311-
];
312-
313-
@override
314-
bool operator ==(Object other) => other is Level && value == other.value;
315-
bool operator <(Level other) => value < other.value;
316-
bool operator <=(Level other) => value <= other.value;
317-
bool operator >(Level other) => value > other.value;
318-
bool operator >=(Level other) => value >= other.value;
319-
320-
@override
321-
int compareTo(Level other) => value - other.value;
322-
323-
@override
324-
int get hashCode => value;
325-
326-
@override
327-
String toString() => name;
328-
}
329-
330-
/// A log entry representation used to propagate information from [Logger] to
331-
/// individual handlers.
332-
class LogRecord {
333-
final Level level;
334-
final String message;
335-
336-
/// Non-string message passed to Logger.
337-
final Object object;
338-
339-
/// Logger where this record is stored.
340-
final String loggerName;
341-
342-
/// Time when this record was created.
343-
final DateTime time;
344-
345-
/// Unique sequence number greater than all log records created before it.
346-
final int sequenceNumber;
347-
348-
static int _nextNumber = 0;
349-
350-
/// Associated error (if any) when recording errors messages.
351-
final Object error;
352-
353-
/// Associated stackTrace (if any) when recording errors messages.
354-
final StackTrace stackTrace;
355-
356-
/// Zone of the calling code which resulted in this LogRecord.
357-
final Zone zone;
358-
359-
LogRecord(this.level, this.message, this.loggerName,
360-
[this.error, this.stackTrace, this.zone, this.object])
361-
: time = DateTime.now(),
362-
sequenceNumber = LogRecord._nextNumber++;
363-
364-
@override
365-
String toString() => '[${level.name}] $loggerName: $message';
366-
}

0 commit comments

Comments
 (0)