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