OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library code_transformers.messages.messages_logger; |
| 6 |
| 7 import 'dart:async'; |
| 8 import 'dart:convert' show JSON; |
| 9 |
| 10 import 'package:barback/barback.dart'; |
| 11 import 'package:source_span/source_span.dart'; |
| 12 |
| 13 import 'messages.dart' show Message, MessageId, BuildLogEntry, LogEntryTable; |
| 14 |
| 15 /// A [TransformLogger] used to track error and warning messages produced during |
| 16 /// a build. |
| 17 /// |
| 18 /// This logger records all messages that were logged and then forwards |
| 19 /// the calls to an underlying [TransformLogger]. The internal records support |
| 20 /// serializing the errors and emiting them to an asset (so they can be |
| 21 /// presented to the user in a web-based client), clustering similar messages |
| 22 /// together, sorting messages in order of importance, etc. |
| 23 /// |
| 24 /// The logger also supports reporting error messages as warnings. Barback makes |
| 25 /// error messages stop the transformation process, which sometimes can surprise |
| 26 /// users. Turning errors into warnings is especially useful when used within |
| 27 /// `pub serve`, where we would like the transformation to continue as far as it |
| 28 /// can. When this flag is turned on, the level is still recorded as an error, |
| 29 /// so a web client UI can still highlight their importance. |
| 30 // TODO(sigmund): also cluster messages when they are reported on the |
| 31 // command-line. |
| 32 class BuildLogger implements TransformLogger { |
| 33 /// Underling transform that is currently active. |
| 34 final Transform _transform; |
| 35 |
| 36 /// Logs created during the current transform. |
| 37 final LogEntryTable _logs = new LogEntryTable(); |
| 38 |
| 39 /// Whether to use `warning` or `error` when forwarding error messages to the |
| 40 /// underlying logger in `_transform.logger`. |
| 41 final bool convertErrorsToWarnings; |
| 42 |
| 43 BuildLogger(this._transform, {this.convertErrorsToWarnings: false}); |
| 44 |
| 45 /// Records a message at the fine level. If [msg] is a [Message] it is |
| 46 /// recorded directly, otherwise it is first converted to a [String]. |
| 47 void fine(msg, {AssetId asset, SourceSpan span}) { |
| 48 msg = msg is Message ? msg : new Message.unknown('$msg'); |
| 49 _transform.logger.fine(msg.snippet, asset: asset, span: span); |
| 50 _logs.add(new BuildLogEntry(msg, span, LogLevel.FINE.name)); |
| 51 } |
| 52 |
| 53 /// Records a message at the info level. If [msg] is a [Message] it is |
| 54 /// recorded directly, otherwise it is first converted to a [String]. |
| 55 void info(msg, {AssetId asset, SourceSpan span}) { |
| 56 msg = msg is Message ? msg : new Message.unknown('$msg'); |
| 57 _transform.logger.info(msg.snippet, asset: asset, span: span); |
| 58 _logs.add(new BuildLogEntry(msg, span, LogLevel.INFO.name)); |
| 59 } |
| 60 |
| 61 /// Records a warning message. If [msg] is a [Message] it is recorded |
| 62 /// directly, otherwise it is first converted to a [String]. |
| 63 void warning(msg, {AssetId asset, SourceSpan span}) { |
| 64 msg = msg is Message ? msg : new Message.unknown('$msg'); |
| 65 _transform.logger.warning(msg.snippet, asset: asset, span: span); |
| 66 _logs.add(new BuildLogEntry(msg, span, LogLevel.WARNING.name)); |
| 67 } |
| 68 |
| 69 /// Records an error message. If [msg] is a [Message] it is recorded |
| 70 /// directly, otherwise it is first converted to a [String]. |
| 71 void error(msg, {AssetId asset, SourceSpan span}) { |
| 72 msg = msg is Message ? msg : new Message.unknown('$msg'); |
| 73 if (convertErrorsToWarnings) { |
| 74 _transform.logger.warning(msg.snippet, asset: asset, span: span); |
| 75 } else { |
| 76 _transform.logger.error(msg.snippet, asset: asset, span: span); |
| 77 } |
| 78 _logs.add(new BuildLogEntry(msg, span, LogLevel.ERROR.name)); |
| 79 } |
| 80 |
| 81 /// Outputs the log data to a JSON serialized file. |
| 82 Future writeOutput() { |
| 83 return _getNextLogAssetPath().then((path) { |
| 84 _transform.addOutput(new Asset.fromString(path, |
| 85 JSON.encode(_logs))); |
| 86 }); |
| 87 } |
| 88 |
| 89 // Each phase outputs a new log file with an incrementing # appended, this |
| 90 // figures out the next # to use. |
| 91 Future<String> _getNextLogAssetPath([int nextNumber = 1]) { |
| 92 var nextAssetPath = _transform.primaryInput.id.addExtension( |
| 93 '${LOG_EXTENSION}.$nextNumber'); |
| 94 return _transform.hasInput(nextAssetPath).then((exists) { |
| 95 if (!exists) return nextAssetPath; |
| 96 return _getNextLogAssetPath(++nextNumber); |
| 97 }); |
| 98 } |
| 99 |
| 100 // Reads all log files for an Asset into [logs]. |
| 101 static Future _readLogFilesForAsset(AssetId id, Transform transform, |
| 102 LogEntryTable entries, [nextNumber = 1]) { |
| 103 var nextAssetPath = id.addExtension('${LOG_EXTENSION}.$nextNumber'); |
| 104 return transform.hasInput(nextAssetPath).then((exists) { |
| 105 if (!exists) return null; |
| 106 return transform.readInputAsString(nextAssetPath).then((data) { |
| 107 entries.addAll(new LogEntryTable.fromJson(JSON.decode(data))); |
| 108 return _readLogFilesForAsset(id, transform, entries, ++nextNumber); |
| 109 }); |
| 110 }); |
| 111 } |
| 112 |
| 113 // Combines all existing ._buildLogs.* files into a single ._buildLogs file. |
| 114 static Future combineLogFiles(Transform transform) { |
| 115 var entries = new LogEntryTable(); |
| 116 var id = transform.primaryInput.id; |
| 117 return _readLogFilesForAsset(id, transform, entries).then((_) { |
| 118 return transform.addOutput(new Asset.fromString( |
| 119 id.addExtension(LOG_EXTENSION), |
| 120 JSON.encode(entries.toJson()))); |
| 121 }); |
| 122 } |
| 123 |
| 124 // Reads all logs for an asset and adds them to this loggers log output. |
| 125 Future addLogFilesFromAsset(AssetId id, [int nextNumber = 1]) { |
| 126 return _readLogFilesForAsset(id, _transform, _logs); |
| 127 } |
| 128 } |
| 129 |
| 130 /// Extension used for assets that contained serialized logs. |
| 131 const String LOG_EXTENSION = '._buildLogs'; |
OLD | NEW |