| // 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 = | |
| StreamController<LogRecord>.broadcast(sync: true, onListen: () { | |
| _noLogSubscribers = false; | |
| }); | |
| void _log(LogLevel level, String loggerName, Object message) { | |
| final LogRecord record = 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); | |
| } | |
| } |