blob: 85f6a7f08f35b8cf2164efed55b494233ec5e2de [file] [log] [blame]
// Copyright (c) 2015, 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.
import 'dart:convert';
import 'package:analyzer/exception/exception.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:logging/logging.dart';
import 'input_converter.dart';
import 'operation.dart';
final int COLON = ':'.codeUnitAt(0);
/**
* [InstrumentationInputConverter] converts an instrumentation stream
* into a series of operations to be sent to the analysis server.
*/
class InstrumentationInputConverter extends CommonInputConverter {
final Set<String> codesSeen = new Set<String>();
/**
* [readBuffer] holds the contents of the file being read from disk
* as recorded in the instrumentation log
* or `null` if not converting a "Read" entry.
*/
StringBuffer readBuffer = null;
InstrumentationInputConverter(String tmpSrcDirPath, PathMap srcPathMap)
: super(tmpSrcDirPath, srcPathMap);
@override
Operation convert(String line) {
List<String> fields;
try {
fields = _parseFields(line);
if (fields.length < 2) {
if (readBuffer != null) {
readBuffer.writeln(fields.length == 1 ? fields[0] : '');
return null;
}
throw 'Failed to process line:\n$line';
}
if (readBuffer != null) {
readBuffer = null;
}
} catch (e, s) {
throw new AnalysisException(
'Failed to parse line\n$line', new CaughtException(e, s));
}
// int timeStamp = int.parse(fields[0], onError: (_) => -1);
String opCode = fields[1];
if (opCode == InstrumentationService.TAG_NOTIFICATION) {
return convertNotification(decodeJson(line, fields[2]));
} else if (opCode == 'Read') {
// 1434096943209:Read:/some/file/path:1434095535000:<file content>
//String filePath = fields[2];
readBuffer = new StringBuffer(fields.length > 4 ? fields[4] : '');
return null;
} else if (opCode == InstrumentationService.TAG_REQUEST) {
return convertRequest(decodeJson(line, fields[2]));
} else if (opCode == InstrumentationService.TAG_RESPONSE) {
// 1434096937454:Res:{"id"::"0","result"::{"version"::"1.7.0"}}
return convertResponse(decodeJson(line, fields[2]));
} else if (opCode == InstrumentationService.TAG_ANALYSIS_TASK) {
// 1434096943208:Task:/Users/
return null;
} else if (opCode == InstrumentationService.TAG_LOG_ENTRY) {
// 1434096937454:Res:{"id"::"0","result"::{"version"::"1.7.0"}}
return null;
} else if (opCode == InstrumentationService.TAG_PERFORMANCE) {
//1434096960092:Perf:analysis_full:16884:context_id=0
return null;
} else if (opCode == InstrumentationService.TAG_SUBPROCESS_START) {
// 1434096938634:SPStart:0:/Users/da
return null;
} else if (opCode == InstrumentationService.TAG_SUBPROCESS_RESULT) {
// 1434096939068:SPResult:0:0:"{\"packages\"::{\"rpi_lidar\"::\"/Users
return null;
} else if (opCode == InstrumentationService.TAG_VERSION) {
// 1434096937358:Ver:1421765742287333878467:org.dartlang.dartplugin
return null;
} else if (opCode == InstrumentationService.TAG_WATCH_EVENT) {
// 1434097460414:Watch:/some/file/path
return null;
}
if (codesSeen.add(opCode)) {
logger.log(
Level.WARNING, 'Ignored instrumentation op code: $opCode\n $line');
}
return null;
}
Map<String, dynamic> decodeJson(String line, String text) {
try {
return asMap(json.decode(text));
} catch (e, s) {
throw new AnalysisException(
'Failed to decode JSON: $text\n$line', new CaughtException(e, s));
}
}
/**
* Determine if the given line is from an instrumentation file.
* For example:
* `1433175833005:Ver:1421765742287333878467:org.dartlang.dartplugin:0.0.0:1.6.2:1.11.0-edge.131698`
*/
static bool isFormat(String line) {
List<String> fields = _parseFields(line);
if (fields.length < 2) return false;
int timeStamp = int.tryParse(fields[0]) ?? -1;
String opCode = fields[1];
return timeStamp > 0 && opCode == 'Ver';
}
/**
* Extract fields from the given [line].
*/
static List<String> _parseFields(String line) {
List<String> fields = new List<String>();
int index = 0;
StringBuffer sb = new StringBuffer();
while (index < line.length) {
int code = line.codeUnitAt(index);
if (code == COLON) {
// Embedded colons are doubled
int next = index + 1;
if (next < line.length && line.codeUnitAt(next) == COLON) {
sb.write(':');
++index;
} else {
fields.add(sb.toString());
sb.clear();
}
} else {
sb.writeCharCode(code);
}
++index;
}
if (sb.isNotEmpty) {
fields.add(sb.toString());
}
return fields;
}
}