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.debug; 020 021import java.io.IOException; 022import java.util.ArrayList; 023import java.util.Collections; 024import java.util.Comparator; 025import java.util.HashMap; 026import java.util.Iterator; 027import java.util.List; 028import java.util.ListIterator; 029import java.util.Map; 030 031import lucee.commons.io.SystemUtil; 032import lucee.commons.io.res.util.ResourceSnippet; 033import lucee.commons.io.res.util.ResourceSnippetsMap; 034import lucee.commons.lang.ExceptionUtil; 035import lucee.commons.lang.StringUtil; 036import lucee.runtime.Component; 037import lucee.runtime.Page; 038import lucee.runtime.PageContext; 039import lucee.runtime.PageContextImpl; 040import lucee.runtime.PageSource; 041import lucee.runtime.PageSourceImpl; 042import lucee.runtime.config.Config; 043import lucee.runtime.config.ConfigImpl; 044import lucee.runtime.db.SQL; 045import lucee.runtime.engine.ThreadLocalPageContext; 046import lucee.runtime.exp.CatchBlock; 047import lucee.runtime.exp.DatabaseException; 048import lucee.runtime.exp.PageException; 049import lucee.runtime.exp.PageExceptionImpl; 050import lucee.runtime.op.Caster; 051import lucee.runtime.type.Array; 052import lucee.runtime.type.ArrayImpl; 053import lucee.runtime.type.Collection; 054import lucee.runtime.type.Collection.Key; 055import lucee.runtime.type.DebugQueryColumn; 056import lucee.runtime.type.KeyImpl; 057import lucee.runtime.type.Query; 058import lucee.runtime.type.QueryColumn; 059import lucee.runtime.type.QueryImpl; 060import lucee.runtime.type.Struct; 061import lucee.runtime.type.StructImpl; 062import lucee.runtime.type.dt.DateTimeImpl; 063import lucee.runtime.type.util.KeyConstants; 064 065 066/** 067 * Class to debug the application 068 */ 069public final class DebuggerImpl implements DebuggerPro { 070 private static final long serialVersionUID = 3957043879267494311L; 071 072 private static final Collection.Key IMPLICIT_ACCESS= KeyImpl.intern("implicitAccess"); 073 private static final Collection.Key PAGE_PARTS= KeyImpl.intern("pageParts"); 074 //private static final Collection.Key OUTPUT_LOG= KeyImpl.intern("outputLog"); 075 076 private static final int MAX_PARTS = 100; 077 078 private Map<String,DebugEntryTemplateImpl> entries=new HashMap<String,DebugEntryTemplateImpl>(); 079 private Map<String,DebugEntryTemplatePartImpl> partEntries; 080 private ResourceSnippetsMap snippetsMap = new ResourceSnippetsMap( 1024, 128 ); 081 082 private List<QueryEntry> queries=new ArrayList<QueryEntry>(); 083 private List<DebugTimerImpl> timers=new ArrayList<DebugTimerImpl>(); 084 private List<DebugTraceImpl> traces=new ArrayList<DebugTraceImpl>(); 085 private List<DebugDump> dumps=new ArrayList<DebugDump>(); 086 private List<CatchBlock> exceptions=new ArrayList<CatchBlock>(); 087 private Map<String,ImplicitAccessImpl> implicitAccesses=new HashMap<String,ImplicitAccessImpl>(); 088 089 private boolean output=true; 090 private long lastEntry; 091 private long lastTrace; 092 private Array historyId=new ArrayImpl(); 093 private Array historyLevel=new ArrayImpl(); 094 095 private long starttime=System.currentTimeMillis(); 096 097 private DebugOutputLog outputLog; 098 099 final static Comparator DEBUG_ENTRY_TEMPLATE_COMPARATOR = new DebugEntryTemplateComparator(); 100 final static Comparator DEBUG_ENTRY_TEMPLATE_PART_COMPARATOR = new DebugEntryTemplatePartComparator(); 101 102 private static final Key CACHE_TYPE = KeyImpl.init("cacheType"); 103 104 @Override 105 public void reset() { 106 entries.clear(); 107 if(partEntries!=null)partEntries.clear(); 108 queries.clear(); 109 implicitAccesses.clear(); 110 timers.clear(); 111 traces.clear(); 112 dumps.clear(); 113 exceptions.clear(); 114 historyId.clear(); 115 historyLevel.clear(); 116 output=true; 117 outputLog=null; 118 } 119 120 public DebuggerImpl() { 121 } 122 123 @Override 124 public DebugEntryTemplate getEntry(PageContext pc,PageSource source) { 125 return getEntry(pc,source,null); 126 } 127 128 @Override 129 public DebugEntryTemplate getEntry(PageContext pc,PageSource source, String key) { 130 lastEntry = System.currentTimeMillis(); 131 String src=DebugEntryTemplateImpl.getSrc(source==null?"":source.getDisplayPath(),key); 132 133 DebugEntryTemplateImpl de= entries.get(src); 134 if(de!=null ){ 135 de.countPP(); 136 historyId.appendEL(de.getId()); 137 historyLevel.appendEL(Caster.toInteger(pc.getCurrentLevel())); 138 return de; 139 } 140 de=new DebugEntryTemplateImpl(source,key); 141 entries.put(src,de); 142 historyId.appendEL(de.getId()); 143 historyLevel.appendEL(Caster.toInteger(pc.getCurrentLevel())); 144 return de; 145 } 146 147 148 @Override 149 public DebugEntryTemplatePart getEntry(PageContext pc, PageSource source, int startPos, int endPos) { 150 String src=DebugEntryTemplatePartImpl.getSrc(source==null?"":source.getDisplayPath(),startPos,endPos); 151 DebugEntryTemplatePartImpl de=null; 152 if(partEntries!=null){ 153 de=partEntries.get(src); 154 if(de!=null ){ 155 de.countPP(); 156 return de; 157 } 158 } 159 else { 160 partEntries=new HashMap<String, DebugEntryTemplatePartImpl>(); 161 } 162 163 ResourceSnippet snippet = snippetsMap.getSnippet( source, startPos, endPos, ((PageContextImpl)pc).getResourceCharset().name()); 164 de=new DebugEntryTemplatePartImpl(source, startPos, endPos, snippet.getStartLine(), snippet.getEndLine(), snippet.getContent()); 165 partEntries.put(src,de); 166 return de; 167 } 168 169 private ArrayList<DebugEntryTemplate> toArray() { 170 ArrayList<DebugEntryTemplate> arrPages=new ArrayList<DebugEntryTemplate>(entries.size()); 171 Iterator<String> it = entries.keySet().iterator(); 172 while(it.hasNext()) { 173 DebugEntryTemplate page =entries.get(it.next()); 174 page.resetQueryTime(); 175 arrPages.add(page); 176 177 } 178 Collections.sort(arrPages, DEBUG_ENTRY_TEMPLATE_COMPARATOR); 179 180 181 // Queries 182 int len=queries.size(); 183 for(int i=0;i<len;i++) { 184 QueryEntryPro entry=(QueryEntryPro) queries.get(i); 185 String path=entry.getSrc(); 186 Object o=entries.get(path); 187 188 if(o!=null) { 189 DebugEntryTemplate oe=(DebugEntryTemplate) o; 190 oe.updateQueryTime(entry.getExecutionTime()); 191 } 192 } 193 194 return arrPages; 195 } 196 197 /*private DumpData _toDumpData(int value) { 198 return new SimpleDumpData(_toString(value)); 199 } 200 private DumpData _toDumpData(long value) { 201 return new SimpleDumpData(_toString(value)); 202 }*/ 203 204 private String _toString(long value) { 205 if(value<=0) return "0"; 206 return String.valueOf(value); 207 } 208 private String _toString(int value) { 209 if(value<=0) return "0"; 210 return String.valueOf(value); 211 } 212 213 @Override 214 public void addQuery(Query query,String datasource,String name,SQL sql, int recordcount, PageSource src,int time) { 215 addQuery(query, datasource, name, sql, recordcount, src, (long)time); 216 } 217 218 @Override 219 public void addQuery(Query query,String datasource,String name,SQL sql, int recordcount, PageSource src,long time) { 220 String path=""; 221 if(src!=null) path=src.getDisplayPath(); 222 queries.add(new QueryEntryImpl(query,datasource,name,sql,recordcount,path,time)); 223 } 224 225 @Override 226 public void setOutput(boolean output) { 227 this.output = output; 228 } 229 230 @Override 231 public List<QueryEntry> getQueries() { 232 return queries; 233 } 234 235 @Override 236 public void writeOut(PageContext pc) throws IOException { 237 //stop(); 238 if(!output)return; 239 String addr = pc.getHttpServletRequest().getRemoteAddr(); 240 lucee.runtime.config.DebugEntry debugEntry = ((ConfigImpl)pc.getConfig()).getDebugEntry(addr, null); 241 242 // no debug File 243 244 if(debugEntry==null) { 245 //pc.forceWrite(pc.getConfig().getDefaultDumpWriter().toString(pc,toDumpData(pc, 9999,DumpUtil.toDumpProperties()),true)); 246 return; 247 } 248 249 Struct args=new StructImpl(); 250 args.setEL(KeyConstants._custom, debugEntry.getCustom()); 251 try { 252 args.setEL(KeyConstants._debugging, pc.getDebugger().getDebuggingData(pc)); 253 } catch (PageException e1) {} 254 255 try { 256 String path = debugEntry.getPath(); 257 PageSource[] arr = ((PageContextImpl)pc).getPageSources(path); 258 Page p = PageSourceImpl.loadPage(pc, arr,null); 259 260 // patch for old path 261 String fullname = debugEntry.getFullname(); 262 if(p==null) { 263 if(path!=null) { 264 boolean changed=false; 265 if(path.endsWith("/Modern.cfc") || path.endsWith("\\Modern.cfc")) { 266 path="/lucee-server/admin/debug/Modern.cfc"; 267 fullname="lucee-server.admin.debug.Modern"; 268 changed=true; 269 } 270 else if(path.endsWith("/Classic.cfc") || path.endsWith("\\Classic.cfc")) { 271 path="/lucee-server/admin/debug/Classic.cfc"; 272 fullname="lucee-server.admin.debug.Classic"; 273 changed=true; 274 } 275 else if(path.endsWith("/Comment.cfc") || path.endsWith("\\Comment.cfc")) { 276 path="/lucee-server/admin/debug/Comment.cfc"; 277 fullname="lucee-server.admin.debug.Comment"; 278 changed=true; 279 } 280 if(changed)pc.write("<span style='color:red'>Please update your debug template defintions in the lucee admin by going into the detail view and hit the \"update\" button.</span>"); 281 282 } 283 284 arr = ((PageContextImpl)pc).getPageSources(path); 285 p = PageSourceImpl.loadPage(pc, arr); 286 } 287 288 289 pc.addPageSource(p.getPageSource(), true); 290 try{ 291 Component cfc = pc.loadComponent(fullname); 292 cfc.callWithNamedValues(pc, "output", args); 293 } 294 finally { 295 pc.removeLastPageSource(true); 296 } 297 } 298 catch (PageException e) { 299 pc.handlePageException(e); 300 } 301 } 302 303 @Override 304 public Struct getDebuggingData(PageContext pc) throws DatabaseException { 305 return getDebuggingData(pc, false); 306 } 307 308 @Override 309 public Struct getDebuggingData(PageContext pc, boolean addAddionalInfo) throws DatabaseException { 310 List<QueryEntry> queries = getQueries(); 311 Struct qryExe=new StructImpl(); 312 ListIterator<QueryEntry> qryIt = queries.listIterator(); 313 Collection.Key[] cols = new Collection.Key[]{ 314 KeyConstants._name, 315 KeyConstants._time, 316 KeyConstants._sql, 317 KeyConstants._src, 318 KeyConstants._count, 319 KeyConstants._datasource, 320 KeyConstants._usage, 321 CACHE_TYPE}; 322 String[] types = new String[]{"VARCHAR","DOUBLE","VARCHAR","VARCHAR","DOUBLE","VARCHAR","ANY","VARCHAR"}; 323 324 //queries 325 Query qryQueries=null; 326 try { 327 qryQueries = new QueryImpl(cols,types,queries.size(),"query"); 328 } catch (DatabaseException e) { 329 qryQueries = new QueryImpl(cols,queries.size(),"query"); 330 } 331 int row=0; 332 try { 333 while(qryIt.hasNext()) { 334 row++; 335 QueryEntryPro qe=(QueryEntryPro) qryIt.next(); 336 qryQueries.setAt(KeyConstants._name,row,qe.getName()==null?"":qe.getName()); 337 qryQueries.setAt(KeyConstants._time,row,Long.valueOf(qe.getExecutionTime())); 338 qryQueries.setAt(KeyConstants._sql,row,qe.getSQL().toString()); 339 qryQueries.setAt(KeyConstants._src,row,qe.getSrc()); 340 qryQueries.setAt(KeyConstants._count,row,Integer.valueOf(qe.getRecordcount())); 341 qryQueries.setAt(KeyConstants._datasource,row,qe.getDatasource()); 342 qryQueries.setAt(CACHE_TYPE,row,qe.getCacheType()); 343 344 Struct usage = getUsage(qe); 345 if(usage!=null) qryQueries.setAt(KeyConstants._usage,row,usage); 346 347 Object o=qryExe.get(KeyImpl.init(qe.getSrc()),null); 348 if(o==null) qryExe.setEL(KeyImpl.init(qe.getSrc()),Long.valueOf(qe.getExecutionTime())); 349 else qryExe.setEL(KeyImpl.init(qe.getSrc()),Long.valueOf(((Long)o).longValue()+qe.getExecutionTime())); 350 } 351 } 352 catch(PageException dbe) {} 353 354 // Pages 355 // src,load,app,query,total 356 Struct debugging=new StructImpl(); 357 row=0; 358 ArrayList<DebugEntryTemplate> arrPages = toArray(); 359 int len=arrPages.size(); 360 Query qryPage=new QueryImpl( 361 new Collection.Key[]{ 362 KeyConstants._id, 363 KeyConstants._count, 364 KeyConstants._min, 365 KeyConstants._max, 366 KeyConstants._avg 367 ,KeyConstants._app, 368 KeyConstants._load, 369 KeyConstants._query, 370 KeyConstants._total, 371 KeyConstants._src}, 372 len,"query"); 373 374 try { 375 DebugEntryTemplate de; 376 //PageSource ps; 377 for(int i=0;i<len;i++) { 378 row++; 379 de=arrPages.get(i); 380 //ps = de.getPageSource(); 381 382 qryPage.setAt(KeyConstants._id,row,de.getId()); 383 qryPage.setAt(KeyConstants._count,row,_toString(de.getCount())); 384 qryPage.setAt(KeyConstants._min,row,_toString(de.getMin())); 385 qryPage.setAt(KeyConstants._max,row,_toString(de.getMax())); 386 qryPage.setAt(KeyConstants._avg,row,_toString(de.getExeTime()/de.getCount())); 387 qryPage.setAt(KeyConstants._app,row,_toString(de.getExeTime()-de.getQueryTime())); 388 qryPage.setAt(KeyConstants._load,row,_toString(de.getFileLoadTime())); 389 qryPage.setAt(KeyConstants._query,row,_toString(de.getQueryTime())); 390 qryPage.setAt(KeyConstants._total,row,_toString( de.getFileLoadTime() + de.getExeTime())); 391 qryPage.setAt(KeyConstants._src,row,de.getSrc()); 392 } 393 } 394 catch(PageException dbe) {} 395 396 397 // Pages Parts 398 List<DebugEntryTemplatePart> filteredPartEntries = null; 399 boolean hasParts=partEntries!=null && !partEntries.isEmpty() && !arrPages.isEmpty(); 400 int qrySize=0; 401 402 if(hasParts) { 403 404 String slowestTemplate = arrPages.get( 0 ).getPath(); 405 406 filteredPartEntries = new ArrayList(); 407 408 java.util.Collection<DebugEntryTemplatePartImpl> col = partEntries.values(); 409 for ( DebugEntryTemplatePart detp : col ) { 410 411 if ( detp.getPath().equals( slowestTemplate ) ) 412 filteredPartEntries.add( detp ); 413 } 414 415 qrySize = Math.min( filteredPartEntries.size(), MAX_PARTS ); 416 } 417 418 Query qryPart = new QueryImpl( 419 new Collection.Key[]{ 420 KeyConstants._id 421 ,KeyConstants._count 422 ,KeyConstants._min 423 ,KeyConstants._max 424 ,KeyConstants._avg 425 ,KeyConstants._total 426 ,KeyConstants._path 427 ,KeyConstants._start 428 ,KeyConstants._end 429 ,KeyConstants._startLine 430 ,KeyConstants._endLine 431 ,KeyConstants._snippet 432 }, qrySize, "query" ); 433 434 if(hasParts) { 435 row=0; 436 Collections.sort( filteredPartEntries, DEBUG_ENTRY_TEMPLATE_PART_COMPARATOR ); 437 438 DebugEntryTemplatePart[] parts = new DebugEntryTemplatePart[ qrySize ]; 439 440 if ( filteredPartEntries.size() > MAX_PARTS ) 441 parts = filteredPartEntries.subList(0, MAX_PARTS).toArray( parts ); 442 else 443 parts = filteredPartEntries.toArray( parts ); 444 445 try { 446 DebugEntryTemplatePart de; 447 //PageSource ps; 448 for(int i=0;i<parts.length;i++) { 449 row++; 450 de=parts[i]; 451 452 qryPart.setAt(KeyConstants._id,row,de.getId()); 453 qryPart.setAt(KeyConstants._count,row,_toString(de.getCount())); 454 qryPart.setAt(KeyConstants._min,row,_toString(de.getMin())); 455 qryPart.setAt(KeyConstants._max,row,_toString(de.getMax())); 456 qryPart.setAt(KeyConstants._avg,row,_toString(de.getExeTime()/de.getCount())); 457 qryPart.setAt(KeyConstants._start,row,_toString(de.getStartPosition())); 458 qryPart.setAt(KeyConstants._end,row,_toString(de.getEndPosition())); 459 qryPart.setAt(KeyConstants._total,row,_toString(de.getExeTime())); 460 qryPart.setAt(KeyConstants._path,row,de.getPath()); 461 462 if ( de instanceof DebugEntryTemplatePartImpl ) { 463 464 qryPart.setAt( KeyConstants._startLine, row, _toString( ((DebugEntryTemplatePartImpl)de).getStartLine() ) ); 465 qryPart.setAt( KeyConstants._endLine, row, _toString( ((DebugEntryTemplatePartImpl)de).getEndLine() )); 466 qryPart.setAt( KeyConstants._snippet, row, ((DebugEntryTemplatePartImpl)de).getSnippet() ); 467 } 468 } 469 } 470 catch(PageException dbe) {} 471 } 472 473 474 475 476 // exceptions 477 len = exceptions==null?0:exceptions.size(); 478 479 Array arrExceptions=new ArrayImpl(); 480 if(len>0) { 481 Iterator<CatchBlock> it = exceptions.iterator(); 482 row=0; 483 while(it.hasNext()) { 484 arrExceptions.appendEL(it.next()); 485 } 486 487 } 488 489 // output log 490 //Query qryOutputLog=getOutputText(); 491 492 493 494 // timers 495 len=timers==null?0:timers.size(); 496 Query qryTimers=new QueryImpl( 497 new Collection.Key[]{KeyConstants._label,KeyConstants._time,KeyConstants._template}, 498 len,"timers"); 499 if(len>0) { 500 try { 501 Iterator<DebugTimerImpl> it = timers.iterator(); 502 DebugTimer timer; 503 row=0; 504 while(it.hasNext()) { 505 timer=it.next(); 506 row++; 507 qryTimers.setAt(KeyConstants._label,row,timer.getLabel()); 508 qryTimers.setAt(KeyConstants._template,row,timer.getTemplate()); 509 qryTimers.setAt(KeyConstants._time,row,Caster.toDouble(timer.getTime())); 510 } 511 } 512 catch(PageException dbe) {} 513 } 514 515 // dumps 516 len=dumps==null?0:dumps.size(); 517 if(!((ConfigImpl)pc.getConfig()).hasDebugOptions(ConfigImpl.DEBUG_DUMP))len=0; 518 Query qryDumps=new QueryImpl( 519 new Collection.Key[]{ 520 KeyConstants._output, 521 KeyConstants._template, 522 KeyConstants._line}, 523 len,"dumps"); 524 if(len>0) { 525 try { 526 Iterator<DebugDump> it = dumps.iterator(); 527 DebugDump dd; 528 row=0; 529 while(it.hasNext()) { 530 dd= it.next(); 531 row++; 532 qryDumps.setAt(KeyConstants._output,row,dd.getOutput()); 533 if(!StringUtil.isEmpty(dd.getTemplate()))qryDumps.setAt(KeyConstants._template,row,dd.getTemplate()); 534 if(dd.getLine()>0)qryDumps.setAt(KeyConstants._line,row,new Double(dd.getLine())); 535 } 536 } 537 catch(PageException dbe) {} 538 } 539 540 // traces 541 len=traces==null?0:traces.size(); 542 if(!((ConfigImpl)pc.getConfig()).hasDebugOptions(ConfigImpl.DEBUG_TRACING))len=0; 543 Query qryTraces=new QueryImpl( 544 new Collection.Key[]{ 545 KeyConstants._type, 546 KeyConstants._category, 547 KeyConstants._text, 548 KeyConstants._template, 549 KeyConstants._line, 550 KeyConstants._action, 551 KeyConstants._varname, 552 KeyConstants._varvalue, 553 KeyConstants._time}, 554 len,"traces"); 555 if(len>0) { 556 try { 557 Iterator<DebugTraceImpl> it = traces.iterator(); 558 DebugTraceImpl trace; 559 row=0; 560 while(it.hasNext()) { 561 trace= it.next(); 562 row++; 563 qryTraces.setAt(KeyConstants._type,row,DebugTraceImpl.toType(trace.getType(), "INFO")); 564 if(!StringUtil.isEmpty(trace.getCategory()))qryTraces.setAt(KeyConstants._category,row,trace.getCategory()); 565 if(!StringUtil.isEmpty(trace.getText()))qryTraces.setAt(KeyConstants._text,row,trace.getText()); 566 if(!StringUtil.isEmpty(trace.getTemplate()))qryTraces.setAt(KeyConstants._template,row,trace.getTemplate()); 567 if(trace.getLine()>0)qryTraces.setAt(KeyConstants._line,row,new Double(trace.getLine())); 568 if(!StringUtil.isEmpty(trace.getAction()))qryTraces.setAt(KeyConstants._action,row,trace.getAction()); 569 if(!StringUtil.isEmpty(trace.getVarName()))qryTraces.setAt(KeyImpl.init("varname"),row,trace.getVarName()); 570 if(!StringUtil.isEmpty(trace.getVarValue()))qryTraces.setAt(KeyImpl.init("varvalue"),row,trace.getVarValue()); 571 qryTraces.setAt(KeyConstants._time,row,new Double(trace.getTime())); 572 } 573 } 574 catch(PageException dbe) {} 575 } 576 577 578 579 // scope access 580 len=implicitAccesses==null?0:implicitAccesses.size(); 581 Query qryImplicitAccesseses=new QueryImpl( 582 new Collection.Key[]{ 583 KeyConstants._template, 584 KeyConstants._line, 585 KeyConstants._scope, 586 KeyConstants._count, 587 KeyConstants._name}, 588 len,"implicitAccess"); 589 if(len>0) { 590 try { 591 Iterator<ImplicitAccessImpl> it = implicitAccesses.values().iterator(); 592 ImplicitAccessImpl das; 593 row=0; 594 while(it.hasNext()) { 595 das= it.next(); 596 row++; 597 qryImplicitAccesseses.setAt(KeyConstants._template,row,das.getTemplate()); 598 qryImplicitAccesseses.setAt(KeyConstants._line,row,new Double(das.getLine())); 599 qryImplicitAccesseses.setAt(KeyConstants._scope,row,das.getScope()); 600 qryImplicitAccesseses.setAt(KeyConstants._count,row,new Double(das.getCount())); 601 qryImplicitAccesseses.setAt(KeyConstants._name,row,das.getName()); 602 603 } 604 } 605 catch(PageException dbe) {} 606 } 607 608 Query history=new QueryImpl(new Collection.Key[]{},0,"history"); 609 try { 610 history.addColumn(KeyConstants._id, historyId); 611 history.addColumn(KeyConstants._level, historyLevel); 612 } catch (PageException e) { 613 } 614 615 if(addAddionalInfo) { 616 debugging.setEL(KeyConstants._cgi,pc.cgiScope()); 617 debugging.setEL(KeyImpl.init("starttime"),new DateTimeImpl(starttime,false)); 618 debugging.setEL(KeyConstants._id,pc.getId()); 619 } 620 621 debugging.setEL(KeyConstants._pages,qryPage); 622 debugging.setEL(PAGE_PARTS,qryPart); 623 debugging.setEL(KeyConstants._queries,qryQueries); 624 debugging.setEL(KeyConstants._timers,qryTimers); 625 debugging.setEL(KeyConstants._traces,qryTraces); 626 debugging.setEL("dumps",qryDumps); 627 debugging.setEL(IMPLICIT_ACCESS,qryImplicitAccesseses); 628 //debugging.setEL(OUTPUT_LOG,qryOutputLog); 629 630 631 632 633 debugging.setEL(KeyConstants._history,history); 634 debugging.setEL(KeyConstants._exceptions,arrExceptions); 635 636 return debugging; 637 } 638 639 private static Struct getUsage(QueryEntry qe) throws PageException { 640 Query qry = ((QueryEntryImpl)qe).getQry(); 641 642 QueryColumn c; 643 DebugQueryColumn dqc; 644 outer:if(qry!=null) { 645 Struct usage=null; 646 Collection.Key[] columnNames = qry.getColumnNames(); 647 Collection.Key columnName; 648 for(int i=0;i<columnNames.length;i++){ 649 columnName=columnNames[i]; 650 c = qry.getColumn(columnName); 651 if(!(c instanceof DebugQueryColumn)) break outer; 652 dqc=(DebugQueryColumn) c; 653 if(usage==null) usage=new StructImpl(); 654 usage.setEL(columnName, Caster.toBoolean(dqc.isUsed())); 655 } 656 return usage; 657 } 658 return null; 659 } 660 661 /*private static String getUsageList(QueryEntry qe) throws PageException { 662 Query qry = ((QueryEntryImpl)qe).getQry(); 663 StringBuilder sb=new StringBuilder(); 664 QueryColumn c; 665 DebugQueryColumn dqc; 666 outer:if(qry!=null) { 667 String[] columnNames = qry.getColumns(); 668 Collection.Key colName; 669 for(int i=0;i<columnNames.length;i++){ 670 colName=KeyImpl.init(columnNames[i]); 671 c = qry.getColumn(colName); 672 if(!(c instanceof DebugQueryColumn)) break outer; 673 dqc=(DebugQueryColumn) c; 674 if(!dqc.isUsed()){ 675 if(sb.length()>0) sb.append(", "); 676 sb.append(colName.getString()); 677 } 678 } 679 } 680 return sb.toString(); 681 }*/ 682 683 @Override 684 public DebugTimer addTimer(String label, long time, String template) { 685 DebugTimerImpl t; 686 timers.add(t=new DebugTimerImpl(label,time,template)); 687 return t; 688 } 689 690 691 @Override 692 public DebugTrace addTrace(int type, String category, String text, PageSource page,String varName,String varValue) { 693 694 long _lastTrace =(traces.isEmpty())?lastEntry: lastTrace; 695 lastTrace = System.currentTimeMillis(); 696 697 DebugTraceImpl t=new DebugTraceImpl(type,category,text,page.getDisplayPath(),SystemUtil.getCurrentContext().line,"",varName,varValue,lastTrace-_lastTrace); 698 traces.add(t); 699 return t; 700 } 701 702 703 public DebugDump addDump(PageSource ps,String dump) { 704 705 DebugDump dt=new DebugDumpImpl(ps.getDisplayPath(),SystemUtil.getCurrentContext().line,dump); 706 dumps.add(dt); 707 return dt; 708 } 709 710 @Override 711 public DebugTrace addTrace(int type, String category, String text, String template,int line,String action,String varName,String varValue) { 712 713 long _lastTrace =(traces.isEmpty())?lastEntry: lastTrace; 714 lastTrace = System.currentTimeMillis(); 715 716 DebugTraceImpl t=new DebugTraceImpl(type,category,text,template,line,action,varName,varValue,lastTrace-_lastTrace); 717 traces.add(t); 718 return t; 719 } 720 721 @Override 722 public DebugTrace[] getTraces() { 723 return getTraces(ThreadLocalPageContext.get()); 724 } 725 726 public DebugTrace[] getTraces(PageContext pc) { 727 if(pc!=null && ((ConfigImpl)pc.getConfig()).hasDebugOptions(ConfigImpl.DEBUG_TRACING)) 728 return traces.toArray(new DebugTrace[traces.size()]); 729 return new DebugTrace[0]; 730 } 731 732 @Override 733 public void addException(Config config,PageException pe) { 734 if(exceptions.size()>1000) return; 735 try { 736 exceptions.add(((PageExceptionImpl)pe).getCatchBlock(config)); 737 } 738 catch(Throwable t){ 739 ExceptionUtil.rethrowIfNecessary(t); 740 } 741 } 742 743 @Override 744 public CatchBlock[] getExceptions() { 745 return exceptions.toArray(new CatchBlock[exceptions.size()]); 746 } 747 748 public void init(Config config) { 749 this.starttime=System.currentTimeMillis()+config.getTimeServerOffset(); 750 } 751 752 @Override 753 public void addImplicitAccess(String scope, String name) { 754 if(implicitAccesses.size()>1000) return; 755 try { 756 SystemUtil.TemplateLine tl = SystemUtil.getCurrentContext(); 757 String key=tl+":"+scope+":"+name; 758 ImplicitAccessImpl dsc = implicitAccesses.get(key); 759 if(dsc!=null) 760 dsc.inc(); 761 else 762 implicitAccesses.put(key,new ImplicitAccessImpl(scope,name,tl.template,tl.line)); 763 } 764 catch(Throwable t){ 765 ExceptionUtil.rethrowIfNecessary(t); 766 } 767 } 768 769 @Override 770 public ImplicitAccess[] getImplicitAccesses(int scope, String name) { 771 return implicitAccesses.values().toArray(new ImplicitAccessImpl[implicitAccesses.size()]); 772 } 773 774 public void setOutputLog(DebugOutputLog outputLog) { 775 this.outputLog=outputLog; 776 } 777 778 public DebugTextFragment[] getOutputTextFragments() { 779 return this.outputLog.getFragments(); 780 } 781 782 public Query getOutputText() throws DatabaseException { 783 DebugTextFragment[] fragments = outputLog.getFragments(); 784 int len = fragments==null?0:fragments.length; 785 Query qryOutputLog=new QueryImpl( 786 new Collection.Key[]{ 787 KeyConstants._line 788 ,KeyConstants._template, 789 KeyConstants._text}, 790 len,"query"); 791 792 793 if(len>0) { 794 for(int i=0;i<fragments.length;i++) { 795 qryOutputLog.setAtEL(KeyConstants._line,i+1,fragments[i].line); 796 qryOutputLog.setAtEL(KeyConstants._template,i+1,fragments[i].template); 797 qryOutputLog.setAtEL(KeyConstants._text,i+1,fragments[i].text); 798 } 799 } 800 return qryOutputLog; 801 802 } 803 804 public void resetTraces() { 805 traces.clear(); 806 } 807 808} 809 810final class DebugEntryTemplateComparator implements Comparator<DebugEntryTemplate> { 811 812 public int compare(DebugEntryTemplate de1,DebugEntryTemplate de2) { 813 long result = ((de2.getExeTime()+de2.getFileLoadTime())-(de1.getExeTime()+de1.getFileLoadTime())); 814 // we do this additional step to try to avoid ticket LUCEE-2076 815 return result>0L?1:(result<0L?-1:0); 816 } 817} 818 819final class DebugEntryTemplatePartComparator implements Comparator<DebugEntryTemplatePart> { 820 821 @Override 822 public int compare(DebugEntryTemplatePart de1,DebugEntryTemplatePart de2) { 823 long result=de2.getExeTime()-de1.getExeTime(); 824 // we do this additional step to try to avoid ticket LUCEE-2076 825 return result>0L?1:(result<0L?-1:0); 826 } 827}