• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'dart:async';
6import 'dart:io' show stderr;
7
8/// Standard error thrown by Flutter Driver API.
9class DriverError extends Error {
10  /// Create an error with a [message] and (optionally) the [originalError] and
11  /// [originalStackTrace] that caused it.
12  DriverError(this.message, [this.originalError, this.originalStackTrace]);
13
14  /// Human-readable error message.
15  final String message;
16
17  /// The error object that was caught and wrapped by this error object.
18  final dynamic originalError;
19
20  /// The stack trace that was caught and wrapped by this error object.
21  final dynamic originalStackTrace;
22
23  @override
24  String toString() {
25    return '''DriverError: $message
26Original error: $originalError
27Original stack trace:
28$originalStackTrace
29    ''';
30  }
31}
32
33// Whether someone redirected the log messages somewhere.
34bool _noLogSubscribers = true;
35
36final StreamController<LogRecord> _logger =
37  StreamController<LogRecord>.broadcast(sync: true, onListen: () {
38    _noLogSubscribers = false;
39  });
40
41void _log(LogLevel level, String loggerName, Object message) {
42  final LogRecord record = LogRecord._(level, loggerName, '$message');
43  // If nobody expressed interest in rerouting log messages somewhere specific,
44  // print them to stderr.
45  if (_noLogSubscribers)
46    stderr.writeln(record);
47  else
48    _logger.add(record);
49}
50
51/// Emits log records from Flutter Driver.
52final Stream<LogRecord> flutterDriverLog = _logger.stream;
53
54/// Severity of a log entry.
55enum LogLevel {
56  /// Messages used to supplement the higher-level messages with more details.
57  ///
58  /// This will likely produce a lot of output.
59  trace,
60
61  /// Informational messages that do not indicate a problem.
62  info,
63
64  /// A potential problem.
65  warning,
66
67  /// A certain problem but the program will attempt to continue.
68  error,
69
70  /// A critical problem; the program will attempt to quit immediately.
71  critical,
72}
73
74/// A log entry, as emitted on [flutterDriverLog].
75class LogRecord {
76  const LogRecord._(this.level, this.loggerName, this.message);
77
78  /// The severity of the log record.
79  final LogLevel level;
80
81  /// The name of the logger that logged the message.
82  final String loggerName;
83
84  /// The log message.
85  ///
86  /// The message should be a normal and complete sentence ending with a period.
87  /// It is OK to omit the subject in the message to imply [loggerName]. It is
88  /// also OK to omit article, such as "the" and "a".
89  ///
90  /// Example: if [loggerName] is "FlutterDriver" and [message] is "Failed to
91  /// connect to application." then this log record means that FlutterDriver
92  /// failed to connect to the application.
93  final String message;
94
95  /// Short description of the log level.
96  ///
97  /// It is meant to be read by humans. There's no guarantee that this value is
98  /// stable enough to be parsed by machines.
99  String get levelDescription => level.toString().split('.').last;
100
101  @override
102  String toString() => '[${levelDescription.padRight(5)}] $loggerName: $message';
103}
104
105/// Logger used internally by Flutter Driver to avoid mandating any specific
106/// logging library.
107///
108/// By default the output from this logger is printed to [stderr]. However, a
109/// subscriber to the [flutterDriverLog] stream may redirect the log records
110/// elsewhere, including other logging API. The logger stops sending messages to
111/// [stderr] upon first subscriber.
112///
113/// This class is package-private. Flutter users should use other public logging
114/// libraries.
115class Logger {
116  /// Creates a new logger.
117  Logger(this.name);
118
119  /// Identifies the part of the system that emits message into this object.
120  ///
121  /// It is common for [name] to be used as an implicit subject of an action
122  /// described in a log message. For example, if you emit message "failed" and
123  /// [name] is "FlutterDriver", the meaning of the message should be understood
124  /// as "FlutterDriver failed". See also [LogRecord.message].
125  final String name;
126
127  /// Emits a [LogLevel.trace] record into `this` logger.
128  void trace(Object message) {
129    _log(LogLevel.trace, name, message);
130  }
131
132  /// Emits a [LogLevel.info] record into `this` logger.
133  void info(Object message) {
134    _log(LogLevel.info, name, message);
135  }
136
137  /// Emits a [LogLevel.warning] record into `this` logger.
138  void warning(Object message) {
139    _log(LogLevel.warning, name, message);
140  }
141
142  /// Emits a [LogLevel.error] record into `this` logger.
143  void error(Object message) {
144    _log(LogLevel.error, name, message);
145  }
146
147  /// Emits a [LogLevel.critical] record into `this` logger.
148  void critical(Object message) {
149    _log(LogLevel.critical, name, message);
150  }
151}
152