Skip to content

Commit

Permalink
Highlight record and record field names in the process state.
Browse files Browse the repository at this point in the history
Make small tuples and lists display on one line.
  • Loading branch information
Andy Till committed May 17, 2015
1 parent 9d704d3 commit ac54b6a
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 26 deletions.
28 changes: 20 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,26 @@ Exceptions are highlighted.

A call that hasn't returned yet is highlighted in yellow.

##### Sequential Tracing of messages

Sequential Tracing ([seq_trace](http://www.erlang.org/doc/man/seq_trace.html)) is message tracing from process to process, allowing you to see the message flow through the application.

![you cannot see the beautiful screen shot](doc/seq-trace.png)

To start a seq trace right click on a function and select **Seq Trace (experimental)**, a Window will pop up that will display the trace messages. When the traced function is called, messages sent afterwards are shown in the window.

This functionality is experimental and highly likely to bork the remote node under test and erlyberly. Once a seq trace is set the only way to stop it is to terminate erlyberly or run `seq_trace:reset_trace()` in the shell of the remote node.

##### Get the process state

Get and display the state of a process.

![you cannot see the beautiful screen shot](doc/process-state.png)

This uses [sys:get_state/1](http://www.erlang.org/doc/man/sys.html#get_state-1) under the hood and so has the same limitations. Processes that do not support the system message may not respond.

If the value is a record that is compiled into the module of the processes initial call then the record name and field names will appear highlighted. Records that are not known by the module at compile time will not be highlighted.

##### Attach to any running system

erlyberly connects as an erlang node to the node you want to trace. Once connected it can trace your application code, 3rd party modules and modules that are part of the erlang standard libary.
Expand Down Expand Up @@ -73,14 +93,6 @@ Right click on a process in the process table and click on *"Get process state"*

Tested on Ubuntu and Windows 7/8. Also seen on [OS X](http://t.co/kzXppo5GEt).

##### Sequential Tracing of messages

Sequential Tracing (seq_trace) is tracing of messages from process to process to see the message flow through the application.

To start a seq trace right click on a function and select **Seq Trace (experimental)**, a Window will pop up that will crudely display the trace messages. When the traced function is called, messages sent afterwards are shown in the window.

This functionality is experimental and highly likely to bork the remote node under test and erlyberly. Once a seq trace is set the only way to stop it is to terminate erlyberly or run `seq_trace:reset_trace()` in the shell of the remote node.

### Shortcuts

| Keys | Action |
Expand Down
Binary file added doc/process-state.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/seq-trace.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 6 additions & 2 deletions src/main/java/erlyberly/ErlyBerly.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ public void start(Stage primaryStage) {
Scene scene;

scene = new Scene(rootView);
scene.getStylesheets().add(getClass().getResource("/floatyfield/floaty-field.css").toExternalForm());
scene.getStylesheets().add(getClass().getResource("/erlyberly/erlyberly.css").toString());
applyCssToWIndow(scene);

primaryStage.setScene(scene);
primaryStage.titleProperty().bind(nodeAPI.summaryProperty());
Expand All @@ -81,6 +80,11 @@ public void start(Stage primaryStage) {
displayConnectionPopup(primaryStage);
}

public static void applyCssToWIndow(Scene scene) {
scene.getStylesheets().add(ErlyBerly.class.getResource("/floatyfield/floaty-field.css").toExternalForm());
scene.getStylesheets().add(ErlyBerly.class.getResource("/erlyberly/erlyberly.css").toString());
}

private void setupProcPaneHiding(FxmlLoadable topBarFxml, FxmlLoadable dbgFxml) {
TopBarView topView;
DbgView dbgView;
Expand Down
1 change: 1 addition & 0 deletions src/main/java/erlyberly/ProcView.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ private void showProcessStateInWindow(ProcInfo procInfo, OtpErlangObject obj) {
termTreeView.populateFromTerm(obj);

Scene scene = new Scene(termTreeView);
ErlyBerly.applyCssToWIndow(scene);

CloseWindowOnEscape.apply(scene, termsStage);

Expand Down
63 changes: 47 additions & 16 deletions src/main/java/erlyberly/TermTreeView.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package erlyberly;

import javafx.scene.control.Label;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;

Expand Down Expand Up @@ -41,32 +42,49 @@ else if(obj instanceof OtpErlangTuple) {
TreeItem tupleItem;

if(isRecord(obj)) {
tupleItem = new TreeItem("#" + OtpUtil.tupleElement(1, obj) + " {");
String recordNameText = "#" + OtpUtil.tupleElement(1, obj) + " ";

tupleItem = new TreeItem("{");
tupleItem.setGraphic(recordLabel(recordNameText));
parent.getChildren().add(tupleItem);
tupleItem.setExpanded(true);

elements = OtpUtil.iterableElements(OtpUtil.tupleElement(2, obj));// ((OtpErlangList) OtpUtil.tupleElement(2, obj)).elements();
for (OtpErlangObject e : elements) {
addToTreeItem(tupleItem, e);
}
parent.getChildren().add(new TreeItem("}"));
}
else if(isRecordField(obj)) {
tupleItem = new TreeItem(OtpUtil.tupleElement(1, obj) + " = ");

tupleItem = new TreeItem(" ");
tupleItem.setGraphic(recordLabel(OtpUtil.tupleElement(1, obj) + " = "));
tupleItem.setExpanded(true);

parent.getChildren().add(tupleItem);
tupleItem.setExpanded(true);

addToTreeItem(tupleItem, OtpUtil.tupleElement(2, obj));
OtpErlangObject value = OtpUtil.tupleElement(2, obj);
if(OtpUtil.isLittleTerm(value))
tupleItem.setValue(value);
else
addToTreeItem(tupleItem, value);

}
else {
tupleItem = new TreeItem("{");
parent.getChildren().add(tupleItem);
tupleItem = new TreeItem();
tupleItem.setExpanded(true);
for (OtpErlangObject e : elements) {
addToTreeItem(tupleItem, e);

if(OtpUtil.isLittleTerm(obj)) {
tupleItem.setValue(obj);
}
parent.getChildren().add(new TreeItem("}"));
else {
tupleItem.setValue("{");
for (OtpErlangObject e : elements) {
addToTreeItem(tupleItem, e);
}
parent.getChildren().add(new TreeItem("}"));
}

parent.getChildren().add(tupleItem);
}
}
}
Expand All @@ -82,13 +100,19 @@ else if(obj instanceof OtpErlangList) {
listItem = new TreeItem("[");
listItem.setExpanded(true);

parent.getChildren().add(listItem);

for (OtpErlangObject e : elements) {
addToTreeItem(listItem, e);
}

if(OtpUtil.isLittleTerm(obj)) {
listItem.setValue(obj);
}
else {
listItem.setValue("[");
for (OtpErlangObject e : elements) {
addToTreeItem(listItem, e);
}
parent.getChildren().add(new TreeItem("]"));
}

parent.getChildren().add(new TreeItem("]"));
parent.getChildren().add(listItem);
}
}
else {
Expand All @@ -98,6 +122,13 @@ else if(obj instanceof OtpErlangList) {
}
}

private Label recordLabel(String recordNameText) {
Label label;
label = new Label(recordNameText);
label.getStyleClass().add("record-label");
return label;
}

private boolean isRecordField(OtpErlangObject obj) {
return OtpUtil.isTupleTagged(OtpUtil.atom("erlyberly_record_field"), obj);
}
Expand Down
48 changes: 48 additions & 0 deletions src/main/java/erlyberly/node/OtpUtil.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package erlyberly.node;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;

import com.ericsson.otp.erlang.OtpConn;
import com.ericsson.otp.erlang.OtpErlangAtom;
Expand All @@ -10,6 +12,7 @@
import com.ericsson.otp.erlang.OtpErlangExit;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangLong;
import com.ericsson.otp.erlang.OtpErlangMap;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangPid;
import com.ericsson.otp.erlang.OtpErlangString;
Expand Down Expand Up @@ -109,6 +112,9 @@ else if(obj instanceof OtpErlangTuple || obj instanceof OtpErlangList) {
}
sb.append(brackets.charAt(1));
}
else if(obj instanceof OtpErlangString) {
sb.append(obj.toString().replace("\n", "\\n"));
}
else {
sb.append(obj.toString());
}
Expand Down Expand Up @@ -252,4 +258,46 @@ else if(obj instanceof OtpErlangString) {
throw new RuntimeException("" + obj + " cannot return OtpErlangObject[]");

}

public static HashSet<Class<?>> LARGE_TERM_TYPES = new HashSet<Class<?>>(
Arrays.asList(OtpErlangList.class, OtpErlangTuple.class, OtpErlangMap.class)
);

/**
* A short term can be displayed on a single line and does not have to be
* broken down further.
*/
public static boolean isLittleTerm(OtpErlangObject obj) {
OtpErlangObject[] elements;

if(LARGE_TERM_TYPES.contains(obj.getClass())) {
elements = iterableElements(obj);
}
else {
return true;
}

// short lists and tuples which do not contain other short lists or
// tuples are ok
if(elements.length > 3)
return false;

for (OtpErlangObject e : elements) {
if(LARGE_TERM_TYPES.contains(e.getClass())) {
return false;
}
else if(e instanceof OtpErlangString) {
int stringLength = ((OtpErlangString) e).stringValue().length();
if(stringLength > 50)
return true;
}
else if(e instanceof OtpErlangBinary) {
int binaryLength = ((OtpErlangBinary) e).size();
if(binaryLength > 50)
return true;
}

}
return true;
}
}
6 changes: 6 additions & 0 deletions src/main/resources/erlyberly/erlyberly.css
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,10 @@

.menu-item:focused > .floaty-label .label {
-fx-text-fill: white;
}

.record-label {
-fx-background-color: #039ED3;
-fx-text-fill: white;
-fx-background-radius: 5;
}

0 comments on commit ac54b6a

Please sign in to comment.