| Index: mojo/public/dart/third_party/analyzer/lib/instrumentation/instrumentation.dart
|
| diff --git a/mojo/public/dart/third_party/analyzer/lib/instrumentation/instrumentation.dart b/mojo/public/dart/third_party/analyzer/lib/instrumentation/instrumentation.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..40db35e549652c429e6dac3b240f6d868c1ce9d9
|
| --- /dev/null
|
| +++ b/mojo/public/dart/third_party/analyzer/lib/instrumentation/instrumentation.dart
|
| @@ -0,0 +1,374 @@
|
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library instrumentation;
|
| +
|
| +import 'dart:convert';
|
| +
|
| +import 'package:analyzer/task/model.dart';
|
| +
|
| +/**
|
| + * A container with analysis performance constants.
|
| + */
|
| +class AnalysisPerformanceKind {
|
| + static const String FULL = 'analysis_full';
|
| + static const String INCREMENTAL = 'analysis_incremental';
|
| +}
|
| +
|
| +/**
|
| + * The interface used by client code to communicate with an instrumentation
|
| + * server.
|
| + */
|
| +abstract class InstrumentationServer {
|
| + /**
|
| + * Pass the given [message] to the instrumentation server so that it will be
|
| + * logged with other messages.
|
| + *
|
| + * This method should be used for most logging.
|
| + */
|
| + void log(String message);
|
| +
|
| + /**
|
| + * Pass the given [message] to the instrumentation server so that it will be
|
| + * logged with other messages.
|
| + *
|
| + * This method should only be used for logging high priority messages, such as
|
| + * exceptions that cause the server to shutdown.
|
| + */
|
| + void logWithPriority(String message);
|
| +
|
| + /**
|
| + * Signal that the client is done communicating with the instrumentation
|
| + * server. This method should be invoked exactly one time and no other methods
|
| + * should be invoked on this instance after this method has been invoked.
|
| + */
|
| + void shutdown();
|
| +}
|
| +
|
| +/**
|
| + * The interface used by client code to communicate with an instrumentation
|
| + * server by wrapping an [InstrumentationServer].
|
| + */
|
| +class InstrumentationService {
|
| + /**
|
| + * An instrumentation service that will not log any instrumentation data.
|
| + */
|
| + static final InstrumentationService NULL_SERVICE =
|
| + new InstrumentationService(null);
|
| +
|
| + static const String TAG_ANALYSIS_TASK = 'Task';
|
| + static const String TAG_ERROR = 'Err';
|
| + static const String TAG_EXCEPTION = 'Ex';
|
| + static const String TAG_FILE_READ = 'Read';
|
| + static const String TAG_LOG_ENTRY = 'Log';
|
| + static const String TAG_NOTIFICATION = 'Noti';
|
| + static const String TAG_PERFORMANCE = 'Perf';
|
| + static const String TAG_REQUEST = 'Req';
|
| + static const String TAG_RESPONSE = 'Res';
|
| + static const String TAG_SUBPROCESS_START = 'SPStart';
|
| + static const String TAG_SUBPROCESS_RESULT = 'SPResult';
|
| + static const String TAG_VERSION = 'Ver';
|
| + static const String TAG_WATCH_EVENT = 'Watch';
|
| +
|
| + /**
|
| + * The instrumentation server used to communicate with the server, or `null`
|
| + * if instrumentation data should not be logged.
|
| + */
|
| + InstrumentationServer _instrumentationServer;
|
| +
|
| + /**
|
| + * Counter used to generate unique ID's for [logSubprocessStart].
|
| + */
|
| + int _subprocessCounter = 0;
|
| +
|
| + /**
|
| + * Initialize a newly created instrumentation service to comunicate with the
|
| + * given [instrumentationServer].
|
| + */
|
| + InstrumentationService(this._instrumentationServer);
|
| +
|
| + /**
|
| + * Return `true` if this [InstrumentationService] was initialized with a
|
| + * non-`null` server (and hence instrumentation is active).
|
| + */
|
| + bool get isActive => _instrumentationServer != null;
|
| +
|
| + /**
|
| + * The current time, expressed as a decimal encoded number of milliseconds.
|
| + */
|
| + String get _timestamp => new DateTime.now().millisecondsSinceEpoch.toString();
|
| +
|
| + /**
|
| + * Log that the given analysis [task] is being performed in the given
|
| + * [context].
|
| + */
|
| + void logAnalysisTask(String context, dynamic task) {
|
| + // TODO(brianwilkerson) When the old task model is removed, change the
|
| + // parameter type to AnalysisTask.
|
| + if (_instrumentationServer != null) {
|
| + String description =
|
| + (task is AnalysisTask) ? task.description : task.toString();
|
| + _instrumentationServer
|
| + .log(_join([TAG_ANALYSIS_TASK, context, description]));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Log the fact that an error, described by the given [message], has occurred.
|
| + */
|
| + void logError(String message) {
|
| + _log(TAG_ERROR, message);
|
| + }
|
| +
|
| + /**
|
| + * Log that the given non-priority [exception] was thrown, with the given
|
| + * [stackTrace].
|
| + */
|
| + void logException(dynamic exception, StackTrace stackTrace) {
|
| + if (_instrumentationServer != null) {
|
| + String message = _toString(exception);
|
| + String trace = _toString(stackTrace);
|
| + _instrumentationServer.log(_join([TAG_EXCEPTION, message, trace]));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Log that the contents of the file with the given [path] were read. The file
|
| + * had the given [content] and [modificationTime].
|
| + */
|
| + void logFileRead(String path, int modificationTime, String content) {
|
| + if (_instrumentationServer != null) {
|
| + String timeStamp = _toString(modificationTime);
|
| + _instrumentationServer
|
| + .log(_join([TAG_FILE_READ, path, timeStamp, content]));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Log that a log entry that was written to the analysis engine's log. The log
|
| + * entry has the given [level] and [message], and was created at the given
|
| + * [time].
|
| + */
|
| + void logLogEntry(String level, DateTime time, String message, Object exception, StackTrace stackTrace) {
|
| + if (_instrumentationServer != null) {
|
| + String timeStamp =
|
| + time == null ? 'null' : time.millisecondsSinceEpoch.toString();
|
| + String exceptionText = exception.toString();
|
| + String stackTraceText = stackTrace.toString();
|
| + _instrumentationServer
|
| + .log(_join([TAG_LOG_ENTRY, level, timeStamp, message, exceptionText, stackTraceText]));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Log that a notification has been sent to the client.
|
| + */
|
| + void logNotification(String notification) {
|
| + _log(TAG_NOTIFICATION, notification);
|
| + }
|
| +
|
| + /**
|
| + * Log the given performance fact.
|
| + */
|
| + void logPerformance(String kind, Stopwatch sw, String message) {
|
| + sw.stop();
|
| + String elapsed = sw.elapsedMilliseconds.toString();
|
| + if (_instrumentationServer != null) {
|
| + _instrumentationServer
|
| + .log(_join([TAG_PERFORMANCE, kind, elapsed, message]));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Log that the given priority [exception] was thrown, with the given
|
| + * [stackTrace].
|
| + */
|
| + void logPriorityException(dynamic exception, StackTrace stackTrace) {
|
| + if (_instrumentationServer != null) {
|
| + String message = _toString(exception);
|
| + String trace = _toString(stackTrace);
|
| + _instrumentationServer
|
| + .logWithPriority(_join([TAG_EXCEPTION, message, trace]));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Log that a request has been sent to the client.
|
| + */
|
| + void logRequest(String request) {
|
| + _log(TAG_REQUEST, request);
|
| + }
|
| +
|
| + /**
|
| + * Log that a response has been sent to the client.
|
| + */
|
| + void logResponse(String response) {
|
| + _log(TAG_RESPONSE, response);
|
| + }
|
| +
|
| + /**
|
| + * Log the result of executing a subprocess. [subprocessId] should be the
|
| + * unique IDreturned by [logSubprocessStart].
|
| + */
|
| + void logSubprocessResult(
|
| + int subprocessId, int exitCode, String stdout, String stderr) {
|
| + if (_instrumentationServer != null) {
|
| + _instrumentationServer.log(_join([
|
| + TAG_SUBPROCESS_RESULT,
|
| + subprocessId.toString(),
|
| + exitCode.toString(),
|
| + JSON.encode(stdout),
|
| + JSON.encode(stderr)
|
| + ]));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Log that the given subprocess is about to be executed. Returns a unique
|
| + * identifier that can be used to identify the subprocess for later log
|
| + * entries.
|
| + */
|
| + int logSubprocessStart(
|
| + String executablePath, List<String> arguments, String workingDirectory) {
|
| + int subprocessId = _subprocessCounter++;
|
| + if (_instrumentationServer != null) {
|
| + _instrumentationServer.log(_join([
|
| + TAG_SUBPROCESS_START,
|
| + subprocessId.toString(),
|
| + executablePath,
|
| + workingDirectory,
|
| + JSON.encode(arguments)
|
| + ]));
|
| + }
|
| + return subprocessId;
|
| + }
|
| +
|
| + /**
|
| + * Signal that the client has started analysis server.
|
| + * This method should be invoked exactly one time.
|
| + */
|
| + void logVersion(String uuid, String clientId, String clientVersion,
|
| + String serverVersion, String sdkVersion) {
|
| + String normalize(String value) =>
|
| + value != null && value.length > 0 ? value : 'unknown';
|
| +
|
| + if (_instrumentationServer != null) {
|
| + _instrumentationServer.logWithPriority(_join([
|
| + TAG_VERSION,
|
| + uuid,
|
| + normalize(clientId),
|
| + normalize(clientVersion),
|
| + serverVersion,
|
| + sdkVersion
|
| + ]));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Log that the file system watcher sent an event. The [folderPath] is the
|
| + * path to the folder containing the changed file, the [filePath] is the path
|
| + * of the file that changed, and the [changeType] indicates what kind of
|
| + * change occurred.
|
| + */
|
| + void logWatchEvent(String folderPath, String filePath, String changeType) {
|
| + if (_instrumentationServer != null) {
|
| + _instrumentationServer
|
| + .log(_join([TAG_WATCH_EVENT, folderPath, filePath, changeType]));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Signal that the client is done communicating with the instrumentation
|
| + * server. This method should be invoked exactly one time and no other methods
|
| + * should be invoked on this instance after this method has been invoked.
|
| + */
|
| + void shutdown() {
|
| + if (_instrumentationServer != null) {
|
| + _instrumentationServer.shutdown();
|
| + _instrumentationServer = null;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Write an escaped version of the given [field] to the given [buffer].
|
| + */
|
| + void _escape(StringBuffer buffer, String field) {
|
| + int index = field.indexOf(':');
|
| + if (index < 0) {
|
| + buffer.write(field);
|
| + return;
|
| + }
|
| + int start = 0;
|
| + while (index >= 0) {
|
| + buffer.write(field.substring(start, index));
|
| + buffer.write('::');
|
| + start = index + 1;
|
| + index = field.indexOf(':', start);
|
| + }
|
| + buffer.write(field.substring(start));
|
| + }
|
| +
|
| + /**
|
| + * Return the result of joining the values of the given fields, escaping the
|
| + * separator character by doubling it.
|
| + */
|
| + String _join(List<String> fields) {
|
| + StringBuffer buffer = new StringBuffer();
|
| + buffer.write(_timestamp);
|
| + for (String field in fields) {
|
| + buffer.write(':');
|
| + _escape(buffer, field);
|
| + }
|
| + return buffer.toString();
|
| + }
|
| +
|
| + /**
|
| + * Log the given message with the given tag.
|
| + */
|
| + void _log(String tag, String message) {
|
| + if (_instrumentationServer != null) {
|
| + _instrumentationServer.log(_join([tag, message]));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Convert the given [object] to a string.
|
| + */
|
| + String _toString(Object object) {
|
| + if (object == null) {
|
| + return 'null';
|
| + }
|
| + return object.toString();
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * An [InstrumentationServer] that sends messages to multiple instances.
|
| + */
|
| +class MulticastInstrumentationServer implements InstrumentationServer {
|
| + final List<InstrumentationServer> _servers;
|
| +
|
| + MulticastInstrumentationServer(this._servers);
|
| +
|
| + @override
|
| + void log(String message) {
|
| + for (InstrumentationServer server in _servers) {
|
| + server.log(message);
|
| + }
|
| + }
|
| +
|
| + @override
|
| + void logWithPriority(String message) {
|
| + for (InstrumentationServer server in _servers) {
|
| + server.logWithPriority(message);
|
| + }
|
| + }
|
| +
|
| + @override
|
| + void shutdown() {
|
| + for (InstrumentationServer server in _servers) {
|
| + server.shutdown();
|
| + }
|
| + }
|
| +}
|
|
|