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 <[email protected]> 018 * slacoin <[email protected]> 019 */ 020package org.nuxeo.ecm.automation.core.trace; 021 022import static org.nuxeo.ecm.automation.core.Constants.LF; 023 024import java.io.BufferedWriter; 025import java.io.ByteArrayOutputStream; 026import java.io.IOException; 027import java.io.OutputStreamWriter; 028import java.nio.charset.Charset; 029import java.util.ArrayList; 030import java.util.Arrays; 031import java.util.List; 032 033import org.apache.commons.logging.Log; 034import org.apache.commons.logging.LogFactory; 035import org.nuxeo.ecm.automation.OperationException; 036import org.nuxeo.ecm.automation.OperationType; 037 038/** 039 * @since 5.7.3 040 */ 041public class Trace { 042 043 private static final Log log = LogFactory.getLog(TracerFactory.class); 044 045 protected final Call parent; 046 047 protected final OperationType chain; 048 049 protected final List<Call> calls; 050 051 protected final Object input; 052 053 protected final Object output; 054 055 protected final OperationException error; 056 057 protected Trace(Call parent, OperationType chain, List<Call> calls, Object input, Object output, 058 OperationException error) { 059 this.parent = parent; 060 this.chain = chain; 061 this.calls = new ArrayList<>(calls); 062 this.input = input; 063 this.output = output; 064 this.error = error; 065 } 066 067 public Call getParent() { 068 return parent; 069 } 070 071 public OperationType getChain() { 072 return chain; 073 } 074 075 public OperationException getError() { 076 return error; 077 } 078 079 public Object getInput() { 080 return input; 081 } 082 083 public Object getOutput() { 084 return output; 085 } 086 087 public List<Call> getCalls() { 088 return calls; 089 } 090 091 @Override 092 public String toString() { 093 return print(true); 094 } 095 096 protected void printHeading(String heading, BufferedWriter writer) throws IOException { 097 writer.append(LF + LF + "****** " + heading + " ******"); 098 } 099 100 protected void litePrint(BufferedWriter writer) throws IOException { 101 printHeading("chain", writer); 102 writer.append(LF); 103 if (getParent() != null) { 104 writer.append("Parent Chain ID: "); 105 writer.append(getParent().getChainId()); 106 writer.append(LF); 107 } 108 writer.append("Name: "); 109 writer.append(getChain().getId()); 110 if (getChain().getAliases() != null && getChain().getAliases().length > 0) { 111 writer.append(LF); 112 writer.append("Aliases: "); 113 writer.append(Arrays.toString(getChain().getAliases())); 114 } 115 if (error != null) { 116 writer.append(LF); 117 writer.append("Exception: "); 118 writer.append(error.getClass().getSimpleName()); 119 writer.append(LF); 120 writer.append("Caught error: "); 121 writer.append(error.getMessage()); 122 writer.append(LF); 123 writer.append("Caused by: "); 124 writer.append(error.toString()); 125 } 126 writer.append(LF); 127 writer.append("****** Hierarchy calls ******"); 128 litePrintCall(calls, writer); 129 writer.flush(); 130 } 131 132 protected void litePrintCall(List<Call> calls, BufferedWriter writer) throws IOException { 133 writer.append(LF); 134 try { 135 printCalls(calls, writer); 136 for (Call call : calls) { 137 if (!call.getNested().isEmpty()) { 138 writer.append(LF); 139 printHeading("start sub chain", writer); 140 for (Trace trace : call.getNested()) { 141 trace.litePrint(writer); 142 } 143 writer.append(LF); 144 printHeading("end sub chain", writer); 145 } 146 } 147 } catch (IOException e) { 148 log.error("Nuxeo TracePrinter cannot write traces output", e); 149 } 150 } 151 152 protected void print(BufferedWriter writer) throws IOException { 153 printHeading("chain", writer); 154 if (error != null) { 155 writer.append(LF); 156 if (getParent() != null) { 157 writer.append("Parent Chain ID: "); 158 writer.append(getParent().getChainId()); 159 writer.append(LF); 160 } 161 writer.append("Name: "); 162 writer.append(getChain().getId()); 163 if (getChain().getAliases() != null && getChain().getAliases().length > 0) { 164 writer.append(LF); 165 writer.append("Aliases: "); 166 writer.append(Arrays.toString(getChain().getAliases())); 167 } 168 writer.append(LF); 169 writer.append("Exception: "); 170 writer.append(error.getClass().getSimpleName()); 171 writer.append(LF); 172 writer.append("Caught error: "); 173 writer.append(error.getMessage()); 174 writer.append(LF); 175 writer.append("Caused by: "); 176 writer.append(error.toString()); 177 } else { 178 writer.append(LF); 179 if (getParent() != null) { 180 writer.append("Parent Chain ID: "); 181 writer.append(getParent().getChainId()); 182 writer.append(LF); 183 } 184 writer.append("Name: "); 185 writer.append(getChain().getId()); 186 writer.append(LF); 187 writer.append("Produced output type: "); 188 writer.append(output == null ? "Void" : output.getClass().getSimpleName()); 189 } 190 writer.append(LF); 191 writer.append("****** Hierarchy calls ******"); 192 writer.append(LF); 193 printCalls(calls, writer); 194 writer.flush(); 195 } 196 197 protected void printCalls(List<Call> calls, BufferedWriter writer) throws IOException { 198 String tabs = "\t"; 199 for (Call call : calls) { 200 writer.append(tabs); 201 call.print(writer); 202 tabs += "\t"; 203 } 204 } 205 206 public String print(boolean litePrint) { 207 ByteArrayOutputStream out = new ByteArrayOutputStream(); 208 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out)); 209 try { 210 if (litePrint) { 211 litePrint(writer); 212 } else { 213 print(writer); 214 } 215 } catch (IOException cause) { 216 return "Cannot print automation trace of " + chain.getId(); 217 } 218 return new String(out.toByteArray(), Charset.forName("UTF-8")); 219 } 220}