1 /* 2 * Created on Nov 19, 2003 3 * Created by Alon Rohter 4 * 5 * Copyright (C) Azureus Software, Inc, All Rights Reserved. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 */ 19 package org.gudy.azureus2.core3.util; 20 21 import java.io.*; 22 import java.net.UnknownHostException; 23 import java.net.ConnectException; 24 import java.util.*; 25 26 /** 27 * Debug-assisting class. 28 */ 29 public class Debug { 30 31 private static boolean STOP_AT_INITIALIZER = System.getProperty("debug.stacktrace.full", "0").equals("0"); 32 33 private static AEDiagnosticsLogger diag_logger; 34 35 static{ 36 try{ 37 diag_logger = AEDiagnostics.getLogger( "debug" ); 38 39 diag_logger.setForced( true ); 40 41 }catch( Throwable e ){ 42 43 } 44 } 45 46 47 /** 48 * Prints out the given debug message to System.out, 49 * prefixed by the calling class name, method and 50 * line number. 51 */ out(final String _debug_message)52 public static void out(final String _debug_message) { 53 out( _debug_message, null ); 54 } 55 56 /** 57 * Prints out the given exception stacktrace to System.out, 58 * prefixed by the calling class name, method and 59 * line number. 60 */ out(final Throwable _exception)61 public static void out(final Throwable _exception) { 62 out( "", _exception ); 63 } 64 65 public static void outNoStack( String str )66 outNoStack( 67 String str ) 68 { 69 outNoStack( str, false ); 70 } 71 72 public static void outNoStack( String str, boolean stderr)73 outNoStack( 74 String str, 75 boolean stderr) 76 { 77 diagLoggerLogAndOut("DEBUG::"+ new Date(SystemTime.getCurrentTime()).toString() + " " + str, stderr ); 78 } 79 80 public static void outDiagLoggerOnly( String str)81 outDiagLoggerOnly( 82 String str) 83 { 84 diagLoggerLog(str); 85 } 86 87 /** 88 * Prints out the given debug message to System.out, 89 * prefixed by the calling class name, method and 90 * line number, appending the stacktrace of the given exception. 91 */ out(final String _debug_msg, final Throwable _exception)92 public static void out(final String _debug_msg, final Throwable _exception) { 93 if ((_exception instanceof ConnectException) && _exception.getMessage().startsWith("No route to host")) { 94 diagLoggerLog(_exception.toString()); 95 return; 96 } 97 if ((_exception instanceof UnknownHostException)) { 98 diagLoggerLog(_exception.toString()); 99 return; 100 } 101 String header = "DEBUG::"; 102 header = header + new Date(SystemTime.getCurrentTime()).toString() + "::"; 103 String className; 104 String methodName; 105 int lineNumber; 106 String trace_trace_tail = null; 107 108 try { 109 throw new Exception(); 110 } 111 catch (Exception e) { 112 StackTraceElement[] st = e.getStackTrace(); 113 114 StackTraceElement first_line = st[2]; 115 className = first_line.getClassName() + "::"; 116 methodName = first_line.getMethodName() + "::"; 117 lineNumber = first_line.getLineNumber(); 118 119 trace_trace_tail = getCompressedStackTrace(e, 3, 200, false); 120 } 121 122 diagLoggerLogAndOut(header+className+(methodName)+lineNumber+":", true); 123 if (_debug_msg.length() > 0) { 124 diagLoggerLogAndOut(" " + _debug_msg, true); 125 } 126 if ( trace_trace_tail != null ){ 127 diagLoggerLogAndOut( " " + trace_trace_tail, true); 128 } 129 if (_exception != null) { 130 diagLoggerLogAndOut(_exception); 131 } 132 } 133 getLastCaller()134 public static String getLastCaller() { 135 return getLastCaller(0); 136 } 137 getLastCaller(int numToGoBackFurther)138 public static String getLastCaller(int numToGoBackFurther) { 139 try { 140 throw new Exception(); 141 } 142 catch (Exception e) { 143 // [0] = our throw 144 // [1] = the line that called getLastCaller 145 // [2] = the line that called the function that has getLastCaller 146 StackTraceElement st[] = e.getStackTrace(); 147 if (st == null || st.length == 0) 148 return "??"; 149 if (st.length > 3 + numToGoBackFurther) 150 return st[3 + numToGoBackFurther].toString(); 151 152 return st[st.length - 1].toString(); 153 } 154 } 155 getLastCallerShort()156 public static String getLastCallerShort() { 157 return getLastCallerShort(0); 158 } 159 getLastCallerShort(int numToGoBackFurther)160 public static String getLastCallerShort(int numToGoBackFurther) { 161 try { 162 throw new Exception(); 163 } 164 catch (Exception e) { 165 // [0] = our throw 166 // [1] = the line that called getLastCaller 167 // [2] = the line that called the function that has getLastCaller 168 StackTraceElement st[] = e.getStackTrace(); 169 StackTraceElement ste; 170 if (st == null || st.length == 0) 171 return "??"; 172 if (st.length > 3 + numToGoBackFurther){ 173 ste = st[3 + numToGoBackFurther]; 174 }else{ 175 ste = st[st.length - 1]; 176 } 177 String fn = ste.getFileName(); 178 179 if ( fn != null ){ 180 return( fn + ":" + ste.getLineNumber()); 181 } 182 return( ste.toString()); 183 } 184 } 185 outStackTrace()186 public static void outStackTrace() { 187 // skip the last, since they'll most likely be main 188 diagLoggerLogAndOut(getStackTrace(1),false); 189 } 190 getStackTrace(int endNumToSkip)191 private static String getStackTrace(int endNumToSkip) { 192 String sStackTrace = ""; 193 try { 194 throw new Exception(); 195 } 196 catch (Exception e) { 197 StackTraceElement st[] = e.getStackTrace(); 198 for (int i = 1; i < st.length - endNumToSkip; i++) { 199 if (!st[i].getMethodName().endsWith("StackTrace")) 200 sStackTrace += st[i].toString() + "\n"; 201 } 202 if (e.getCause() != null) 203 sStackTrace += "\tCaused By: " + getStackTrace(e.getCause()) + "\n"; 204 } 205 return sStackTrace; 206 } 207 208 public static void killAWTThreads()209 killAWTThreads() 210 { 211 ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); 212 213 killAWTThreads( threadGroup ); 214 } 215 216 private static String getCompressedStackTrace( Throwable t, int frames_to_skip)217 getCompressedStackTrace( 218 Throwable t, 219 int frames_to_skip) 220 { 221 return getCompressedStackTrace(t, frames_to_skip, 200); 222 } 223 224 225 public static String getCompressedStackTrace( Throwable t, int frames_to_skip, int iMaxLines)226 getCompressedStackTrace( 227 Throwable t, 228 int frames_to_skip, 229 int iMaxLines) 230 { 231 return getCompressedStackTrace(t, frames_to_skip, iMaxLines, true); 232 } 233 234 235 public static String getCompressedStackTrace( Throwable t, int frames_to_skip, int iMaxLines, boolean showErrString)236 getCompressedStackTrace( 237 Throwable t, 238 int frames_to_skip, 239 int iMaxLines, 240 boolean showErrString) 241 { 242 StringBuffer sbStackTrace = new StringBuffer(showErrString ? (t.toString() + "; ") : ""); 243 StackTraceElement[] st = t.getStackTrace(); 244 245 if (iMaxLines < 0) { 246 iMaxLines = st.length + iMaxLines; 247 if (iMaxLines < 0) { 248 iMaxLines = 1; 249 } 250 } 251 int iMax = Math.min(st.length, iMaxLines + frames_to_skip); 252 for (int i = frames_to_skip; i < iMax; i++) { 253 254 if (i > frames_to_skip) { 255 sbStackTrace.append(", "); 256 } 257 258 String classname = st[i].getClassName(); 259 String cnShort = classname.substring( classname.lastIndexOf(".")+1); 260 261 if (Constants.IS_CVS_VERSION) { 262 if (STOP_AT_INITIALIZER 263 && st[i].getClassName().equals( 264 "com.aelitis.azureus.ui.swt.Initializer")) { 265 sbStackTrace.append("Initializer"); 266 break; 267 } 268 // Formatted so it's clickable in eclipse 269 // sbStackTrace.append(st[i].toString()); 270 271 // Shorter version method(filename.java:1234) 272 sbStackTrace.append(st[i].getMethodName()); 273 // the space is needed otherwise Eclipse tries to look up method name 274 sbStackTrace.append(" ("); 275 sbStackTrace.append(st[i].getFileName()); 276 sbStackTrace.append(':'); 277 sbStackTrace.append(st[i].getLineNumber()); 278 sbStackTrace.append(')'); 279 } else { 280 sbStackTrace.append(cnShort); 281 sbStackTrace.append("::"); 282 sbStackTrace.append(st[i].getMethodName()); 283 sbStackTrace.append("::"); 284 sbStackTrace.append(st[i].getLineNumber()); 285 } 286 } 287 288 Throwable cause = t.getCause(); 289 290 if (cause != null) { 291 sbStackTrace.append("\n\tCaused By: "); 292 sbStackTrace.append(getCompressedStackTrace(cause, 0)); 293 } 294 295 return sbStackTrace.toString(); 296 } 297 getStackTrace(boolean bCompressed, boolean bIncludeSelf)298 public static String getStackTrace(boolean bCompressed, boolean bIncludeSelf) { 299 return getStackTrace(bCompressed, bIncludeSelf, bIncludeSelf ? 0 : 1, 200); 300 } 301 getStackTrace(boolean bCompressed, boolean bIncludeSelf, int iNumLinesToSkip, int iMaxLines)302 public static String getStackTrace(boolean bCompressed, boolean bIncludeSelf, 303 int iNumLinesToSkip, int iMaxLines) { 304 if (bCompressed) 305 return getCompressedStackTrace(bIncludeSelf ? 2 + iNumLinesToSkip 306 : 3 + iNumLinesToSkip, iMaxLines); 307 308 // bIncludeSelf not supported gor non Compressed yet 309 return getStackTrace(1); 310 } 311 getCompressedStackTrace(int frames_to_skip, int iMaxLines)312 private static String getCompressedStackTrace(int frames_to_skip, 313 int iMaxLines) { 314 String trace_trace_tail = null; 315 316 try { 317 throw new Exception(); 318 } catch (Exception e) { 319 trace_trace_tail = getCompressedStackTrace(e, frames_to_skip, iMaxLines, false); 320 } 321 322 return (trace_trace_tail); 323 } 324 325 public static void killAWTThreads( ThreadGroup threadGroup )326 killAWTThreads( 327 ThreadGroup threadGroup ) 328 { 329 Thread[] threadList = new Thread[threadGroup.activeCount()]; 330 331 threadGroup.enumerate(threadList); 332 333 for (int i = 0; i < threadList.length; i++){ 334 335 Thread t = threadList[i]; 336 337 if ( t != null ){ 338 339 String name = t.getName(); 340 341 if ( name.startsWith( "AWT" )){ 342 343 out( "Interrupting thread '".concat(t.toString()).concat("'" )); 344 345 t.interrupt(); 346 } 347 } 348 } 349 350 if ( threadGroup.getParent() != null ){ 351 352 killAWTThreads(threadGroup.getParent()); 353 } 354 } 355 356 public static void dumpThreads( String name )357 dumpThreads( 358 String name ) 359 { 360 out(name+":"); 361 362 ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); 363 364 dumpThreads( threadGroup, "\t" ); 365 } 366 367 public static void dumpThreads( ThreadGroup threadGroup, String indent )368 dumpThreads( 369 ThreadGroup threadGroup, 370 String indent ) 371 { 372 Thread[] threadList = new Thread[threadGroup.activeCount()]; 373 374 threadGroup.enumerate(threadList); 375 376 for (int i = 0; i < threadList.length; i++){ 377 378 Thread t = threadList[i]; 379 380 if ( t != null ){ 381 382 out( indent.concat("active thread = ").concat(t.toString()).concat(", daemon = ").concat(String.valueOf(t.isDaemon()))); 383 } 384 } 385 386 if ( threadGroup.getParent() != null ){ 387 388 dumpThreads(threadGroup.getParent(),indent+"\t"); 389 } 390 } 391 392 public static void dumpThreadsLoop( final String name )393 dumpThreadsLoop( 394 final String name ) 395 { 396 new AEThread("Thread Dumper") 397 { 398 public void 399 runSupport() 400 { 401 while(true){ 402 Debug.dumpThreads(name); 403 404 try{ 405 Thread.sleep(5000); 406 }catch( Throwable e ){ 407 Debug.printStackTrace( e ); 408 } 409 } 410 } 411 }.start(); 412 } 413 414 public static void dumpSystemProperties()415 dumpSystemProperties() 416 { 417 out( "System Properties:"); 418 419 Properties props = System.getProperties(); 420 421 Iterator it = props.keySet().iterator(); 422 423 while(it.hasNext()){ 424 425 String name = (String)it.next(); 426 427 out( "\t".concat(name).concat(" = '").concat(props.get(name).toString()).concat("'" )); 428 } 429 } 430 431 public static String getNestedExceptionMessage( Throwable e )432 getNestedExceptionMessage( 433 Throwable e ) 434 { 435 String last_message = ""; 436 437 while( e != null ){ 438 439 String this_message; 440 441 if ( e instanceof UnknownHostException ){ 442 443 this_message = "Unknown host " + e.getMessage(); 444 445 }else if ( e instanceof FileNotFoundException ){ 446 447 this_message = "File not found: " + e.getMessage(); 448 449 }else{ 450 451 this_message = e.getMessage(); 452 } 453 454 // if no exception message then pick up class name. if we have a deliberate 455 // zero length string then we assume that the exception can be ignored for 456 // logging purposes as it is just delegating 457 458 if ( this_message == null ){ 459 460 this_message = e.getClass().getName(); 461 462 int pos = this_message.lastIndexOf("."); 463 464 this_message = this_message.substring( pos+1 ).trim(); 465 } 466 467 if ( this_message.length() > 0 && last_message.indexOf( this_message ) == -1 ){ 468 469 last_message += (last_message.length()==0?"":", " ) + this_message; 470 } 471 472 e = e.getCause(); 473 } 474 475 return( last_message ); 476 } 477 478 public static boolean containsException( Throwable error, Class<? extends Throwable> cla )479 containsException( 480 Throwable error, 481 Class<? extends Throwable> cla ) 482 { 483 if ( error == null ){ 484 485 return( false ); 486 487 }else if ( cla.isInstance( error )){ 488 489 return( true ); 490 } 491 492 return( containsException( error.getCause(), cla )); 493 } 494 495 public static String getNestedExceptionMessageAndStack( Throwable e )496 getNestedExceptionMessageAndStack( 497 Throwable e ) 498 { 499 return( getNestedExceptionMessage(e) + ", " + getCompressedStackTrace( e, 0 )); 500 } 501 502 public static String getCompressedStackTraceSkipFrames( int frames_to_skip )503 getCompressedStackTraceSkipFrames( 504 int frames_to_skip ) 505 { 506 return( getCompressedStackTrace( new Throwable(), frames_to_skip+1, 200, false )); 507 } 508 509 public static String getCompressedStackTrace()510 getCompressedStackTrace() 511 { 512 return( getCompressedStackTrace( new Throwable(), 1, 200, false )); 513 } 514 515 /** 516 * 517 * @param iMaxLines Max # of stack lines. If < 0, chops off -MaxLines entries from end 518 * @return 519 */ 520 public static String getCompressedStackTrace(int iMaxLines)521 getCompressedStackTrace(int iMaxLines) 522 { 523 return( getCompressedStackTrace( new Throwable(), 1, iMaxLines, false )); 524 } 525 526 public static String getExceptionMessage( Throwable e )527 getExceptionMessage( 528 Throwable e ) 529 { 530 String message = e.getMessage(); 531 532 if ( message == null || message.length() == 0 ){ 533 534 message = e.getClass().getName(); 535 536 int pos = message.lastIndexOf("."); 537 538 message = message.substring( pos+1 ); 539 540 }else if ( e instanceof ClassNotFoundException ){ 541 542 if ( message.toLowerCase().indexOf("found") == -1 ){ 543 544 message = "Class " + message + " not found"; 545 } 546 } 547 548 return( message ); 549 } 550 printStackTrace(Throwable e)551 public static void printStackTrace(Throwable e) { 552 printStackTrace(e, null); 553 } 554 555 556 public static void printStackTrace( Throwable e, Object context)557 printStackTrace( 558 Throwable e, 559 Object context) 560 { 561 if ((e instanceof ConnectException) && e.getMessage().startsWith("No route to host")) { 562 diagLoggerLog(e.toString()); 563 return; 564 } 565 if ((e instanceof UnknownHostException)) { 566 diagLoggerLog(e.toString()); 567 return; 568 } 569 String header = "DEBUG::"; 570 header = header + new Date(SystemTime.getCurrentTime()).toString() + "::"; 571 String className = "?::"; 572 String methodName = "?::"; 573 int lineNumber = -1; 574 575 try { 576 throw new Exception(); 577 }catch (Exception f) { 578 StackTraceElement[] st = f.getStackTrace(); 579 580 for (int i=1;i<st.length;i++){ 581 StackTraceElement first_line = st[i]; 582 className = first_line.getClassName() + "::"; 583 methodName = first_line.getMethodName() + "::"; 584 lineNumber = first_line.getLineNumber(); 585 586 // skip stuff generated by the logger 587 588 if ( className.indexOf( ".logging." ) != -1 || 589 className.endsWith( ".Debug::" )){ 590 591 continue; 592 } 593 594 break; 595 } 596 } 597 598 diagLoggerLogAndOut(header+className+(methodName)+lineNumber+":", true); 599 600 try{ 601 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 602 603 PrintWriter pw = new PrintWriter( new OutputStreamWriter( baos )); 604 605 if (context!=null) {pw.print(" "); pw.println(context);} 606 pw.print(" "); 607 e.printStackTrace( pw ); 608 609 pw.close(); 610 611 String stack = baos.toString(); 612 613 diagLoggerLogAndOut(stack, true ); 614 }catch( Throwable ignore ){ 615 616 e.printStackTrace(); 617 } 618 } 619 getStackTrace(Throwable e)620 public static String getStackTrace(Throwable e) { 621 try { 622 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 623 624 PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos)); 625 626 e.printStackTrace(pw); 627 628 pw.close(); 629 630 return baos.toString(); 631 632 } catch (Throwable ignore) { 633 return ""; 634 } 635 } 636 diagLoggerLog(String str)637 private static void diagLoggerLog(String str) { 638 if ( diag_logger == null ){ 639 System.out.println( str ); 640 }else{ 641 diag_logger.log(str); 642 } 643 } 644 645 private static void diagLoggerLogAndOut( String str, boolean stderr )646 diagLoggerLogAndOut( 647 String str, 648 boolean stderr ) 649 { 650 // handle possible recursive initialisation problems where the init of diag-logger gets 651 // back here.... 652 653 if ( diag_logger == null ){ 654 if ( stderr ){ 655 System.err.println( str ); 656 }else{ 657 System.out.println( str ); 658 } 659 }else{ 660 diag_logger.logAndOut( str, stderr ); 661 } 662 } 663 private static void diagLoggerLogAndOut( Throwable e )664 diagLoggerLogAndOut( 665 Throwable e ) 666 { 667 // handle possible recursive initialisation problems where the init of diag-logger gets 668 // back here.... 669 670 if ( diag_logger == null ){ 671 e.printStackTrace(); 672 }else{ 673 diag_logger.logAndOut( e ); 674 } 675 } 676 677 /** 678 * @param key 679 * @return 680 */ secretFileName(String key)681 public static String secretFileName(String key) { 682 if (key == null) 683 return ""; 684 685 final String sep = File.separator; 686 final String regex = "([\\" + sep + "]?[^\\" + sep + "]{0,3}+)[^\\" + sep 687 + "]*"; 688 689 String secretName = key.replaceAll(regex, "$1"); 690 int iExtensionPos = key.lastIndexOf("."); 691 if (iExtensionPos >= 0) 692 secretName += key.substring(iExtensionPos); 693 return secretName; 694 } 695 main(String[] args)696 public static void main(String[] args) { 697 System.out.println(secretFileName("c:\\temp\\hello there.txt")); 698 System.out.println(secretFileName("hello there.txt")); 699 } 700 } 701