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.IOException; 024import java.io.OutputStream; 025import java.io.OutputStreamWriter; 026import java.io.Writer; 027import java.util.Arrays; 028import java.util.Calendar; 029import java.util.List; 030 031import org.apache.commons.logging.Log; 032import org.apache.commons.logging.LogFactory; 033 034/** 035 * @since 5.7.3 036 */ 037public class TracePrinter { 038 039 private static final Log log = LogFactory.getLog(TracePrinter.class); 040 041 protected final BufferedWriter writer; 042 043 protected String preamble = ""; 044 045 public TracePrinter(Writer writer) { 046 this.writer = new BufferedWriter(writer); 047 } 048 049 public TracePrinter(OutputStream out) { 050 this(new OutputStreamWriter(out)); 051 } 052 053 protected void printLine(String line) throws IOException { 054 writer.write(preamble + line); 055 } 056 057 protected void printHeading(String heading) throws IOException { 058 printLine(System.getProperty("line.separator") + System.getProperty("line.separator") + "****** " + heading 059 + " ******"); 060 } 061 062 public void print(Trace trace) throws IOException { 063 StringBuilder sb = new StringBuilder(); 064 printHeading("chain"); 065 if (trace.error != null) { 066 sb.append(System.getProperty("line.separator")); 067 if (trace.getParent() != null) { 068 sb.append("Parent Chain ID: "); 069 sb.append(trace.getParent().getChainId()); 070 sb.append(System.getProperty("line.separator")); 071 } 072 sb.append("Name: "); 073 sb.append(trace.getChain().getId()); 074 if (trace.getChain().getAliases() != null && trace.getChain().getAliases().length > 0) { 075 sb.append(System.getProperty("line.separator")); 076 sb.append("Aliases: "); 077 sb.append(Arrays.toString(trace.getChain().getAliases())); 078 } 079 sb.append(System.getProperty("line.separator")); 080 sb.append("Exception: "); 081 sb.append(trace.error.getClass().getSimpleName()); 082 sb.append(System.getProperty("line.separator")); 083 sb.append("Caught error: "); 084 sb.append(trace.error.getMessage()); 085 sb.append(System.getProperty("line.separator")); 086 sb.append("Caused by: "); 087 sb.append(trace.error.getCause()); 088 printLine(sb.toString()); 089 } else { 090 sb.append(System.getProperty("line.separator")); 091 if (trace.getParent() != null) { 092 sb.append("Parent Chain ID: "); 093 sb.append(trace.getParent().getChainId()); 094 sb.append(System.getProperty("line.separator")); 095 } 096 sb.append("Name: "); 097 sb.append(trace.getChain().getId()); 098 sb.append(System.getProperty("line.separator")); 099 sb.append("Produced output type: "); 100 sb.append(trace.output == null ? "Void" : trace.output.getClass().getSimpleName()); 101 printLine(sb.toString()); 102 } 103 StringBuilder stringBuilder = new StringBuilder(); 104 stringBuilder.append(System.getProperty("line.separator")); 105 stringBuilder.append("****** Hierarchy calls ******"); 106 stringBuilder.append(System.getProperty("line.separator")); 107 displayOperationTreeCalls(trace.operations, stringBuilder); 108 printLine(stringBuilder.toString()); 109 print(trace.operations); 110 writer.flush(); 111 } 112 113 public void print(List<Call> calls) throws IOException { 114 for (Call call : calls) { 115 print(call); 116 } 117 } 118 119 public void print(Call call) throws IOException { 120 printCall(call); 121 } 122 123 public void printCall(Call call) { 124 try { 125 StringBuilder sb = new StringBuilder(); 126 sb.append(System.getProperty("line.separator")); 127 sb.append(System.getProperty("line.separator")); 128 sb.append("****** " + call.getType().getId() + " ******"); 129 sb.append(System.getProperty("line.separator")); 130 sb.append("Chain ID: "); 131 sb.append(call.getChainId()); 132 if (call.getAliases() != null) { 133 sb.append(System.getProperty("line.separator")); 134 sb.append("Chain Aliases: "); 135 sb.append(call.getAliases()); 136 } 137 sb.append(System.getProperty("line.separator")); 138 sb.append("Class: "); 139 sb.append(call.getType().getType().getSimpleName()); 140 sb.append(System.getProperty("line.separator")); 141 sb.append("Method: '"); 142 sb.append(call.getMethod().getMethod().getName()); 143 sb.append("' | Input Type: "); 144 sb.append(call.getMethod().getConsume()); 145 sb.append(" | Output Type: "); 146 sb.append(call.getMethod().getProduce()); 147 sb.append(System.getProperty("line.separator")); 148 sb.append("Input: "); 149 sb.append(call.getInput()); 150 if (!call.getParmeters().isEmpty()) { 151 sb.append(System.getProperty("line.separator")); 152 sb.append("Parameters "); 153 for (String parameter : call.getParmeters().keySet()) { 154 sb.append(" | "); 155 sb.append("Name: "); 156 sb.append(parameter); 157 sb.append(", Value: "); 158 Object value = call.getParmeters().get(parameter); 159 if (value instanceof Call.ExpressionParameter) { 160 value = String.format("Expr:(id=%s | value=%s)", 161 ((Call.ExpressionParameter) call.getParmeters().get(parameter)).getParameterId(), 162 ((Call.ExpressionParameter) call.getParmeters().get(parameter)).getParameterValue()); 163 } 164 sb.append(value); 165 } 166 } 167 if (!call.getVariables().isEmpty()) { 168 sb.append(System.getProperty("line.separator")); 169 sb.append("Context Variables"); 170 for (String keyVariable : call.getVariables().keySet()) { 171 sb.append(" | "); 172 sb.append("Key: "); 173 sb.append(keyVariable); 174 sb.append(", Value: "); 175 Object variable = call.getVariables().get(keyVariable); 176 if (variable instanceof Calendar) { 177 sb.append(((Calendar) variable).getTime()); 178 } else { 179 sb.append(variable); 180 } 181 } 182 } 183 printLine(sb.toString()); 184 sb = new StringBuilder(); 185 if (!call.getNested().isEmpty()) { 186 sb.append(System.getProperty("line.separator")); 187 printHeading("start sub chain"); 188 for (Trace trace : call.getNested()) { 189 print(trace); 190 } 191 sb.append(System.getProperty("line.separator")); 192 printHeading("end sub chain"); 193 } 194 printLine(sb.toString()); 195 } catch (IOException e) { 196 log.error("Nuxeo TracePrinter cannot write traces output", e); 197 } 198 } 199 200 public void litePrint(Trace trace) throws IOException { 201 StringBuilder sb = new StringBuilder(); 202 printHeading("chain"); 203 if (trace.error != null) { 204 sb.append(System.getProperty("line.separator")); 205 if (trace.getParent() != null) { 206 sb.append("Parent Chain ID: "); 207 sb.append(trace.getParent().getChainId()); 208 sb.append(System.getProperty("line.separator")); 209 } 210 sb.append("Name: "); 211 sb.append(trace.getChain().getId()); 212 if (trace.getChain().getAliases() != null && trace.getChain().getAliases().length > 0) { 213 sb.append(System.getProperty("line.separator")); 214 sb.append("Aliases: "); 215 sb.append(Arrays.toString(trace.getChain().getAliases())); 216 } 217 sb.append(System.getProperty("line.separator")); 218 sb.append("Exception: "); 219 sb.append(trace.error.getClass().getSimpleName()); 220 sb.append(System.getProperty("line.separator")); 221 sb.append("Caught error: "); 222 sb.append(trace.error.getMessage()); 223 sb.append(System.getProperty("line.separator")); 224 sb.append("Caused by: "); 225 sb.append(trace.error.getCause()); 226 } 227 sb.append(System.getProperty("line.separator")); 228 sb.append("****** Hierarchy calls ******"); 229 printLine(sb.toString()); 230 litePrintCall(trace.operations); 231 writer.flush(); 232 } 233 234 public void litePrintCall(List<Call> calls) throws IOException { 235 StringBuilder stringBuilder = new StringBuilder(); 236 stringBuilder.append(System.getProperty("line.separator")); 237 try { 238 displayOperationTreeCalls(calls, stringBuilder); 239 printLine(stringBuilder.toString()); 240 stringBuilder = new StringBuilder(); 241 for (Call call : calls) { 242 if (!call.getNested().isEmpty()) { 243 stringBuilder.append(System.getProperty("line.separator")); 244 printHeading("start sub chain"); 245 for (Trace trace : call.getNested()) { 246 litePrint(trace); 247 } 248 stringBuilder.append(System.getProperty("line.separator")); 249 printHeading("end sub chain"); 250 } 251 } 252 printLine(stringBuilder.toString()); 253 } catch (IOException e) { 254 log.error("Nuxeo TracePrinter cannot write traces output", e); 255 } 256 } 257 258 private void displayOperationTreeCalls(List<Call> calls, StringBuilder stringBuilder) { 259 String tabs = "\t"; 260 for (Call call : calls) { 261 stringBuilder.append(tabs); 262 stringBuilder.append(call.getType().getType().getName()); 263 stringBuilder.append(System.getProperty("line.separator")); 264 tabs += "\t"; 265 } 266 } 267 268}