/* * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * vpasquier <vpasquier@nuxeo.com> * slacoin <slacoin@nuxeo.com> */ package org.nuxeo.ecm.automation.core.trace; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Calendar; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * @since 5.7.3 */ public class TracePrinter { private static final Log log = LogFactory.getLog(TracePrinter.class); private static final String LF = System.getProperty("line.separator"); protected final BufferedWriter writer; public TracePrinter(Writer writer) { this.writer = new BufferedWriter(writer); } public TracePrinter(OutputStream out) { this(new OutputStreamWriter(out)); } protected void printHeading(String heading) throws IOException { writer.append(LF+ LF + "****** " + heading + " ******"); } protected void printCalls(List<Call> calls) throws IOException { String tabs = "\t"; for (Call call : calls) { writer.append(tabs); writer.append(call.getType().getType().getName()); writer.append(LF); tabs += "\t"; } } public void print(Trace trace) throws IOException { printHeading("chain"); if (trace.error != null) { writer.append(LF); if (trace.getParent() != null) { writer.append("Parent Chain ID: "); writer.append(trace.getParent().getChainId()); writer.append(LF); } writer.append("Name: "); writer.append(trace.getChain().getId()); if (trace.getChain().getAliases() != null && trace.getChain().getAliases().length > 0) { writer.append(LF); writer.append("Aliases: "); writer.append(Arrays.toString(trace.getChain().getAliases())); } writer.append(LF); writer.append("Exception: "); writer.append(trace.error.getClass().getSimpleName()); writer.append(LF); writer.append("Caught error: "); writer.append(trace.error.getMessage()); writer.append(LF); writer.append("Caused by: "); writer.append(trace.error.toString()); } else { writer.append(LF); if (trace.getParent() != null) { writer.append("Parent Chain ID: "); writer.append(trace.getParent().getChainId()); writer.append(LF); } writer.append("Name: "); writer.append(trace.getChain().getId()); writer.append(LF); writer.append("Produced output type: "); writer.append(trace.output == null ? "Void" : trace.output.getClass().getSimpleName()); } writer.append(LF); writer.append("****** Hierarchy calls ******"); writer.append(LF); printCalls(trace.calls); print(trace.calls); writer.flush(); } public void print(List<Call> calls) throws IOException { for (Call call : calls) { print(call); } } public void print(Call call) throws IOException { printCall(call); } public void printCall(Call call) { try { writer.append(LF); writer.append(LF); writer.append("****** " + call.getType().getId() + " ******"); writer.append(LF); writer.append("Chain ID: "); writer.append(call.getChainId()); if (call.getAliases() != null) { writer.append(LF); writer.append("Chain Aliases: "); writer.append(call.getAliases()); } writer.append(LF); writer.append("Class: "); writer.append(call.getType().getType().getSimpleName()); writer.append(LF); writer.append("Method: '"); writer.append(call.getMethod().getMethod().getName()); writer.append("' | Input Type: "); writer.append(call.getMethod().getConsume().getName()); writer.append(" | Output Type: "); writer.append(call.getMethod().getProduce().getName()); writer.append(LF); writer.append("Input: "); writer.append(call.getInput() == null ? "null" : call.getInput().toString()); if (!call.getParameters().isEmpty()) { writer.append(LF); writer.append("Parameters "); for (String parameter : call.getParameters().keySet()) { writer.append(" | "); writer.append("Name: "); writer.append(parameter); writer.append(", Value: "); Object value = call.getParameters().get(parameter); if (value instanceof Call.ExpressionParameter) { value = String.format("Expr:(id=%s | value=%s)", ((Call.ExpressionParameter) call.getParameters().get(parameter)).getParameterId(), ((Call.ExpressionParameter) call.getParameters().get(parameter)).getParameterValue()); } writer.append(value.toString()); } } if (!call.getVariables().isEmpty()) { writer.append(LF); writer.append("Context Variables"); for (String keyVariable : call.getVariables().keySet()) { writer.append(" | "); writer.append("Key: "); writer.append(keyVariable); writer.append(", Value: "); Object variable = call.getVariables().get(keyVariable); if (variable instanceof Calendar) { writer.append(((Calendar) variable).getTime().toString()); } else { writer.append(variable == null ? "null" : variable.toString()); } } } if (!call.getNested().isEmpty()) { writer.append(LF); printHeading("start sub chain"); for (Trace trace : call.getNested()) { print(trace); } writer.append(LF); printHeading("end sub chain"); } } catch (IOException e) { log.error("Nuxeo TracePrinter cannot write traces output", e); } } public void litePrint(Trace trace) throws IOException { printHeading("chain"); writer.append(LF); if (trace.getParent() != null) { writer.append("Parent Chain ID: "); writer.append(trace.getParent().getChainId()); writer.append(LF); } writer.append("Name: "); writer.append(trace.getChain().getId()); if (trace.getChain().getAliases() != null && trace.getChain().getAliases().length > 0) { writer.append(LF); writer.append("Aliases: "); writer.append(Arrays.toString(trace.getChain().getAliases())); } if (trace.error != null) { writer.append(LF); writer.append("Exception: "); writer.append(trace.error.getClass().getSimpleName()); writer.append(LF); writer.append("Caught error: "); writer.append(trace.error.getMessage()); writer.append(LF); writer.append("Caused by: "); writer.append(trace.error.toString()); } writer.append(LF); writer.append("****** Hierarchy calls ******"); litePrintCall(trace.calls); writer.flush(); } public void litePrintCall(List<Call> calls) throws IOException { writer.append(LF); try { printCalls(calls); for (Call call : calls) { if (!call.getNested().isEmpty()) { writer.append(LF); printHeading("start sub chain"); for (Trace trace : call.getNested()) { litePrint(trace); } writer.append(LF); printHeading("end sub chain"); } } } catch (IOException e) { log.error("Nuxeo TracePrinter cannot write traces output", e); } } public static String print(Trace trace, boolean liteprint) { ByteArrayOutputStream out = new ByteArrayOutputStream(); TracePrinter printer = new TracePrinter(out); try { if (liteprint) { printer.litePrint(trace); } else { printer.print(trace); } } catch (IOException cause) { return "Cannot print automation trace of " + trace.chain.getId(); } return new String(out.toByteArray(), Charset.forName("UTF-8")); } }