001/* 002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * vpasquier <vpasquier@nuxeo.com> 018 * slacoin <slacoin@nuxeo.com> 019 */ 020package org.nuxeo.ecm.automation.core.trace; 021 022import java.io.BufferedWriter; 023import java.io.ByteArrayOutputStream; 024import java.io.IOException; 025import java.io.OutputStream; 026import java.io.OutputStreamWriter; 027import java.io.Writer; 028import java.nio.charset.Charset; 029import java.util.Arrays; 030import java.util.Calendar; 031import java.util.List; 032 033import org.apache.commons.logging.Log; 034import org.apache.commons.logging.LogFactory; 035 036/** 037 * @since 5.7.3 038 */ 039public class TracePrinter { 040 041 private static final Log log = LogFactory.getLog(TracePrinter.class); 042 043 private static final String LF = System.getProperty("line.separator"); 044 045 protected final BufferedWriter writer; 046 047 048 public TracePrinter(Writer writer) { 049 this.writer = new BufferedWriter(writer); 050 } 051 052 public TracePrinter(OutputStream out) { 053 this(new OutputStreamWriter(out)); 054 } 055 056 protected void printHeading(String heading) throws IOException { 057 writer.append(LF+ LF + "****** " + heading + " ******"); 058 } 059 060 protected void printCalls(List<Call> calls) throws IOException { 061 String tabs = "\t"; 062 for (Call call : calls) { 063 writer.append(tabs); 064 writer.append(call.getType().getType().getName()); 065 writer.append(LF); 066 tabs += "\t"; 067 } 068 } 069 070 public void print(Trace trace) throws IOException { 071 printHeading("chain"); 072 if (trace.error != null) { 073 writer.append(LF); 074 if (trace.getParent() != null) { 075 writer.append("Parent Chain ID: "); 076 writer.append(trace.getParent().getChainId()); 077 writer.append(LF); 078 } 079 writer.append("Name: "); 080 writer.append(trace.getChain().getId()); 081 if (trace.getChain().getAliases() != null && trace.getChain().getAliases().length > 0) { 082 writer.append(LF); 083 writer.append("Aliases: "); 084 writer.append(Arrays.toString(trace.getChain().getAliases())); 085 } 086 writer.append(LF); 087 writer.append("Exception: "); 088 writer.append(trace.error.getClass().getSimpleName()); 089 writer.append(LF); 090 writer.append("Caught error: "); 091 writer.append(trace.error.getMessage()); 092 writer.append(LF); 093 writer.append("Caused by: "); 094 writer.append(trace.error.toString()); 095 } else { 096 writer.append(LF); 097 if (trace.getParent() != null) { 098 writer.append("Parent Chain ID: "); 099 writer.append(trace.getParent().getChainId()); 100 writer.append(LF); 101 } 102 writer.append("Name: "); 103 writer.append(trace.getChain().getId()); 104 writer.append(LF); 105 writer.append("Produced output type: "); 106 writer.append(trace.output == null ? "Void" : trace.output.getClass().getSimpleName()); 107 } 108 writer.append(LF); 109 writer.append("****** Hierarchy calls ******"); 110 writer.append(LF); 111 printCalls(trace.calls); 112 print(trace.calls); 113 writer.flush(); 114 } 115 116 public void print(List<Call> calls) throws IOException { 117 for (Call call : calls) { 118 print(call); 119 } 120 } 121 122 public void print(Call call) throws IOException { 123 printCall(call); 124 } 125 126 public void printCall(Call call) { 127 try { 128 writer.append(LF); 129 writer.append(LF); 130 writer.append("****** " + call.getType().getId() + " ******"); 131 writer.append(LF); 132 writer.append("Chain ID: "); 133 writer.append(call.getChainId()); 134 if (call.getAliases() != null) { 135 writer.append(LF); 136 writer.append("Chain Aliases: "); 137 writer.append(call.getAliases()); 138 } 139 writer.append(LF); 140 writer.append("Class: "); 141 writer.append(call.getType().getType().getSimpleName()); 142 writer.append(LF); 143 writer.append("Method: '"); 144 writer.append(call.getMethod().getMethod().getName()); 145 writer.append("' | Input Type: "); 146 writer.append(call.getMethod().getConsume().getName()); 147 writer.append(" | Output Type: "); 148 writer.append(call.getMethod().getProduce().getName()); 149 writer.append(LF); 150 writer.append("Input: "); 151 writer.append(call.getInput() == null ? "null" : call.getInput().toString()); 152 if (!call.getParameters().isEmpty()) { 153 writer.append(LF); 154 writer.append("Parameters "); 155 for (String parameter : call.getParameters().keySet()) { 156 writer.append(" | "); 157 writer.append("Name: "); 158 writer.append(parameter); 159 writer.append(", Value: "); 160 Object value = call.getParameters().get(parameter); 161 if (value instanceof Call.ExpressionParameter) { 162 value = String.format("Expr:(id=%s | value=%s)", 163 ((Call.ExpressionParameter) call.getParameters().get(parameter)).getParameterId(), 164 ((Call.ExpressionParameter) call.getParameters().get(parameter)).getParameterValue()); 165 } 166 writer.append(value.toString()); 167 } 168 } 169 if (!call.getVariables().isEmpty()) { 170 writer.append(LF); 171 writer.append("Context Variables"); 172 for (String keyVariable : call.getVariables().keySet()) { 173 writer.append(" | "); 174 writer.append("Key: "); 175 writer.append(keyVariable); 176 writer.append(", Value: "); 177 Object variable = call.getVariables().get(keyVariable); 178 if (variable instanceof Calendar) { 179 writer.append(((Calendar) variable).getTime().toString()); 180 } else { 181 writer.append(variable == null ? "null" : variable.toString()); 182 } 183 } 184 } 185 if (!call.getNested().isEmpty()) { 186 writer.append(LF); 187 printHeading("start sub chain"); 188 for (Trace trace : call.getNested()) { 189 print(trace); 190 } 191 writer.append(LF); 192 printHeading("end sub chain"); 193 } 194 } catch (IOException e) { 195 log.error("Nuxeo TracePrinter cannot write traces output", e); 196 } 197 } 198 199 public void litePrint(Trace trace) throws IOException { 200 printHeading("chain"); 201 writer.append(LF); 202 if (trace.getParent() != null) { 203 writer.append("Parent Chain ID: "); 204 writer.append(trace.getParent().getChainId()); 205 writer.append(LF); 206 } 207 writer.append("Name: "); 208 writer.append(trace.getChain().getId()); 209 if (trace.getChain().getAliases() != null && trace.getChain().getAliases().length > 0) { 210 writer.append(LF); 211 writer.append("Aliases: "); 212 writer.append(Arrays.toString(trace.getChain().getAliases())); 213 } 214 if (trace.error != null) { 215 writer.append(LF); 216 writer.append("Exception: "); 217 writer.append(trace.error.getClass().getSimpleName()); 218 writer.append(LF); 219 writer.append("Caught error: "); 220 writer.append(trace.error.getMessage()); 221 writer.append(LF); 222 writer.append("Caused by: "); 223 writer.append(trace.error.toString()); 224 } 225 writer.append(LF); 226 writer.append("****** Hierarchy calls ******"); 227 litePrintCall(trace.calls); 228 writer.flush(); 229 } 230 231 public void litePrintCall(List<Call> calls) throws IOException { 232 writer.append(LF); 233 try { 234 printCalls(calls); 235 for (Call call : calls) { 236 if (!call.getNested().isEmpty()) { 237 writer.append(LF); 238 printHeading("start sub chain"); 239 for (Trace trace : call.getNested()) { 240 litePrint(trace); 241 } 242 writer.append(LF); 243 printHeading("end sub chain"); 244 } 245 } 246 } catch (IOException e) { 247 log.error("Nuxeo TracePrinter cannot write traces output", e); 248 } 249 } 250 251 public static String print(Trace trace, boolean liteprint) { 252 ByteArrayOutputStream out = new ByteArrayOutputStream(); 253 TracePrinter printer = new TracePrinter(out); 254 try { 255 if (liteprint) { 256 printer.litePrint(trace); 257 } else { 258 printer.print(trace); 259 } 260 } catch (IOException cause) { 261 return "Cannot print automation trace of " + trace.chain.getId(); 262 } 263 return new String(out.toByteArray(), Charset.forName("UTF-8")); 264 } 265 266}