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()+"&nbsp;</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}