001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.tag; 020 021import java.io.IOException; 022 023import lucee.commons.io.log.Log; 024import lucee.commons.io.log.LogUtil; 025import lucee.commons.lang.StringUtil; 026import lucee.runtime.PageSource; 027import lucee.runtime.config.ConfigImpl; 028import lucee.runtime.converter.ConverterException; 029import lucee.runtime.converter.ScriptConverter; 030import lucee.runtime.debug.DebugTrace; 031import lucee.runtime.debug.DebugTraceImpl; 032import lucee.runtime.debug.DebuggerPro; 033import lucee.runtime.exp.Abort; 034import lucee.runtime.exp.ApplicationException; 035import lucee.runtime.exp.PageException; 036import lucee.runtime.ext.tag.BodyTagImpl; 037import lucee.runtime.functions.other.Dump; 038import lucee.runtime.interpreter.VariableInterpreter; 039import lucee.runtime.op.Caster; 040import lucee.runtime.type.Struct; 041import lucee.runtime.type.dt.DateTimeImpl; 042import lucee.runtime.type.scope.Scope; 043import lucee.runtime.type.trace.TraceObjectSupport; 044 045public final class Trace extends BodyTagImpl { 046 047 private boolean abort=false; 048 private boolean follow=false; 049 private String category; 050 private boolean inline=false; 051 private String text; 052 private int type=Log.LEVEL_INFO; 053 private String var; 054 private Struct caller; 055 056 057 @Override 058 public void release() { 059 super.release(); 060 abort=false; 061 category=null; 062 inline=false; 063 text=null; 064 type=Log.LEVEL_INFO; 065 var=null; 066 caller=null; 067 follow=false; 068 } 069 070 /** 071 * @param abort the abort to set 072 */ 073 public void setAbort(boolean abort) { 074 this.abort = abort; 075 } 076 public void setFollow(boolean follow) { 077 this.follow = follow; 078 } 079 080 /** 081 * @param category the category to set 082 */ 083 public void setCategory(String category) { 084 this.category = category; 085 } 086 087 /** 088 * @param inline the inline to set 089 */ 090 public void setInline(boolean inline) { 091 this.inline = inline; 092 } 093 094 /** 095 * @param text the text to set 096 */ 097 public void setText(String text) { 098 this.text = text; 099 } 100 101 /** 102 * @param type the type to set 103 * @throws ApplicationException 104 */ 105 public void setType(String strType) throws ApplicationException { 106 strType = strType.toLowerCase().trim(); 107 if("info".equals(strType)) type=Log.LEVEL_INFO; 108 if("information".equals(strType)) type=Log.LEVEL_INFO; 109 else if("warn".equals(strType)) type=Log.LEVEL_WARN; 110 else if("warning".equals(strType)) type=Log.LEVEL_WARN; 111 else if("error".equals(strType)) type=Log.LEVEL_ERROR; 112 else if("fatal information".equals(strType)) type=Log.LEVEL_FATAL; 113 else if("fatal-information".equals(strType)) type=Log.LEVEL_FATAL; 114 else if("fatal_information".equals(strType)) type=Log.LEVEL_FATAL; 115 else if("fatalinformation".equals(strType)) type=Log.LEVEL_FATAL; 116 else if("fatal info".equals(strType)) type=Log.LEVEL_FATAL; 117 else if("fatal-info".equals(strType)) type=Log.LEVEL_FATAL; 118 else if("fatal_info".equals(strType)) type=Log.LEVEL_FATAL; 119 else if("fatalinfo".equals(strType)) type=Log.LEVEL_FATAL; 120 else if("fatal".equals(strType)) type=Log.LEVEL_FATAL; 121 else if("debug".equals(strType)) type=Log.LEVEL_DEBUG; 122 else if("debugging".equals(strType)) type=Log.LEVEL_DEBUG; 123 else if("debuging".equals(strType)) type=Log.LEVEL_DEBUG; 124 else if("trace".equals(strType)) type=LogUtil.LEVEL_TRACE; 125 else throw new ApplicationException("invalid value ["+strType+"] for attribute [type], valid values are [Debug, Information, Warning, Error, Fatal Information]"); 126 } 127 128 /** 129 * @param var the var to set 130 */ 131 public void setVar(String var) { 132 this.var = var; 133 } 134 135 public void setCaller(Struct caller) { 136 this.caller = caller; 137 } 138 139 /** 140 * @param var the var to set 141 */ 142 public void setVariable(String var) { 143 this.var = var; 144 } 145 146 @Override 147 public int doStartTag() { 148 return EVAL_BODY_INCLUDE; 149 } 150 151 152 @Override 153 public int doEndTag() throws PageException { 154 try { 155 _doEndTag(); 156 } 157 catch (IOException e) {} 158 return EVAL_PAGE; 159 } 160 161 public void _doEndTag() throws IOException, PageException { 162 163 PageSource page = pageContext.getCurrentTemplatePageSource(); 164 165 // var 166 String varValue=null; 167 Object value=null,traceValue=null; 168 if(!StringUtil.isEmpty(var)) { 169 170 try { 171 if(caller instanceof Scope) value=VariableInterpreter.getVariable(pageContext,var,(Scope)caller); 172 else value = pageContext.getVariable(var); 173 } 174 catch (PageException e) { 175 varValue="(undefined)"; 176 follow=false; 177 } 178 179 if(follow){ 180 //print.o(1); 181 if(StringUtil.isEmpty(text,true)) text=var; 182 //print.o(2); 183 traceValue=TraceObjectSupport.toTraceObject(pageContext.getDebugger(), value, type, category, text); 184 185 if(caller instanceof Scope) VariableInterpreter.setVariable(pageContext,var,traceValue,(Scope)caller); 186 else pageContext.setVariable(var,traceValue); 187 } 188 189 try { 190 varValue=new ScriptConverter().serialize(value); 191 } 192 catch (ConverterException e) { 193 if(value!=null)varValue="("+Caster.toTypeName(value)+")"; 194 } 195 196 197 198 } 199 DebugTrace trace = pageContext.getDebugger().addTrace(type,category,text,page,var,varValue); 200 DebugTrace[] traces = ((DebuggerPro)pageContext.getDebugger()).getTraces(pageContext); 201 202 String total="(1st trace)"; 203 if(traces.length>1) { 204 long t=0; 205 for(int i=0;i<traces.length;i++) { 206 t+=traces[i].getTime(); 207 } 208 total="("+t+")"; 209 } 210 211 boolean hasCat=!StringUtil.isEmpty(trace.getCategory()); 212 boolean hasText=!StringUtil.isEmpty(trace.getText()); 213 boolean hasVar=!StringUtil.isEmpty(var); 214 215 // inline 216 if(inline) { 217 lucee.runtime.format.TimeFormat tf = new lucee.runtime.format.TimeFormat(pageContext.getConfig().getLocale()); 218 StringBuffer sb=new StringBuffer(); 219 sb.append("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" bgcolor=\"white\">"); 220 sb.append("<tr>"); 221 //sb.append("<td><img src=\"/CFIDE/debug/images/Error_16x16.gif\" alt=\"Error type\">"); 222 sb.append("<td>"); 223 sb.append("<font color=\"orange\">"); 224 sb.append("<b>"); 225 sb.append(DebugTraceImpl.toType(trace.getType(),"INFO")+" - "); 226 sb.append("[CFTRACE "+tf.format(new DateTimeImpl(pageContext.getConfig()), "hh:mm:ss:l")+"]"); 227 sb.append("["+trace.getTime()+" ms "+total+"]"); 228 sb.append("["+trace.getTemplate()+" @ line: "+trace.getLine()+"]"); 229 if(hasCat || hasText)sb.append(" -"); 230 if(hasCat)sb.append(" ["+trace.getCategory()+"]"); 231 if(hasText)sb.append(" <i>"+trace.getText()+" </i>"); 232 sb.append("</b>"); 233 sb.append("</font>"); 234 sb.append("</td>"); 235 sb.append("</tr>"); 236 sb.append("</table>"); 237 pageContext.forceWrite(sb.toString()); 238 239 if(hasVar)Dump.call(pageContext, value, var); 240 241 } 242 243 // log 244 Log log = ((ConfigImpl)pageContext.getConfig()).getLog("trace"); 245 StringBuffer msg=new StringBuffer(); 246 msg.append("["+trace.getTime()+" ms "+total+"] "); 247 msg.append("["+trace.getTemplate()+" @ line: "+trace.getLine()+"]"); 248 if(hasCat || hasText || hasVar) msg.append("- "); 249 if(hasCat)msg.append("["+trace.getCategory()+"] "); 250 if(hasVar)msg.append("["+var+"="+varValue+"] "); 251 if(hasText)msg.append(" "+trace.getText()+" "); 252 log.log(trace.getType(), "cftrace", msg.toString()); 253 254 // abort 255 if(abort) throw new Abort(Abort.SCOPE_REQUEST); 256 257 } 258 259 @Override 260 public void doInitBody() { 261 262 } 263 264 @Override 265 public int doAfterBody() { 266 return SKIP_BODY; 267 } 268 269 /** 270 * sets if has body or not 271 * @param hasBody 272 */ 273 public void hasBody(boolean hasBody) { 274 275 } 276}