/** * erlyberly, erlang trace debugger * Copyright (C) 2016 Andy Till * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package erlyberly.node; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; import com.ericsson.otp.erlang.OtpErlangAtom; import com.ericsson.otp.erlang.OtpErlangList; import com.ericsson.otp.erlang.OtpErlangObject; import com.ericsson.otp.erlang.OtpErlangString; import com.ericsson.otp.erlang.OtpErlangTuple; import erlyberly.TraceLog; public class TraceManager { private static final OtpErlangAtom RETURN_FROM_ATOM = new OtpErlangAtom("return_from"); private static final OtpErlangAtom EXCEPTION_FROM_ATOM = new OtpErlangAtom("exception_from"); private static final OtpErlangAtom CALL_ATOM = new OtpErlangAtom("call"); private final HashMap<String, Stack<TraceLog>> unfinishedCalls = new HashMap<String, Stack<TraceLog>>(); public List<TraceLog> collateTraces(OtpErlangList traceLogs) { final ArrayList<TraceLog> traceList = new ArrayList<TraceLog>(); for (OtpErlangObject obj : traceLogs) { decodeTraceLog(obj, traceList); } return traceList; } public List<TraceLog> collateTraceSingle(OtpErlangTuple traceLog) { final ArrayList<TraceLog> traceList = new ArrayList<TraceLog>(); decodeTraceLog(traceLog, traceList); return traceList; } private void decodeTraceLog(OtpErlangObject otpErlangObject, ArrayList<TraceLog> traceList) { OtpErlangTuple tup = (OtpErlangTuple) otpErlangObject; OtpErlangAtom traceType = (OtpErlangAtom) tup.elementAt(0); if(CALL_ATOM.equals(traceType)) { TraceLog trace = proplistToTraceLog(tup); Stack<TraceLog> stack = unfinishedCalls.get(trace.getPidString()); if(stack == null) stack = new Stack<TraceLog>(); stack.add(trace); unfinishedCalls.put(trace.getPidString(), stack); traceList.add(trace); } else if(RETURN_FROM_ATOM.equals(traceType) || EXCEPTION_FROM_ATOM.equals(traceType)) { Map<Object, Object> map = propsFromTrace(tup); Object object = map.get(TraceLog.ATOM_PID); if(object != null) { OtpErlangString pidString = (OtpErlangString) object; Stack<TraceLog> stack = unfinishedCalls.get(pidString.stringValue()); if(stack == null) return; TraceLog traceLog = stack.pop(); traceLog.complete(map); if(stack.isEmpty()) unfinishedCalls.remove(pidString.stringValue()); } } } private TraceLog proplistToTraceLog(OtpErlangTuple tup) { Map<Object, Object> map = propsFromTrace(tup); TraceLog trace = new TraceLog(map); return trace; } private Map<Object, Object> propsFromTrace(OtpErlangTuple tup) { return OtpUtil.propsToMap((OtpErlangList) tup.elementAt(1)); } }