| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:async'; |
| import 'dart:io' show stderr; |
| |
| /// Standard error thrown by Flutter Driver API. |
| class DriverError extends Error { |
| /// Create an error with a [message] and (optionally) the [originalError] and |
| /// [originalStackTrace] that caused it. |
| DriverError(this.message, [this.originalError, this.originalStackTrace]); |
| |
| /// Human-readable error message. |
| final String message; |
| |
| /// The error object that was caught and wrapped by this error object. |
| final dynamic originalError; |
| |
| /// The stack trace that was caught and wrapped by this error object. |
| final dynamic originalStackTrace; |
| |
| @override |
| String toString() { |
| return '''DriverError: $message |
| Original error: $originalError |
| Original stack trace: |
| $originalStackTrace |
| '''; |
| } |
| } |
| |
| // Whether someone redirected the log messages somewhere. |
| bool _noLogSubscribers = true; |
| |
| final StreamController<LogRecord> _logger = |
| new StreamController<LogRecord>.broadcast(sync: true, onListen: () { |
| _noLogSubscribers = false; |
| }); |
| |
| void _log(LogLevel level, String loggerName, Object message) { |
| final LogRecord record = new LogRecord._(level, loggerName, '$message'); |
| // If nobody expressed interest in rerouting log messages somewhere specific, |
| // print them to stderr. |
| if (_noLogSubscribers) |
| stderr.writeln(record); |
| else |
| _logger.add(record); |
| } |
| |
| /// Emits log records from Flutter Driver. |
| final Stream<LogRecord> flutterDriverLog = _logger.stream; |
| |
| /// Severity of a log entry. |
| enum LogLevel { |
| /// Messages used to supplement the higher-level messages with more details. |
| /// |
| /// This will likely produce a lot of output. |
| trace, |
| |
| /// Informational messages that do not indicate a problem. |
| info, |
| |
| /// A potential problem. |
| warning, |
| |
| /// A certain problem but the program will attempt to continue. |
| error, |
| |
| /// A critical problem; the program will attempt to quit immediately. |
| critical, |
| } |
| |
| /// A log entry, as emitted on [flutterDriverLog]. |
| class LogRecord { |
| const LogRecord._(this.level, this.loggerName, this.message); |
| |
| /// The severity of the log record. |
| final LogLevel level; |
| |
| /// The name of the logger that logged the message. |
| final String loggerName; |
| |
| /// The log message. |
| /// |
| /// The message should be a normal and complete sentence ending with a period. |
| /// It is OK to omit the subject in the message to imply [loggerName]. It is |
| /// also OK to omit article, such as "the" and "a". |
| /// |
| /// Example: if [loggerName] is "FlutterDriver" and [message] is "Failed to |
| /// connect to application." then this log record means that FlutterDriver |
| /// failed to connect to the application. |
| final String message; |
| |
| /// Short description of the log level. |
| /// |
| /// It is meant to be read by humans. There's no guarantee that this value is |
| /// stable enough to be parsed by machines. |
| String get levelDescription => level.toString().split('.').last; |
| |
| @override |
| String toString() => '[${levelDescription.padRight(5)}] $loggerName: $message'; |
| } |
| |
| /// Logger used internally by Flutter Driver to avoid mandating any specific |
| /// logging library. |
| /// |
| /// By default the output from this logger is printed to [stderr]. However, a |
| /// subscriber to the [flutterDriverLog] stream may redirect the log records |
| /// elsewhere, including other logging API. The logger stops sending messages to |
| /// [stderr] upon first subscriber. |
| /// |
| /// This class is package-private. Flutter users should use other public logging |
| /// libraries. |
| class Logger { |
| /// Creates a new logger. |
| Logger(this.name); |
| |
| /// Identifies the part of the system that emits message into this object. |
| /// |
| /// It is common for [name] to be used as an implicit subject of an action |
| /// described in a log message. For example, if you emit message "failed" and |
| /// [name] is "FlutterDriver", the meaning of the message should be understood |
| /// as "FlutterDriver failed". See also [LogRecord.message]. |
| final String name; |
| |
| /// Emits a [LogLevel.trace] record into `this` logger. |
| void trace(Object message) { |
| _log(LogLevel.trace, name, message); |
| } |
| |
| /// Emits a [LogLevel.info] record into `this` logger. |
| void info(Object message) { |
| _log(LogLevel.info, name, message); |
| } |
| |
| /// Emits a [LogLevel.warning] record into `this` logger. |
| void warning(Object message) { |
| _log(LogLevel.warning, name, message); |
| } |
| |
| /// Emits a [LogLevel.error] record into `this` logger. |
| void error(Object message) { |
| _log(LogLevel.error, name, message); |
| } |
| |
| /// Emits a [LogLevel.critical] record into `this` logger. |
| void critical(Object message) { |
| _log(LogLevel.critical, name, message); |
| } |
| } |