package org.erlide.tracing.core.utils;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import org.erlide.tracing.core.Activator;
import org.erlide.tracing.core.Images;
import org.erlide.tracing.core.TraceType;
import org.erlide.tracing.core.mvc.model.treenodes.FunctionNode;
import org.erlide.tracing.core.mvc.model.treenodes.ITreeNode;
import org.erlide.tracing.core.mvc.model.treenodes.ModuleNode;
import org.erlide.tracing.core.mvc.model.treenodes.TracingResultsNode;
import org.erlide.tracing.core.mvc.model.treenodes.TreeNode;
import org.erlide.util.ErlLogger;
import com.ericsson.otp.erlang.OtpErlangAtom;
import com.ericsson.otp.erlang.OtpErlangInt;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangLong;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangPid;
import com.ericsson.otp.erlang.OtpErlangRangeException;
import com.ericsson.otp.erlang.OtpErlangString;
import com.ericsson.otp.erlang.OtpErlangTuple;
/**
* Handler which reads trace data.
*
* @author Piotr Dorobisz
*
*/
public class TraceDataHandler {
// atoms
private static final String ATOM_ERROR_LOADING = "error_loading";
private static final Object ATOM_FILE_INFO = "file_info";
private static final Object ATOM_DROP = "drop";
private static final String ATOM_STOP_TRACING = "stop_tracing";
private static final String ATOM_TRACE_TS = "trace_ts";
// trace tuple fields
private static final int INDEX_PROCESS = 1;
private static final int INDEX_PROCESS_PID = 0;
private static final int INDEX_PROCESS_INFO = 1;
private static final int INDEX_PROCESS_NODE = 2;
private static final int INDEX_TRACE_TYPE = 2;
private static final int INDEX_FUNCTION = 3;
private static final int INDEX_FUNCTION_MODULE = 0;
private static final int INDEX_FUNCTION_NAME = 1;
private static final int INDEX_FUNCTION_ARGS = 2;
private static final int INDEX_MESSAGE = 3;
private static final int INDEX_REGNAME = 3;
private static final int INDEX_REASON = 3;
private static final int INDEX_PROCESS2 = 3;
private static final int INDEX_INFO = 3;
private static final int INDEX_EXCEPTION = 4;
private static final int INDEX_EXCEPTION_CLASS = 0;
private static final int INDEX_EXCEPTION_VALUE = 1;
private static final int INDEX_TO = 4;
private static final int INDEX_RETURN_VALUE = 4;
private static final int INDEX_SPAWN_FUNCTION = 4;
// file info tuple fields
private static final int INDEX_INFO_START_DATE = 1;
private static final int INDEX_INFO_END_DATE = 2;
private static final int INDEX_INFO_PATH = 3;
private static final int INDEX_INFO_COUNT = 4;
private Date lastTraceDate;
private String lastProcessDescription;
private String lastFunctionDescription;
private final SimpleDateFormat infoDateFormatter = new SimpleDateFormat(
"dd.MM.yy HH:mm:ss");
private final SimpleDateFormat nodeDateFormatter = new SimpleDateFormat(
"HH:mm:ss.SSS dd.MM.yy");
/**
* Checks if given message is last one.
*
* @param message
* message
* @return <code>true</code> if it is last message, <code>false</code>
* otherwise
*/
public boolean isTracingFinished(final OtpErlangObject message) {
if (message instanceof OtpErlangAtom) {
final OtpErlangAtom atom = (OtpErlangAtom) message;
if (atom.atomValue().equals(ATOM_STOP_TRACING)) {
return true;
}
}
return false;
}
/**
* Reads error reason from message.
*
* @param message
* message
* @return error reason or <code>null</code> or if it is not an error
* message
*/
public OtpErlangObject getErrorReson(final OtpErlangObject message) {
if (message instanceof OtpErlangTuple) {
final OtpErlangTuple tuple = (OtpErlangTuple) message;
if (tuple.elementAt(0) instanceof OtpErlangAtom) {
final OtpErlangAtom atom = (OtpErlangAtom) tuple.elementAt(0);
if (atom.atomValue().equals(ATOM_ERROR_LOADING)) {
return tuple.elementAt(1);
}
}
}
return null;
}
/**
* Reads data described by given object. It can be trace event or
* information about file containing tracing results.
*
* @param otpErlangObject
* input object
*
* @return tree node that describes data
*/
public ITreeNode getData(final OtpErlangObject otpErlangObject) {
try {
if (otpErlangObject instanceof OtpErlangTuple) {
final OtpErlangTuple tuple = (OtpErlangTuple) otpErlangObject;
final String atomValue = ((OtpErlangAtom) tuple.elementAt(0)).atomValue();
if (atomValue.equals(ATOM_TRACE_TS)) {
// trace data: {trace_ts, Data}
final OtpErlangAtom traceType = (OtpErlangAtom) tuple
.elementAt(INDEX_TRACE_TYPE);
lastTraceDate = readDateTuple((OtpErlangTuple) tuple.elementAt(tuple
.arity() - 1));
switch (TraceType.valueOf(traceType.atomValue().toUpperCase())) {
case CALL:
return processCallTrace("Call", tuple);
case EXCEPTION_FROM:
return processExceptionFrom("Exception", tuple);
case EXIT:
return processExitTrace("Exit", tuple);
case GC_END:
return processGcTrace("GC end", Images.GC_END_NODE, tuple);
case GC_START:
return processGcTrace("GC start", Images.GC_START_NODE, tuple);
case GETTING_LINKED:
return processLinkTrace("Getting linked",
Images.GETTING_LINKED_NODE, tuple);
case GETTING_UNLINKED:
return processLinkTrace("Getting unlinked",
Images.GETTING_UNLINKED_NODE, tuple);
case IN:
return processInOutTrace("In", Images.IN_NODE, tuple);
case LINK:
return processLinkTrace("Link", Images.LINK_NODE, tuple);
case OUT:
return processInOutTrace("Out", Images.OUT_NODE, tuple);
case RECEIVE:
return processReceiveTrace("Received", tuple);
case REGISTER:
return processRegisterTrace("Register", Images.REGISTER_NODE,
tuple);
case RETURN_FROM:
return processReturnTrace("Return from", Images.RETURN_FROM_NODE,
tuple, true);
case RETURN_TO:
return processReturnTrace("Return to", Images.RETURN_TO_NODE,
tuple, false);
case SEND:
return processSendTrace("Sent", Images.SENT_MESSAGE_NODE, tuple);
case SEND_TO_NON_EXISTING_PROCESS:
return processSendTrace("Sent to non existing process",
Images.WRONG_MESSAGE_NODE, tuple);
case SPAWN:
return processSpawnTrace("Spawn", tuple);
case UNLINK:
return processLinkTrace("Unlink", Images.ULINK_NODE, tuple);
case UNREGISTER:
return processRegisterTrace("Unregister", Images.UNREGISTER_NODE,
tuple);
}
} else if (atomValue.equals(ATOM_FILE_INFO)) {
return processFileInfo(tuple);
} else if (atomValue.equals(ATOM_DROP)) {
// drop information: {drop, Long}
return processDropTrace(tuple);
}
}
} catch (final Exception e) {
ErlLogger.error(e);
}
return null;
}
/**
* Converts tuple representing date and time (<code>{date(), time()}</code>)
* to java {@link Date} object.
*
* @param tuple
* date tuple
* @return java date
* @throws OtpErlangRangeException
*/
private Date readDateTuple(final OtpErlangTuple tuple) throws OtpErlangRangeException {
final OtpErlangTuple dateTuple = (OtpErlangTuple) tuple.elementAt(0);
final OtpErlangTuple timeTuple = (OtpErlangTuple) tuple.elementAt(1);
final int year = ((OtpErlangLong) dateTuple.elementAt(0)).intValue();
final int month = ((OtpErlangLong) dateTuple.elementAt(1)).intValue() - 1;
final int day = ((OtpErlangLong) dateTuple.elementAt(2)).intValue();
final int hour = ((OtpErlangLong) timeTuple.elementAt(0)).intValue();
final int minute = ((OtpErlangLong) timeTuple.elementAt(1)).intValue();
final int second = ((OtpErlangLong) timeTuple.elementAt(2)).intValue();
final Calendar calendar = Calendar.getInstance();
calendar.set(year, month, day, hour, minute, second);
return calendar.getTime();
}
private String createNodeLabel(final String text) {
return "[" + nodeDateFormatter.format(lastTraceDate) + "] " + text;
}
private String pid2Str(final OtpErlangPid pid) {
return new StringBuilder().append(pid.id()).append(".").append(pid.serial())
.append(".").append(pid.creation()).toString();
}
// functions creating nodes
private ITreeNode processDropTrace(final OtpErlangTuple tuple) {
final OtpErlangLong amount = (OtpErlangLong) tuple.elementAt(1);
final ITreeNode node = new TreeNode("Dropped traces: " + amount.longValue(),
Activator.getImage(Images.DROP_NODE));
return node;
}
private ITreeNode processFileInfo(final OtpErlangTuple tuple) {
TracingResultsNode node = null;
if (tuple.elementAt(INDEX_INFO_START_DATE) instanceof OtpErlangAtom) {
// file contains no trace events
return null;
}
try {
final Date from = readDateTuple((OtpErlangTuple) tuple
.elementAt(INDEX_INFO_START_DATE));
final Date to = readDateTuple((OtpErlangTuple) tuple
.elementAt(INDEX_INFO_END_DATE));
final String path = ((OtpErlangString) tuple.elementAt(INDEX_INFO_PATH))
.stringValue();
final long size = ((OtpErlangLong) tuple.elementAt(INDEX_INFO_COUNT))
.longValue();
node = new TracingResultsNode();
node.setStartDate(from);
node.setEndDate(to);
node.setFileName(path);
node.setSize(size);
// node label
final StringBuilder builder = new StringBuilder();
builder.append(infoDateFormatter.format(from)).append(" - ")
.append(infoDateFormatter.format(to)).append(" (").append(size)
.append(" traces): ").append(path);
node.setLabel(builder.toString());
} catch (final OtpErlangRangeException e) {
ErlLogger.error(e);
}
return node;
}
private ITreeNode createProcessNode(final String label,
final OtpErlangObject erlangObject) {
final StringBuilder builder = new StringBuilder();
ITreeNode functionNode = null;
ITreeNode nameNode = null;
ITreeNode pidNode = null;
ITreeNode processNodeNode = null;
if (erlangObject instanceof OtpErlangTuple) {
// tuple: {Pid(), Initial_call()|Registered_name(), Node()} |
// {Registered_name, Node()}
final OtpErlangTuple processTuple = (OtpErlangTuple) erlangObject;
int index = 0;
// pid
OtpErlangPid pid = null;
if (processTuple.arity() == 3) {
// {Pid(), Initial_call()|Registered_name(), Node()}
pid = (OtpErlangPid) processTuple.elementAt(INDEX_PROCESS_PID);
pidNode = new TreeNode("pid: " + pid2Str(pid),
Activator.getImage(Images.INFO_NODE));
} else {
index = 1;// tuple doesn't contain Pid element
}
final OtpErlangObject info = processTuple.elementAt(INDEX_PROCESS_INFO
- index);
// process node
final OtpErlangObject processNode = processTuple.elementAt(INDEX_PROCESS_NODE
- index);
processNodeNode = new TreeNode("node: " + processNode,
Activator.getImage(Images.INFO_NODE));
if (info instanceof OtpErlangTuple) {
// initial call
functionNode = createFunctionNode("initial call:", info);
functionNode.setImage(Activator.getImage(Images.INFO_NODE));
if (pid != null) {
builder.append(pid2Str(pid));
} else {
builder.append(lastFunctionDescription);
}
} else {
// registered name
nameNode = new TreeNode("name: " + info,
Activator.getImage(Images.INFO_NODE));
builder.append(info.toString());
}
builder.append(" (").append(processNode).append(")");
} else if (erlangObject instanceof OtpErlangPid) {
// Pid
final OtpErlangPid pid = (OtpErlangPid) erlangObject;
pidNode = new TreeNode("pid: " + pid2Str(pid),
Activator.getImage(Images.INFO_NODE));
processNodeNode = new TreeNode("node: " + pid.node(),
Activator.getImage(Images.INFO_NODE));
builder.append(pid2Str(pid)).append(" (").append(pid.node()).append(")");
} else {
// Atom (registered name)
nameNode = new TreeNode("name: " + erlangObject,
Activator.getImage(Images.INFO_NODE));
builder.append(erlangObject.toString());
}
final ITreeNode node = new TreeNode();
if (pidNode != null) {
node.addChildren(pidNode);
}
if (nameNode != null) {
node.addChildren(nameNode);
}
if (processNodeNode != null) {
node.addChildren(processNodeNode);
}
if (functionNode != null) {
node.addChildren(functionNode);
}
lastProcessDescription = builder.toString();
node.setLabel(label + lastProcessDescription);
return node;
}
private ITreeNode createFunctionNode(final String label,
final OtpErlangObject erlangObject) {
final ITreeNode node = new TreeNode();
if (erlangObject instanceof OtpErlangTuple) {
final OtpErlangTuple functionTuple = (OtpErlangTuple) erlangObject;
final OtpErlangAtom moduleName = (OtpErlangAtom) functionTuple
.elementAt(INDEX_FUNCTION_MODULE);
final OtpErlangAtom functionName = (OtpErlangAtom) functionTuple
.elementAt(INDEX_FUNCTION_NAME);
// args or arity node
final TreeNode argsNode = new TreeNode();
argsNode.setImage(Activator.getImage(Images.INFO_NODE));
final OtpErlangObject arityOrArgs = functionTuple
.elementAt(INDEX_FUNCTION_ARGS);
int arityValue = -1;
if (arityOrArgs instanceof OtpErlangList) {
// last element is a list of arguments
final OtpErlangList arguments = (OtpErlangList) arityOrArgs;
final StringBuilder builder = new StringBuilder("arguments: ");
for (int i = 1; i < arguments.arity(); i++) {
builder.append(arguments.elementAt(i)).append(", ");
}
arityValue = arguments.arity() - 1;
argsNode.setLabel(builder.substring(0, builder.length() - 2));
} else {
// last element is arity
try {
if (functionTuple.elementAt(INDEX_FUNCTION_ARGS) instanceof OtpErlangInt) {
arityValue = ((OtpErlangInt) functionTuple
.elementAt(INDEX_FUNCTION_ARGS)).intValue();
} else {
arityValue = (int) ((OtpErlangLong) functionTuple
.elementAt(INDEX_FUNCTION_ARGS)).longValue();
}
argsNode.setLabel("arity: " + arityValue);
} catch (final OtpErlangRangeException e) {
ErlLogger.error(e);
}
}
// module name node
final TreeNode moduleNameNode = new ModuleNode(moduleName.atomValue());
moduleNameNode.setLabel("module: " + moduleName);
// function name node
final TreeNode functionNameNode = new FunctionNode(moduleName.atomValue(),
functionName.atomValue(), arityValue);
functionNameNode.setLabel("function: " + functionName);
node.addChildren(moduleNameNode, functionNameNode, argsNode);
lastFunctionDescription = label + moduleName + ":" + functionName + "/"
+ arityValue;
} else {
lastFunctionDescription = "unknown";
}
node.setLabel(lastFunctionDescription);
return node;
}
private ITreeNode createMessageNode(final OtpErlangObject message) {
final ITreeNode node = new TreeNode(message.toString(),
Activator.getImage(Images.MESSAGE_NODE));
return node;
}
// functions processing different trace types
private ITreeNode processGcTrace(final String label, final Images image,
final OtpErlangTuple tuple) {
final StringBuilder labelBuilder = new StringBuilder(label).append(": ");
final ITreeNode processNode = createProcessNode("process: ",
tuple.elementAt(INDEX_PROCESS));
processNode.setImage(Activator.getImage(Images.PROCESS_NODE));
labelBuilder.append(lastProcessDescription);
final ITreeNode node = new TreeNode(createNodeLabel(labelBuilder.toString()),
Activator.getImage(image));
node.addChildren(processNode);
final OtpErlangList list = (OtpErlangList) tuple.elementAt(INDEX_INFO);
for (final OtpErlangObject otpErlangObject : list) {
final OtpErlangTuple infoTuple = (OtpErlangTuple) otpErlangObject;
final OtpErlangObject key = infoTuple.elementAt(0);
final OtpErlangObject value = infoTuple.elementAt(1);
final TreeNode treeNode = new TreeNode(key.toString() + ": "
+ value.toString());
treeNode.setImage(Activator.getImage(Images.INFO_NODE));
node.addChildren(treeNode);
}
return node;
}
private ITreeNode processSpawnTrace(final String label, final OtpErlangTuple tuple) {
final StringBuilder labelBuilder = new StringBuilder(label).append(": ");
final ITreeNode processNode = createProcessNode("process: ",
tuple.elementAt(INDEX_PROCESS));
processNode.setImage(Activator.getImage(Images.PROCESS_NODE));
labelBuilder.append(lastProcessDescription).append("->");
final ITreeNode processNode2 = createProcessNode("new process: ",
tuple.elementAt(INDEX_PROCESS2));
processNode2.setImage(Activator.getImage(Images.NEW_PROCESS_NODE));
labelBuilder.append(lastProcessDescription);
final ITreeNode functionNode = createFunctionNode("function: ",
tuple.elementAt(INDEX_SPAWN_FUNCTION));
functionNode.setImage(Activator.getImage(Images.FUNCTION_NODE));
final ITreeNode node = new TreeNode(createNodeLabel(labelBuilder.toString()),
Activator.getImage(Images.SPAWN_NODE));
node.addChildren(processNode, processNode2, functionNode);
return node;
}
private ITreeNode processExceptionFrom(final String label, final OtpErlangTuple tuple) {
final StringBuilder labelBuilder = new StringBuilder(label).append(": ");
final ITreeNode processNode = createProcessNode("process: ",
tuple.elementAt(INDEX_PROCESS));
processNode.setImage(Activator.getImage(Images.PROCESS_NODE));
final OtpErlangTuple exceptionTuple = (OtpErlangTuple) tuple
.elementAt(INDEX_EXCEPTION);
final OtpErlangObject exceptionClass = exceptionTuple
.elementAt(INDEX_EXCEPTION_CLASS);
final OtpErlangObject exceptionValue = exceptionTuple
.elementAt(INDEX_EXCEPTION_VALUE);
labelBuilder.append(exceptionClass.toString());
final ITreeNode exceptionClassNode = new TreeNode(exceptionClass.toString(),
Activator.getImage(Images.INFO_NODE));
exceptionClassNode.addChildren(new TreeNode(exceptionValue.toString()));
final ITreeNode node = processReturnTrace(labelBuilder.toString(),
Images.EXCEPTION_NODE, tuple, false);
node.addChildren(processNode, exceptionClassNode);
return node;
}
private ITreeNode processReturnTrace(final String label, final Images image,
final OtpErlangTuple tuple, final boolean showRetValue) {
final StringBuilder labelBuilder = new StringBuilder(label).append(": ");
final ITreeNode processNode = createProcessNode("process: ",
tuple.elementAt(INDEX_PROCESS));
processNode.setImage(Activator.getImage(Images.PROCESS_NODE));
final ITreeNode functionNode = createFunctionNode("function: ",
tuple.elementAt(INDEX_FUNCTION));
functionNode.setImage(Activator.getImage(Images.FUNCTION_NODE));
labelBuilder.append(lastFunctionDescription);
final ITreeNode node = new TreeNode();
node.addChildren(processNode, functionNode);
if (showRetValue) {
final ITreeNode returnValueNode = new TreeNode("return value: "
+ tuple.elementAt(INDEX_RETURN_VALUE));
returnValueNode.setImage(Activator.getImage(Images.INFO_NODE));
labelBuilder.append("->").append(tuple.elementAt(INDEX_RETURN_VALUE));
node.addChildren(returnValueNode);
}
node.setLabel(createNodeLabel(labelBuilder.toString()));
node.setImage(Activator.getImage(image));
return node;
}
private ITreeNode processInOutTrace(final String label, final Images image,
final OtpErlangTuple tuple) {
final StringBuilder labelBuilder = new StringBuilder(label).append(": ");
final ITreeNode processNode = createProcessNode("process: ",
tuple.elementAt(INDEX_PROCESS));
processNode.setImage(Activator.getImage(Images.PROCESS_NODE));
labelBuilder.append(lastProcessDescription);
final ITreeNode functionNode = createFunctionNode("function: ",
tuple.elementAt(INDEX_FUNCTION));
functionNode.setImage(Activator.getImage(Images.FUNCTION_NODE));
final ITreeNode node = new TreeNode(createNodeLabel(labelBuilder.toString()),
Activator.getImage(image));
node.addChildren(processNode, functionNode);
return node;
}
private ITreeNode processRegisterTrace(final String label, final Images image,
final OtpErlangTuple tuple) {
final StringBuilder labelBuilder = new StringBuilder(label).append(": ");
final ITreeNode process = createProcessNode("process: ",
tuple.elementAt(INDEX_PROCESS));
process.setImage(Activator.getImage(Images.REGISTER_NODE));
labelBuilder.append(lastProcessDescription).append("->");
final TreeNode regName = new TreeNode("name: "
+ tuple.elementAt(INDEX_REGNAME).toString(),
Activator.getImage(Images.INFO_NODE));
labelBuilder.append(regName);
final ITreeNode node = new TreeNode(createNodeLabel(labelBuilder.toString()),
Activator.getImage(image));
node.addChildren(process, regName);
return node;
}
private ITreeNode processLinkTrace(final String label, final Images image,
final OtpErlangTuple tuple) {
final StringBuilder labelBuilder = new StringBuilder(label).append(": ");
final ITreeNode process1Node = createProcessNode("process 1: ",
tuple.elementAt(INDEX_PROCESS));
process1Node.setImage(Activator.getImage(Images.PROCESS_NODE));
labelBuilder.append(lastProcessDescription).append("->");
final ITreeNode process2Node = createProcessNode("process 2: ",
tuple.elementAt(INDEX_PROCESS2));
process2Node.setImage(Activator.getImage(Images.PROCESS_NODE));
labelBuilder.append(lastProcessDescription);
final TreeNode node = new TreeNode(createNodeLabel(labelBuilder.toString()));
node.setImage(Activator.getImage(image));
node.addChildren(process1Node, process2Node);
return node;
}
private ITreeNode processExitTrace(final String label, final OtpErlangTuple tuple) {
final StringBuilder labelBuilder = new StringBuilder(label).append(": ");
final ITreeNode processNode = createProcessNode("process: ",
tuple.elementAt(INDEX_PROCESS));
processNode.setImage(Activator.getImage(Images.PROCESS_NODE));
labelBuilder.append(lastProcessDescription);
final ITreeNode reasonNode = new TreeNode("reason: "
+ tuple.elementAt(INDEX_REASON).toString(),
Activator.getImage(Images.INFO_NODE));
final TreeNode node = new TreeNode(createNodeLabel(labelBuilder.toString()));
node.setImage(Activator.getDefault().getImageRegistry()
.get(Images.EXIT_NODE.toString()));
node.addChildren(processNode, reasonNode);
return node;
}
private ITreeNode processReceiveTrace(final String label, final OtpErlangTuple tuple) {
final StringBuilder labelBuilder = new StringBuilder(label).append(": ");
final ITreeNode processNode = createProcessNode("receiver: ",
tuple.elementAt(INDEX_PROCESS));
processNode.setImage(Activator.getImage(Images.RECEIVER_NODE));
labelBuilder.append(lastProcessDescription);
final ITreeNode messageNode = createMessageNode(tuple.elementAt(INDEX_MESSAGE));
final TreeNode node = new TreeNode(createNodeLabel(labelBuilder.toString()));
node.setImage(Activator.getDefault().getImageRegistry()
.get(Images.RECEIVED_MESSAGE_NODE.toString()));
node.addChildren(processNode, messageNode);
return node;
}
private ITreeNode processSendTrace(final String label, final Images image,
final OtpErlangTuple tuple) {
final StringBuilder labelBuilder = new StringBuilder(label).append(": ");
final ITreeNode senderNode = createProcessNode("sender: ",
tuple.elementAt(INDEX_PROCESS));
senderNode.setImage(Activator.getImage(Images.SENDER_NODE));
labelBuilder.append(lastProcessDescription).append("->");
final ITreeNode receiverNode = createProcessNode("receiver: ",
tuple.elementAt(INDEX_TO));
receiverNode.setImage(Activator.getImage(Images.RECEIVER_NODE));
labelBuilder.append(lastProcessDescription);
final ITreeNode messageNode = createMessageNode(tuple.elementAt(INDEX_MESSAGE));
final TreeNode node = new TreeNode(createNodeLabel(labelBuilder.toString()));
node.setImage(Activator.getImage(image));
node.addChildren(senderNode, receiverNode, messageNode);
return node;
}
private ITreeNode processCallTrace(final String label, final OtpErlangTuple tuple) {
final ITreeNode processNode = createProcessNode("process: ",
tuple.elementAt(INDEX_PROCESS));
processNode.setImage(Activator.getImage(Images.PROCESS_NODE));
final ITreeNode node = createFunctionNode(createNodeLabel(label + ": "),
tuple.elementAt(INDEX_FUNCTION));
node.setImage(Activator.getImage(Images.CALL_NODE));
node.addChildren(processNode);
return node;
}
}