001 /* 002 * Copyright 2008-2014 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005 /* 006 * Copyright (C) 2008-2014 UnboundID Corp. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021 package com.unboundid.util; 022 023 024 025 import java.io.Serializable; 026 import java.util.EnumSet; 027 import java.util.Properties; 028 import java.util.Set; 029 import java.util.StringTokenizer; 030 import java.util.logging.Level; 031 import java.util.logging.Logger; 032 033 import com.unboundid.asn1.ASN1Buffer; 034 import com.unboundid.asn1.ASN1Element; 035 import com.unboundid.ldap.protocol.LDAPResponse; 036 import com.unboundid.ldap.sdk.DisconnectType; 037 import com.unboundid.ldap.sdk.Entry; 038 import com.unboundid.ldap.sdk.LDAPConnection; 039 import com.unboundid.ldap.sdk.LDAPRequest; 040 import com.unboundid.ldap.sdk.Version; 041 import com.unboundid.ldif.LDIFRecord; 042 043 import static com.unboundid.util.StaticUtils.*; 044 045 046 047 /** 048 * This class provides a means of enabling and configuring debugging in the LDAP 049 * SDK. 050 * <BR><BR> 051 * Access to debug information can be enabled through applications that use the 052 * SDK by calling the {@code Debug#setEnabled} methods, or it can also be 053 * enabled without any code changes through the use of system properties. In 054 * particular, the {@code Debug#PROPERTY_DEBUG_ENABLED}, 055 * {@code Debug#PROPERTY_DEBUG_LEVEL}, and {@code Debug#PROPERTY_DEBUG_TYPE} 056 * properties may be used to control debugging without the need to alter any 057 * code within the application that uses the SDK. 058 * <BR><BR> 059 * The LDAP SDK debugging subsystem uses the Java logging framework available 060 * through the {@code java.util.logging} package with a logger name of 061 * "{@code com.unboundid.ldap.sdk}". The {@code Debug#getLogger} method may 062 * be used to access the logger instance used by the LDAP SDK. 063 * <BR><BR> 064 * <H2>Example</H2> 065 * The following example demonstrates the process that may be used to enable 066 * debugging within the LDAP SDK and write information about all messages with 067 * a {@code WARNING} level or higher to a specified file: 068 * <PRE> 069 * Debug.setEnabled(true); 070 * Logger logger = Debug.getLogger(); 071 * 072 * FileHandler fileHandler = new FileHandler(logFilePath); 073 * fileHandler.setLevel(Level.WARNING); 074 * logger.addHandler(fileHandler); 075 * </PRE> 076 */ 077 public final class Debug 078 implements Serializable 079 { 080 /** 081 * The name of the system property that will be used to enable debugging in 082 * the UnboundID LDAP SDK for Java. The fully-qualified name for this 083 * property is "{@code com.unboundid.ldap.sdk.debug.enabled}". If it is set, 084 * then it should have a value of either "true" or "false". 085 */ 086 public static final String PROPERTY_DEBUG_ENABLED = 087 "com.unboundid.ldap.sdk.debug.enabled"; 088 089 090 091 /** 092 * The name of the system property that may be used to indicate whether stack 093 * trace information for the thread calling the debug method should be 094 * included in debug log messages. The fully-qualified name for this property 095 * is "{@code com.unboundid.ldap.sdk.debug.includeStackTrace}". If it is set, 096 * then it should have a value of either "true" or "false". 097 */ 098 public static final String PROPERTY_INCLUDE_STACK_TRACE = 099 "com.unboundid.ldap.sdk.debug.includeStackTrace"; 100 101 102 103 /** 104 * The name of the system property that will be used to set the initial level 105 * for the debug logger. The fully-qualified name for this property is 106 * "{@code com.unboundid.ldap.sdk.debug.level}". If it is set, then it should 107 * be one of the strings "{@code SEVERE}", "{@code WARNING}", "{@code INFO}", 108 * "{@code CONFIG}", "{@code FINE}", "{@code FINER}", or "{@code FINEST}". 109 */ 110 public static final String PROPERTY_DEBUG_LEVEL = 111 "com.unboundid.ldap.sdk.debug.level"; 112 113 114 115 /** 116 * The name of the system property that will be used to indicate that 117 * debugging should be enabled for specific types of messages. The 118 * fully-qualified name for this property is 119 * "{@code com.unboundid.ldap.sdk.debug.type}". If it is set, then it should 120 * be a comma-delimited list of the names of the desired debug types. See the 121 * {@code DebugType} enum for the available debug types. 122 */ 123 public static final String PROPERTY_DEBUG_TYPE = 124 "com.unboundid.ldap.sdk.debug.type"; 125 126 127 128 /** 129 * The name that will be used for the Java logger that will actually handle 130 * the debug messages if debugging is enabled. 131 */ 132 public static final String LOGGER_NAME = "com.unboundid.ldap.sdk"; 133 134 135 136 /** 137 * The logger that will be used to handle the debug messages if debugging is 138 * enabled. 139 */ 140 private static final Logger logger = Logger.getLogger(LOGGER_NAME); 141 142 143 144 /** 145 * The serial version UID for this serializable class. 146 */ 147 private static final long serialVersionUID = -6079754380415146030L; 148 149 150 151 // Indicates whether any debugging is currently enabled for the SDK. 152 private static boolean debugEnabled; 153 154 // Indicates whether to capture a thread stack trace whenever a debug message 155 // is logged. 156 private static boolean includeStackTrace; 157 158 // The set of debug types for which debugging is enabled. 159 private static EnumSet<DebugType> debugTypes; 160 161 162 163 static 164 { 165 initialize(System.getProperties()); 166 } 167 168 169 170 /** 171 * Prevent this class from being instantiated. 172 */ 173 private Debug() 174 { 175 // No implementation is required. 176 } 177 178 179 180 /** 181 * Initializes this debugger with the default settings. Debugging will be 182 * disabled, the set of debug types will include all types, and the debug 183 * level will be "ALL". 184 */ 185 public static void initialize() 186 { 187 includeStackTrace = false; 188 debugEnabled = false; 189 debugTypes = EnumSet.allOf(DebugType.class); 190 191 logger.setLevel(Level.ALL); 192 } 193 194 195 196 /** 197 * Initializes this debugger with settings from the provided set of 198 * properties. Any debug setting that isn't configured in the provided 199 * properties will be initialized with its default value. 200 * 201 * @param properties The set of properties to use to initialize this 202 * debugger. 203 */ 204 public static void initialize(final Properties properties) 205 { 206 // First, apply the default values for the properties. 207 initialize(); 208 if ((properties == null) || properties.isEmpty()) 209 { 210 // No properties were provided, so we don't need to do anything. 211 return; 212 } 213 214 final String enabledProp = properties.getProperty(PROPERTY_DEBUG_ENABLED); 215 if ((enabledProp != null) && (enabledProp.length() > 0)) 216 { 217 if (enabledProp.equalsIgnoreCase("true")) 218 { 219 debugEnabled = true; 220 } 221 else if (enabledProp.equalsIgnoreCase("false")) 222 { 223 debugEnabled = false; 224 } 225 else 226 { 227 throw new IllegalArgumentException("Invalid value '" + enabledProp + 228 "' for property " + 229 PROPERTY_DEBUG_ENABLED + 230 ". The value must be either " + 231 "'true' or 'false'."); 232 } 233 } 234 235 final String stackProp = 236 properties.getProperty(PROPERTY_INCLUDE_STACK_TRACE); 237 if ((stackProp != null) && (stackProp.length() > 0)) 238 { 239 if (stackProp.equalsIgnoreCase("true")) 240 { 241 includeStackTrace = true; 242 } 243 else if (stackProp.equalsIgnoreCase("false")) 244 { 245 includeStackTrace = false; 246 } 247 else 248 { 249 throw new IllegalArgumentException("Invalid value '" + stackProp + 250 "' for property " + 251 PROPERTY_INCLUDE_STACK_TRACE + 252 ". The value must be either " + 253 "'true' or 'false'."); 254 } 255 } 256 257 final String typesProp = properties.getProperty(PROPERTY_DEBUG_TYPE); 258 if ((typesProp != null) && (typesProp.length() > 0)) 259 { 260 debugTypes = EnumSet.noneOf(DebugType.class); 261 final StringTokenizer t = new StringTokenizer(typesProp, ", "); 262 while (t.hasMoreTokens()) 263 { 264 final String debugTypeName = t.nextToken(); 265 final DebugType debugType = DebugType.forName(debugTypeName); 266 if (debugType == null) 267 { 268 // Throw a runtime exception to indicate that the debug type is 269 // invalid. 270 throw new IllegalArgumentException("Invalid value '" + debugTypeName + 271 "' for property " + PROPERTY_DEBUG_TYPE + 272 ". Allowed values include: " + 273 DebugType.getTypeNameList() + '.'); 274 } 275 else 276 { 277 debugTypes.add(debugType); 278 } 279 } 280 } 281 282 final String levelProp = properties.getProperty(PROPERTY_DEBUG_LEVEL); 283 if ((levelProp != null) && (levelProp.length() > 0)) 284 { 285 logger.setLevel(Level.parse(levelProp)); 286 } 287 } 288 289 290 291 /** 292 * Retrieves the logger that will be used to write the debug messages. 293 * 294 * @return The logger that will be used to write the debug messages. 295 */ 296 public static Logger getLogger() 297 { 298 return logger; 299 } 300 301 302 303 /** 304 * Indicates whether any form of debugging is enabled. 305 * 306 * @return {@code true} if debugging is enabled, or {@code false} if not. 307 */ 308 public static boolean debugEnabled() 309 { 310 return debugEnabled; 311 } 312 313 314 315 /** 316 * Indicates whether debugging is enabled for messages of the specified debug 317 * type. 318 * 319 * @param debugType The debug type for which to make the determination. 320 * 321 * @return {@code true} if debugging is enabled for messages of the specified 322 * debug type, or {@code false} if not. 323 */ 324 public static boolean debugEnabled(final DebugType debugType) 325 { 326 return (debugEnabled && debugTypes.contains(debugType)); 327 } 328 329 330 331 /** 332 * Specifies whether debugging should be enabled. If it should be, then it 333 * will be enabled for all debug types. 334 * 335 * @param enabled Specifies whether debugging should be enabled. 336 */ 337 public static void setEnabled(final boolean enabled) 338 { 339 debugTypes = EnumSet.allOf(DebugType.class); 340 debugEnabled = enabled; 341 } 342 343 344 345 /** 346 * Specifies whether debugging should be enabled. If it should be, then it 347 * will be enabled for all debug types in the provided set. 348 * 349 * @param enabled Specifies whether debugging should be enabled. 350 * @param types The set of debug types that should be enabled. It may be 351 * {@code null} or empty to indicate that it should be for 352 * all debug types. 353 */ 354 public static void setEnabled(final boolean enabled, 355 final Set<DebugType> types) 356 { 357 if ((types == null) || types.isEmpty()) 358 { 359 debugTypes = EnumSet.allOf(DebugType.class); 360 } 361 else 362 { 363 debugTypes = EnumSet.copyOf(types); 364 } 365 366 debugEnabled = enabled; 367 } 368 369 370 371 /** 372 * Indicates whether log messages should include a stack trace of the thread 373 * that invoked the debug method. 374 * 375 * @return {@code true} if log messages should include a stack trace of the 376 * thread that invoked the debug method, or {@code false} if not. 377 */ 378 public static boolean includeStackTrace() 379 { 380 return includeStackTrace; 381 } 382 383 384 385 /** 386 * Specifies whether log messages should include a stack trace of the thread 387 * that invoked the debug method. 388 * 389 * @param includeStackTrace Indicates whether log messages should include a 390 * stack trace of the thread that invoked the debug 391 * method. 392 */ 393 public static void setIncludeStackTrace(final boolean includeStackTrace) 394 { 395 Debug.includeStackTrace = includeStackTrace; 396 } 397 398 399 400 /** 401 * Retrieves the set of debug types that will be used if debugging is enabled. 402 * 403 * @return The set of debug types that will be used if debugging is enabled. 404 */ 405 public static EnumSet<DebugType> getDebugTypes() 406 { 407 return debugTypes; 408 } 409 410 411 412 /** 413 * Writes debug information about the provided exception, if appropriate. If 414 * it is to be logged, then it will be sent to the underlying logger using the 415 * {@code WARNING} level. 416 * 417 * @param t The exception for which debug information should be written. 418 */ 419 public static void debugException(final Throwable t) 420 { 421 if (debugEnabled && debugTypes.contains(DebugType.EXCEPTION)) 422 { 423 debugException(Level.WARNING, t); 424 } 425 } 426 427 428 429 /** 430 * Writes debug information about the provided exception, if appropriate. 431 * 432 * @param l The log level that should be used for the debug information. 433 * @param t The exception for which debug information should be written. 434 */ 435 public static void debugException(final Level l, final Throwable t) 436 { 437 if (debugEnabled && debugTypes.contains(DebugType.EXCEPTION)) 438 { 439 final StringBuilder buffer = new StringBuilder(); 440 addCommonHeader(buffer, l); 441 buffer.append("caughtException=\""); 442 getStackTrace(t, buffer); 443 buffer.append('"'); 444 445 logger.log(l, buffer.toString(), t); 446 } 447 } 448 449 450 451 /** 452 * Writes debug information to indicate that a connection has been 453 * established, if appropriate. If it is to be logged, then it will be sent 454 * to the underlying logger using the {@code INFO} level. 455 * 456 * @param h The address of the server to which the connection was 457 * established. 458 * @param p The port of the server to which the connection was established. 459 */ 460 public static void debugConnect(final String h, final int p) 461 { 462 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 463 { 464 debugConnect(Level.INFO, h, p, null); 465 } 466 } 467 468 469 470 /** 471 * Writes debug information to indicate that a connection has been 472 * established, if appropriate. 473 * 474 * @param l The log level that should be used for the debug information. 475 * @param h The address of the server to which the connection was 476 * established. 477 * @param p The port of the server to which the connection was established. 478 */ 479 public static void debugConnect(final Level l, final String h, final int p) 480 { 481 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 482 { 483 debugConnect(l, h, p, null); 484 } 485 } 486 487 488 489 /** 490 * Writes debug information to indicate that a connection has been 491 * established, if appropriate. If it is to be logged, then it will be sent 492 * to the underlying logger using the {@code INFO} level. 493 * 494 * @param h The address of the server to which the connection was 495 * established. 496 * @param p The port of the server to which the connection was established. 497 * @param c The connection object for the connection that has been 498 * established. It may be {@code null} for historic reasons, but 499 * should be non-{@code null} in new uses. 500 */ 501 public static void debugConnect(final String h, final int p, 502 final LDAPConnection c) 503 { 504 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 505 { 506 debugConnect(Level.INFO, h, p, c); 507 } 508 } 509 510 511 512 /** 513 * Writes debug information to indicate that a connection has been 514 * established, if appropriate. 515 * 516 * @param l The log level that should be used for the debug information. 517 * @param h The address of the server to which the connection was 518 * established. 519 * @param p The port of the server to which the connection was established. 520 * @param c The connection object for the connection that has been 521 * established. It may be {@code null} for historic reasons, but 522 * should be non-{@code null} in new uses. 523 */ 524 public static void debugConnect(final Level l, final String h, final int p, 525 final LDAPConnection c) 526 { 527 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 528 { 529 final StringBuilder buffer = new StringBuilder(); 530 addCommonHeader(buffer, l); 531 buffer.append("connectedTo=\""); 532 buffer.append(h); 533 buffer.append(':'); 534 buffer.append(p); 535 buffer.append('"'); 536 537 if (c != null) 538 { 539 buffer.append(" connectionID="); 540 buffer.append(c.getConnectionID()); 541 542 final String connectionName = c.getConnectionName(); 543 if (connectionName != null) 544 { 545 buffer.append(" connectionName=\""); 546 buffer.append(connectionName); 547 buffer.append('"'); 548 } 549 550 final String connectionPoolName = c.getConnectionPoolName(); 551 if (connectionPoolName != null) 552 { 553 buffer.append(" connectionPoolName=\""); 554 buffer.append(connectionPoolName); 555 buffer.append('"'); 556 } 557 } 558 559 logger.log(l, buffer.toString()); 560 } 561 } 562 563 564 565 /** 566 * Writes debug information to indicate that a connection has been 567 * terminated, if appropriate. If it is to be logged, then it will be sent 568 * to the underlying logger using the {@code INFO} level. 569 * 570 * @param h The address of the server to which the connection was 571 * established. 572 * @param p The port of the server to which the connection was established. 573 * @param t The disconnect type. 574 * @param m The disconnect message, if available. 575 * @param e The disconnect cause, if available. 576 */ 577 public static void debugDisconnect(final String h, final int p, 578 final DisconnectType t, final String m, 579 final Throwable e) 580 { 581 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 582 { 583 debugDisconnect(Level.INFO, h, p, null, t, m, e); 584 } 585 } 586 587 588 589 /** 590 * Writes debug information to indicate that a connection has been 591 * terminated, if appropriate. 592 * 593 * @param l The log level that should be used for the debug information. 594 * @param h The address of the server to which the connection was 595 * established. 596 * @param p The port of the server to which the connection was established. 597 * @param t The disconnect type. 598 * @param m The disconnect message, if available. 599 * @param e The disconnect cause, if available. 600 */ 601 public static void debugDisconnect(final Level l, final String h, final int p, 602 final DisconnectType t, final String m, 603 final Throwable e) 604 { 605 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 606 { 607 debugDisconnect(l, h, p, null, t, m, e); 608 } 609 } 610 611 612 613 /** 614 * Writes debug information to indicate that a connection has been 615 * terminated, if appropriate. If it is to be logged, then it will be sent 616 * to the underlying logger using the {@code INFO} level. 617 * 618 * @param h The address of the server to which the connection was 619 * established. 620 * @param p The port of the server to which the connection was established. 621 * @param c The connection object for the connection that has been closed. 622 * It may be {@code null} for historic reasons, but should be 623 * non-{@code null} in new uses. 624 * @param t The disconnect type. 625 * @param m The disconnect message, if available. 626 * @param e The disconnect cause, if available. 627 */ 628 public static void debugDisconnect(final String h, final int p, 629 final LDAPConnection c, 630 final DisconnectType t, final String m, 631 final Throwable e) 632 { 633 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 634 { 635 debugDisconnect(Level.INFO, h, p, c, t, m, e); 636 } 637 } 638 639 640 641 /** 642 * Writes debug information to indicate that a connection has been 643 * terminated, if appropriate. 644 * 645 * @param l The log level that should be used for the debug information. 646 * @param h The address of the server to which the connection was 647 * established. 648 * @param p The port of the server to which the connection was established. 649 * @param c The connection object for the connection that has been closed. 650 * It may be {@code null} for historic reasons, but should be 651 * non-{@code null} in new uses. 652 * @param t The disconnect type. 653 * @param m The disconnect message, if available. 654 * @param e The disconnect cause, if available. 655 */ 656 public static void debugDisconnect(final Level l, final String h, final int p, 657 final LDAPConnection c, 658 final DisconnectType t, final String m, 659 final Throwable e) 660 { 661 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 662 { 663 final StringBuilder buffer = new StringBuilder(); 664 addCommonHeader(buffer, l); 665 666 if (c != null) 667 { 668 buffer.append("connectionID="); 669 buffer.append(c.getConnectionID()); 670 671 final String connectionName = c.getConnectionName(); 672 if (connectionName != null) 673 { 674 buffer.append(" connectionName=\""); 675 buffer.append(connectionName); 676 buffer.append('"'); 677 } 678 679 final String connectionPoolName = c.getConnectionPoolName(); 680 if (connectionPoolName != null) 681 { 682 buffer.append(" connectionPoolName=\""); 683 buffer.append(connectionPoolName); 684 buffer.append('"'); 685 } 686 687 buffer.append(' '); 688 } 689 690 buffer.append("disconnectedFrom=\""); 691 buffer.append(h); 692 buffer.append(':'); 693 buffer.append(p); 694 buffer.append("\" disconnectType=\""); 695 buffer.append(t.name()); 696 buffer.append('"'); 697 698 if (m != null) 699 { 700 buffer.append("\" disconnectMessage=\""); 701 buffer.append(m); 702 buffer.append('"'); 703 } 704 705 if (e != null) 706 { 707 buffer.append("\" disconnectCause=\""); 708 getStackTrace(e, buffer); 709 buffer.append('"'); 710 } 711 712 logger.log(l, buffer.toString(), c); 713 } 714 } 715 716 717 718 /** 719 * Writes debug information about the provided request, if appropriate. If 720 * it is to be logged, then it will be sent to the underlying logger using the 721 * {@code INFO} level. 722 * 723 * @param r The LDAP request for which debug information should be written. 724 */ 725 public static void debugLDAPRequest(final LDAPRequest r) 726 { 727 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 728 { 729 debugLDAPRequest(Level.INFO, r, -1, null); 730 } 731 } 732 733 734 735 /** 736 * Writes debug information about the provided request, if appropriate. 737 * 738 * @param l The log level that should be used for the debug information. 739 * @param r The LDAP request for which debug information should be written. 740 */ 741 public static void debugLDAPRequest(final Level l, final LDAPRequest r) 742 { 743 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 744 { 745 debugLDAPRequest(l, r, -1, null); 746 } 747 } 748 749 750 751 /** 752 * Writes debug information about the provided request, if appropriate. If 753 * it is to be logged, then it will be sent to the underlying logger using the 754 * {@code INFO} level. 755 * 756 * @param r The LDAP request for which debug information should be written. 757 * @param i The message ID for the request that will be sent. It may be 758 * negative if no message ID is available. 759 * @param c The connection on which the request will be sent. It may be 760 * {@code null} for historic reasons, but should be 761 * non-{@code null} in new uses. 762 */ 763 public static void debugLDAPRequest(final LDAPRequest r, final int i, 764 final LDAPConnection c) 765 { 766 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 767 { 768 debugLDAPRequest(Level.INFO, r, i, c); 769 } 770 } 771 772 773 774 /** 775 * Writes debug information about the provided request, if appropriate. 776 * 777 * @param l The log level that should be used for the debug information. 778 * @param r The LDAP request for which debug information should be written. 779 * @param i The message ID for the request that will be sent. It may be 780 * negative if no message ID is available. 781 * @param c The connection on which the request will be sent. It may be 782 * {@code null} for historic reasons, but should be 783 * non-{@code null} in new uses. 784 */ 785 public static void debugLDAPRequest(final Level l, final LDAPRequest r, 786 final int i, final LDAPConnection c) 787 { 788 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 789 { 790 final StringBuilder buffer = new StringBuilder(); 791 addCommonHeader(buffer, l); 792 793 if (c != null) 794 { 795 buffer.append("connectionID="); 796 buffer.append(c.getConnectionID()); 797 798 final String connectionName = c.getConnectionName(); 799 if (connectionName != null) 800 { 801 buffer.append(" connectionName=\""); 802 buffer.append(connectionName); 803 buffer.append('"'); 804 } 805 806 final String connectionPoolName = c.getConnectionPoolName(); 807 if (connectionPoolName != null) 808 { 809 buffer.append(" connectionPoolName=\""); 810 buffer.append(connectionPoolName); 811 buffer.append('"'); 812 } 813 814 buffer.append(" connectedTo=\""); 815 buffer.append(c.getConnectedAddress()); 816 buffer.append(':'); 817 buffer.append(c.getConnectedPort()); 818 buffer.append("\" "); 819 } 820 821 if (i >= 0) 822 { 823 buffer.append(" messageID="); 824 buffer.append(i); 825 buffer.append(' '); 826 } 827 828 buffer.append("sendingLDAPRequest=\""); 829 r.toString(buffer); 830 buffer.append('"'); 831 832 logger.log(l, buffer.toString()); 833 } 834 } 835 836 837 838 /** 839 * Writes debug information about the provided result, if appropriate. If 840 * it is to be logged, then it will be sent to the underlying logger using the 841 * {@code INFO} level. 842 * 843 * @param r The result for which debug information should be written. 844 */ 845 public static void debugLDAPResult(final LDAPResponse r) 846 { 847 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 848 { 849 debugLDAPResult(Level.INFO, r, null); 850 } 851 } 852 853 854 855 /** 856 * Writes debug information about the provided result, if appropriate. 857 * 858 * @param l The log level that should be used for the debug information. 859 * @param r The result for which debug information should be written. 860 */ 861 public static void debugLDAPResult(final Level l, final LDAPResponse r) 862 { 863 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 864 { 865 debugLDAPResult(l, r, null); 866 } 867 } 868 869 870 871 /** 872 * Writes debug information about the provided result, if appropriate. If 873 * it is to be logged, then it will be sent to the underlying logger using the 874 * {@code INFO} level. 875 * 876 * @param r The result for which debug information should be written. 877 * @param c The connection on which the response was received. It may be 878 * {@code null} for historic reasons, but should be 879 * non-{@code null} in new uses. 880 */ 881 public static void debugLDAPResult(final LDAPResponse r, 882 final LDAPConnection c) 883 { 884 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 885 { 886 debugLDAPResult(Level.INFO, r, c); 887 } 888 } 889 890 891 892 /** 893 * Writes debug information about the provided result, if appropriate. 894 * 895 * @param l The log level that should be used for the debug information. 896 * @param r The result for which debug information should be written. 897 * @param c The connection on which the response was received. It may be 898 * {@code null} for historic reasons, but should be 899 * non-{@code null} in new uses. 900 */ 901 public static void debugLDAPResult(final Level l, final LDAPResponse r, 902 final LDAPConnection c) 903 { 904 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 905 { 906 final StringBuilder buffer = new StringBuilder(); 907 addCommonHeader(buffer, l); 908 909 if (c != null) 910 { 911 buffer.append("connectionID="); 912 buffer.append(c.getConnectionID()); 913 914 final String connectionName = c.getConnectionName(); 915 if (connectionName != null) 916 { 917 buffer.append(" connectionName=\""); 918 buffer.append(connectionName); 919 buffer.append('"'); 920 } 921 922 final String connectionPoolName = c.getConnectionPoolName(); 923 if (connectionPoolName != null) 924 { 925 buffer.append(" connectionPoolName=\""); 926 buffer.append(connectionPoolName); 927 buffer.append('"'); 928 } 929 930 buffer.append(" connectedTo=\""); 931 buffer.append(c.getConnectedAddress()); 932 buffer.append(':'); 933 buffer.append(c.getConnectedPort()); 934 buffer.append("\" "); 935 } 936 937 buffer.append("readLDAPResult=\""); 938 r.toString(buffer); 939 buffer.append('"'); 940 941 logger.log(l, buffer.toString()); 942 } 943 } 944 945 946 947 /** 948 * Writes debug information about the provided ASN.1 element to be written, 949 * if appropriate. If it is to be logged, then it will be sent to the 950 * underlying logger using the {@code INFO} level. 951 * 952 * @param e The ASN.1 element for which debug information should be written. 953 */ 954 public static void debugASN1Write(final ASN1Element e) 955 { 956 if (debugEnabled && debugTypes.contains(DebugType.ASN1)) 957 { 958 debugASN1Write(Level.INFO, e); 959 } 960 } 961 962 963 964 /** 965 * Writes debug information about the provided ASN.1 element to be written, 966 * if appropriate. 967 * 968 * @param l The log level that should be used for the debug information. 969 * @param e The ASN.1 element for which debug information should be written. 970 */ 971 public static void debugASN1Write(final Level l, final ASN1Element e) 972 { 973 if (debugEnabled && debugTypes.contains(DebugType.ASN1)) 974 { 975 final StringBuilder buffer = new StringBuilder(); 976 addCommonHeader(buffer, l); 977 buffer.append("writingASN1Element=\""); 978 e.toString(buffer); 979 buffer.append('"'); 980 981 logger.log(l, buffer.toString()); 982 } 983 } 984 985 986 987 /** 988 * Writes debug information about the provided ASN.1 element to be written, 989 * if appropriate. If it is to be logged, then it will be sent to the 990 * underlying logger using the {@code INFO} level. 991 * 992 * @param b The ASN.1 buffer with the information to be written. 993 */ 994 public static void debugASN1Write(final ASN1Buffer b) 995 { 996 if (debugEnabled && debugTypes.contains(DebugType.ASN1)) 997 { 998 debugASN1Write(Level.INFO, b); 999 } 1000 } 1001 1002 1003 1004 /** 1005 * Writes debug information about the provided ASN.1 element to be written, 1006 * if appropriate. 1007 * 1008 * @param l The log level that should be used for the debug information. 1009 * @param b The ASN1Buffer with the information to be written. 1010 */ 1011 public static void debugASN1Write(final Level l, final ASN1Buffer b) 1012 { 1013 if (debugEnabled && debugTypes.contains(DebugType.ASN1)) 1014 { 1015 final StringBuilder buffer = new StringBuilder(); 1016 addCommonHeader(buffer, l); 1017 buffer.append("writingASN1Element=\""); 1018 toHex(b.toByteArray(), buffer); 1019 buffer.append('"'); 1020 1021 logger.log(l, buffer.toString()); 1022 } 1023 } 1024 1025 1026 1027 /** 1028 * Writes debug information about the provided ASN.1 element that was read, if 1029 * appropriate. If it is to be logged, then it will be sent to the underlying 1030 * logger using the {@code INFO} level. 1031 * 1032 * @param e The ASN.1 element for which debug information should be written. 1033 */ 1034 public static void debugASN1Read(final ASN1Element e) 1035 { 1036 if (debugEnabled && debugTypes.contains(DebugType.ASN1)) 1037 { 1038 debugASN1Read(Level.INFO, e); 1039 } 1040 } 1041 1042 1043 1044 /** 1045 * Writes debug information about the provided ASN.1 element that was read, if 1046 * appropriate. 1047 * 1048 * @param l The log level that should be used for the debug information. 1049 * @param e The ASN.1 element for which debug information should be written. 1050 */ 1051 public static void debugASN1Read(final Level l, final ASN1Element e) 1052 { 1053 if (debugEnabled && debugTypes.contains(DebugType.ASN1)) 1054 { 1055 final StringBuilder buffer = new StringBuilder(); 1056 addCommonHeader(buffer, l); 1057 buffer.append("readASN1Element=\""); 1058 e.toString(buffer); 1059 buffer.append('"'); 1060 1061 logger.log(l, buffer.toString()); 1062 } 1063 } 1064 1065 1066 1067 /** 1068 * Writes debug information about the provided LDIF record to be written, if 1069 * if appropriate. If it is to be logged, then it will be sent to the 1070 * underlying logger using the {@code INFO} level. 1071 * 1072 * @param r The LDIF record for which debug information should be written. 1073 */ 1074 public static void debugLDIFWrite(final LDIFRecord r) 1075 { 1076 if (debugEnabled && debugTypes.contains(DebugType.LDIF)) 1077 { 1078 debugLDIFWrite(Level.INFO, r); 1079 } 1080 } 1081 1082 1083 1084 /** 1085 * Writes debug information about the provided LDIF record to be written, if 1086 * appropriate. 1087 * 1088 * @param l The log level that should be used for the debug information. 1089 * @param r The LDIF record for which debug information should be written. 1090 */ 1091 public static void debugLDIFWrite(final Level l, final LDIFRecord r) 1092 { 1093 if (debugEnabled && debugTypes.contains(DebugType.LDIF)) 1094 { 1095 final StringBuilder buffer = new StringBuilder(); 1096 addCommonHeader(buffer, l); 1097 buffer.append("writingLDIFRecord=\""); 1098 r.toString(buffer); 1099 buffer.append('"'); 1100 1101 logger.log(l, buffer.toString()); 1102 } 1103 } 1104 1105 1106 1107 /** 1108 * Writes debug information about the provided record read from LDIF, if 1109 * appropriate. If it is to be logged, then it will be sent to the underlying 1110 * logger using the {@code INFO} level. 1111 * 1112 * @param r The LDIF record for which debug information should be written. 1113 */ 1114 public static void debugLDIFRead(final LDIFRecord r) 1115 { 1116 if (debugEnabled && debugTypes.contains(DebugType.LDIF)) 1117 { 1118 debugLDIFRead(Level.INFO, r); 1119 } 1120 } 1121 1122 1123 1124 /** 1125 * Writes debug information about the provided record read from LDIF, if 1126 * appropriate. 1127 * 1128 * @param l The log level that should be used for the debug information. 1129 * @param r The LDIF record for which debug information should be written. 1130 */ 1131 public static void debugLDIFRead(final Level l, final LDIFRecord r) 1132 { 1133 if (debugEnabled && debugTypes.contains(DebugType.LDIF)) 1134 { 1135 final StringBuilder buffer = new StringBuilder(); 1136 addCommonHeader(buffer, l); 1137 buffer.append("readLDIFRecord=\""); 1138 r.toString(buffer); 1139 buffer.append('"'); 1140 1141 logger.log(l, buffer.toString()); 1142 } 1143 } 1144 1145 1146 1147 /** 1148 * Writes debug information about monitor entry parsing. If it is to be 1149 * logged, then it will be sent to the underlying logger using the 1150 * {@code FINE} level. 1151 * 1152 * @param e The entry containing the monitor information being parsed. 1153 * @param m The message to be written to the debug logger. 1154 */ 1155 public static void debugMonitor(final Entry e, final String m) 1156 { 1157 if (debugEnabled && debugTypes.contains(DebugType.MONITOR)) 1158 { 1159 debugMonitor(Level.FINE, e, m); 1160 } 1161 } 1162 1163 1164 1165 /** 1166 * Writes debug information about monitor entry parsing, if appropriate. 1167 * 1168 * @param l The log level that should be used for the debug information. 1169 * @param e The entry containing the monitor information being parsed. 1170 * @param m The message to be written to the debug logger. 1171 */ 1172 public static void debugMonitor(final Level l, final Entry e, final String m) 1173 { 1174 if (debugEnabled && debugTypes.contains(DebugType.MONITOR)) 1175 { 1176 final StringBuilder buffer = new StringBuilder(); 1177 addCommonHeader(buffer, l); 1178 buffer.append("monitorEntryDN=\""); 1179 buffer.append(e.getDN()); 1180 buffer.append("\" message=\""); 1181 buffer.append(m); 1182 buffer.append('"'); 1183 1184 logger.log(l, buffer.toString()); 1185 } 1186 } 1187 1188 1189 1190 /** 1191 * Writes debug information about a coding error detected in the use of the 1192 * LDAP SDK. If it is to be logged, then it will be sent to the underlying 1193 * logger using the {@code SEVERE} level. 1194 * 1195 * @param t The {@code Throwable} object that was created and will be thrown 1196 * as a result of the coding error. 1197 */ 1198 public static void debugCodingError(final Throwable t) 1199 { 1200 if (debugEnabled && debugTypes.contains(DebugType.CODING_ERROR)) 1201 { 1202 final StringBuilder buffer = new StringBuilder(); 1203 addCommonHeader(buffer, Level.SEVERE); 1204 buffer.append("codingError=\""); 1205 getStackTrace(t, buffer); 1206 buffer.append('"'); 1207 1208 logger.log(Level.SEVERE, buffer.toString()); 1209 } 1210 } 1211 1212 1213 1214 /** 1215 * Writes a generic debug message, if appropriate. 1216 * 1217 * @param l The log level that should be used for the debug information. 1218 * @param t The debug type to use to determine whether to write the message. 1219 * @param m The message to be written. 1220 */ 1221 public static void debug(final Level l, final DebugType t, final String m) 1222 { 1223 if (debugEnabled && debugTypes.contains(t)) 1224 { 1225 final StringBuilder buffer = new StringBuilder(); 1226 addCommonHeader(buffer, l); 1227 buffer.append("message=\""); 1228 buffer.append(m); 1229 buffer.append('"'); 1230 1231 logger.log(l, buffer.toString()); 1232 } 1233 } 1234 1235 1236 1237 /** 1238 * Writes a generic debug message, if appropriate. 1239 * 1240 * @param l The log level that should be used for the debug information. 1241 * @param t The debug type to use to determine whether to write the message. 1242 * @param m The message to be written. 1243 * @param e An exception to include with the log message. 1244 */ 1245 public static void debug(final Level l, final DebugType t, final String m, 1246 final Throwable e) 1247 { 1248 if (debugEnabled && debugTypes.contains(t)) 1249 { 1250 final StringBuilder buffer = new StringBuilder(); 1251 addCommonHeader(buffer, l); 1252 buffer.append("message=\""); 1253 buffer.append(m); 1254 buffer.append('"'); 1255 buffer.append(" exception=\""); 1256 getStackTrace(e, buffer); 1257 buffer.append('"'); 1258 1259 logger.log(l, buffer.toString(), e); 1260 } 1261 } 1262 1263 1264 1265 /** 1266 * Writes common header information to the provided buffer. It will include 1267 * the thread ID, name, and caller stack trace (optional), and it will be 1268 * followed by a trailing space. 1269 * 1270 * @param buffer The buffer to which the information should be appended. 1271 * @param level The log level for the message that will be written. 1272 */ 1273 private static void addCommonHeader(final StringBuilder buffer, 1274 final Level level) 1275 { 1276 buffer.append("level=\""); 1277 buffer.append(level.getName()); 1278 buffer.append("\" threadID="); 1279 buffer.append(Thread.currentThread().getId()); 1280 buffer.append(" threadName=\""); 1281 buffer.append(Thread.currentThread().getName()); 1282 1283 if (includeStackTrace) 1284 { 1285 buffer.append("\" calledFrom=\""); 1286 1287 boolean appended = false; 1288 boolean foundDebug = false; 1289 for (final StackTraceElement e : Thread.currentThread().getStackTrace()) 1290 { 1291 final String className = e.getClassName(); 1292 if (className.equals(Debug.class.getName())) 1293 { 1294 foundDebug = true; 1295 } 1296 else if (foundDebug) 1297 { 1298 if (appended) 1299 { 1300 buffer.append(" / "); 1301 } 1302 appended = true; 1303 1304 buffer.append(e.getMethodName()); 1305 buffer.append('('); 1306 buffer.append(e.getFileName()); 1307 1308 final int lineNumber = e.getLineNumber(); 1309 if (lineNumber > 0) 1310 { 1311 buffer.append(':'); 1312 buffer.append(lineNumber); 1313 } 1314 else if (e.isNativeMethod()) 1315 { 1316 buffer.append(":native"); 1317 } 1318 1319 buffer.append(')'); 1320 } 1321 } 1322 } 1323 1324 buffer.append("\" revision="); 1325 buffer.append(Version.REVISION_NUMBER); 1326 buffer.append(' '); 1327 } 1328 }