Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

☠️ WIP ☠️ Show traces in a call hierarchy #65

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
11 changes: 10 additions & 1 deletion src/main/java/erlyberly/CrashReport.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,16 @@ public CrashReport(OtpErlangObject obj) {
}

<T> List<T> mapStackTraces(StackTraceFn<T> fn) {
OtpErlangList stackTrace = (OtpErlangList) errorInfo.elementAt(2);
OtpErlangList stackTrace = null;
if(errorInfo.elementAt(0).equals(OtpUtil.atom("exit"))) {
OtpErlangTuple exitInfo = (OtpErlangTuple)errorInfo.elementAt(1);
if(exitInfo.elementAt(1) instanceof OtpErlangList) {
stackTrace = (OtpErlangList)exitInfo.elementAt(1);
}
}
if(stackTrace == null) {
stackTrace = (OtpErlangList) errorInfo.elementAt(2);
}
ArrayList<T> result = new ArrayList<T>();

for (OtpErlangObject obj : stackTrace) {
Expand Down
27 changes: 17 additions & 10 deletions src/main/java/erlyberly/DbgController.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,24 @@
import java.util.ArrayList;
import java.util.ResourceBundle;

import com.ericsson.otp.erlang.OtpErlangException;
import com.ericsson.otp.erlang.OtpErlangList;

import erlyberly.node.NodeAPI;
import erlyberly.node.NodeAPI.RpcCallback;
import erlyberly.node.TraceManager;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.Initializable;

import com.ericsson.otp.erlang.OtpErlangException;
import com.ericsson.otp.erlang.OtpErlangList;

import erlyberly.node.NodeAPI;
import erlyberly.node.NodeAPI.RpcCallback;
import javafx.scene.control.TreeItem;


public class DbgController implements Initializable {

public final ObservableList<TraceLog> traceLogs = FXCollections.observableArrayList();
public final ObservableList<TreeItem<TraceLog>> traceLogs = FXCollections.observableArrayList();

private final ObservableList<ModFunc> traces = FXCollections.observableArrayList();

Expand All @@ -31,6 +32,8 @@ public class DbgController implements Initializable {

private volatile boolean collectingSeqTraces;

private final TraceManager traceManager = new TraceManager();

public void setCollectingTraces(boolean collecting) {
collectingTraces = collecting;
}
Expand All @@ -41,7 +44,7 @@ public void initialize(URL url, ResourceBundle r) {
new SeqTraceCollectorThread((seqs) -> { seqTraces.addAll(seqs); }).start();
}

public ObservableList<TraceLog> getTraceLogs() {
public ObservableList<TreeItem<TraceLog>> getTraceLogs() {
return traceLogs;
}

Expand Down Expand Up @@ -139,9 +142,13 @@ public void run() {
while (true) {
if(collectingTraces && ErlyBerly.nodeAPI().isConnected()) {
try {
final ArrayList<TraceLog> collectTraceLogs = ErlyBerly.nodeAPI().collectTraceLogs();
OtpErlangList collectTraceLogs = ErlyBerly.nodeAPI().collectTraceLogs();

Platform.runLater(() -> { traceLogs.addAll(collectTraceLogs); });
Platform.runLater(() -> {
final ArrayList<TreeItem<TraceLog>> resultList = new ArrayList<>();
traceManager.collateTraces(collectTraceLogs, resultList);
traceLogs.addAll(resultList);
});
} catch (Exception e) {
e.printStackTrace();
}
Expand Down
112 changes: 55 additions & 57 deletions src/main/java/erlyberly/DbgTraceView.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.WeakChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
import javafx.scene.Node;
Expand All @@ -20,42 +16,43 @@
import javafx.scene.control.Label;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableRow;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import ui.TreeItemSF;


public class DbgTraceView extends VBox {

private final ObservableList<TraceLog> traceLogs = FXCollections.observableArrayList();

private final SortedList<TraceLog> sortedTtraces = new SortedList<TraceLog>(traceLogs);

private final FilteredList<TraceLog> filteredTraces = new FilteredList<TraceLog>(sortedTtraces);

private final TableView<TraceLog> tracesBox;
private final TreeTableView<TraceLog> tracesBox;

/**
* Set insertTracesAtTop=true in the .erlyberly file in your home directory to
* make traces be inserted at the top of the list.
*/
private boolean insertTracesAtTop;

private TreeItemSF<TraceLog> rootItem = new TreeItemSF<>();

public DbgTraceView(DbgController dbgController) {
setSpacing(5d);
setStyle("-fx-background-insets: 5;");
setMaxHeight(Double.MAX_VALUE);

insertTracesAtTop = PrefBind.getOrDefault("insertTracesAtTop", "false").equals("true");

tracesBox = new TableView<TraceLog>();
tracesBox = new TreeTableView<TraceLog>();
tracesBox.setShowRoot(false);
tracesBox.setRoot(rootItem);
tracesBox.setOnMouseClicked(this::onTraceClicked);
tracesBox.setMaxHeight(Double.MAX_VALUE);
VBox.setVgrow(tracesBox, Priority.ALWAYS);
Expand All @@ -66,9 +63,9 @@ public DbgTraceView(DbgController dbgController) {
// the table cannot be sorted on columns. Binding the items will throw exceptions
// when sorting on columns.
// see http://code.makery.ch/blog/javafx-8-tableview-sorting-filtering/
SortedList<TraceLog> sortedData = new SortedList<>(filteredTraces);
sortedData.comparatorProperty().bind(tracesBox.comparatorProperty());
tracesBox.setItems(sortedData);
//SortedList<TraceLog> sortedData = new SortedList<>(filteredTraces);
//ReadOnlyObjectProperty<Comparator<TreeItem<TraceLog>>> comparator = tracesBox.comparatorProperty();
//sortedData.comparatorProperty().bind(comparator);

putTraceContextMenu();

Expand All @@ -81,43 +78,43 @@ public DbgTraceView(DbgController dbgController) {

@SuppressWarnings({ "unchecked", "rawtypes" })
private void putTableColumns() {
TableColumn<TraceLog,Long> seqColumn;
seqColumn = new TableColumn<TraceLog,Long>("Seq.");
seqColumn.setCellValueFactory(new PropertyValueFactory("instanceNum"));
TreeTableColumn<TraceLog,Long> seqColumn;
seqColumn = new TreeTableColumn<TraceLog,Long>("Seq.");
seqColumn.setCellValueFactory(new TreeItemPropertyValueFactory("instanceNum"));

TableColumn<TraceLog,String> pidColumn;
pidColumn = new TableColumn<TraceLog,String>("Pid");
pidColumn.setCellValueFactory(new PropertyValueFactory("pid"));
TreeTableColumn<TraceLog,String> pidColumn;
pidColumn = new TreeTableColumn<TraceLog,String>("Pid");
pidColumn.setCellValueFactory(new TreeItemPropertyValueFactory("pid"));

TableColumn<TraceLog,String> regNameColumn;
regNameColumn = new TableColumn<TraceLog,String>("Reg. Name");
regNameColumn.setCellValueFactory(new PropertyValueFactory("regName"));
TreeTableColumn<TraceLog,String> regNameColumn;
regNameColumn = new TreeTableColumn<TraceLog,String>("Reg. Name");
regNameColumn.setCellValueFactory(new TreeItemPropertyValueFactory("regName"));

TableColumn<TraceLog,String> durationNameColumn;
durationNameColumn = new TableColumn<TraceLog,String>("Duration");
durationNameColumn.setCellValueFactory(new PropertyValueFactory("duration"));
TreeTableColumn<TraceLog,String> durationNameColumn;
durationNameColumn = new TreeTableColumn<TraceLog,String>("Duration");
durationNameColumn.setCellValueFactory(new TreeItemPropertyValueFactory("duration"));

TableColumn<TraceLog,String> functionnNameColumn;
functionnNameColumn = new TableColumn<TraceLog,String>("Function");
functionnNameColumn.setCellValueFactory(new PropertyValueFactory("function"));
TreeTableColumn<TraceLog,String> functionnNameColumn;
functionnNameColumn = new TreeTableColumn<TraceLog,String>("Function");
functionnNameColumn.setCellValueFactory(new TreeItemPropertyValueFactory("function"));

TableColumn<TraceLog,String> argsColumn;
argsColumn = new TableColumn<TraceLog,String>("Args");
argsColumn.setCellValueFactory(new PropertyValueFactory("args"));
TreeTableColumn<TraceLog,String> argsColumn;
argsColumn = new TreeTableColumn<TraceLog,String>("Args");
argsColumn.setCellValueFactory(new TreeItemPropertyValueFactory("args"));

TableColumn<TraceLog,String> resultColumn;
resultColumn = new TableColumn<TraceLog,String>("Result");
resultColumn.setCellValueFactory(new PropertyValueFactory("result"));
TreeTableColumn<TraceLog,String> resultColumn;
resultColumn = new TreeTableColumn<TraceLog,String>("Result");
resultColumn.setCellValueFactory(new TreeItemPropertyValueFactory("result"));

tracesBox.getColumns().setAll(
seqColumn, pidColumn, regNameColumn, durationNameColumn, functionnNameColumn, argsColumn, resultColumn
functionnNameColumn, seqColumn, pidColumn, regNameColumn, durationNameColumn, argsColumn, resultColumn
);

// based on http://stackoverflow.com/questions/27015961/tableview-row-style
PseudoClass exceptionClass = PseudoClass.getPseudoClass("exception");
PseudoClass notCompletedClass = PseudoClass.getPseudoClass("not-completed");
tracesBox.setRowFactory(tv -> {
TableRow<TraceLog> row = new TableRow<>();
TreeTableRow<TraceLog> row = new TreeTableRow<>();
row.itemProperty().addListener((obs, oldTl, tl) -> {
if (tl != null) {
row.pseudoClassStateChanged(exceptionClass, tl.isExceptionThrower());
Expand All @@ -132,7 +129,7 @@ private void putTableColumns() {
});

tracesBox.setRowFactory(tv -> {
TableRow<TraceLog> row = new TableRow<>();
TreeTableRow<TraceLog> row = new TreeTableRow<>();
ChangeListener<Boolean> completeListener = (obs, oldComplete, newComplete) -> {
row.pseudoClassStateChanged(exceptionClass, row.getItem().isExceptionThrower());
row.pseudoClassStateChanged(notCompletedClass, !row.getItem().isComplete());
Expand All @@ -157,7 +154,7 @@ private void putTableColumns() {

private void putTraceContextMenu() {
TraceContextMenu traceContextMenu = new TraceContextMenu();
traceContextMenu.setItems(traceLogs);
traceContextMenu.setItems(rootItem.getInputItems());
traceContextMenu
.setSelectedItems(tracesBox.getSelectionModel().getSelectedItems());

Expand All @@ -167,10 +164,10 @@ private void putTraceContextMenu() {

private void onTraceClicked(MouseEvent me) {
if(me.getButton().equals(MouseButton.PRIMARY) && me.getClickCount() == 2) {
TraceLog selectedItem = tracesBox.getSelectionModel().getSelectedItem();
TreeItem<TraceLog> selectedItem = tracesBox.getSelectionModel().getSelectedItem();

if(selectedItem != null && selectedItem != null) {
showTraceTermView(selectedItem);
if(selectedItem != null && selectedItem.getValue() != null) {
showTraceTermView(selectedItem.getValue());
}
}
}
Expand Down Expand Up @@ -230,11 +227,11 @@ private Node labelledTreeView(String label, TermTreeView node) {
}

private void onTraceFilterChange(String searchText) {
BasicSearch basicSearch = new BasicSearch(searchText);
filteredTraces.setPredicate((t) -> {
String logText = t.toString();
return basicSearch.matches(logText);
});
//BasicSearch basicSearch = new BasicSearch(searchText);
//filteredTraces.setPredicate((t) -> {
// String logText = t.toString();
// return basicSearch.matches(logText);
//});
}

private Region traceLogFloatySearchControl() {
Expand All @@ -260,13 +257,14 @@ private Region traceLogFloatySearchControl() {
return fxmlNode;
}

public void traceLogsChanged(ListChangeListener.Change<? extends TraceLog> e) {
public void traceLogsChanged(ListChangeListener.Change<? extends TreeItem<TraceLog>> e) {
while(e.next()) {
for (TraceLog trace : e.getAddedSubList()) {
if(insertTracesAtTop)
traceLogs.add(0, trace);
for (TreeItem<TraceLog> trace : e.getAddedSubList()) {
TreeItemSF<TraceLog> traceRoot = (TreeItemSF<TraceLog>) tracesBox.getRoot();
if(insertTracesAtTop)
traceRoot.getInputItems().add(0, trace);
else
traceLogs.add(trace);
traceRoot.getInputItems().add(trace);
}
}
}
Expand Down
Loading