1 /* 2 * Copyright (c) 2004-2005 SLF4J.ORG 3 * Copyright (c) 2004-2005 QOS.ch 4 * 5 * All rights reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining 8 * a copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, and/or sell copies of the Software, and to permit persons 12 * to whom the Software is furnished to do so, provided that the above 13 * copyright notice(s) and this permission notice appear in all copies of 14 * the Software and that both the above copyright notice(s) and this 15 * permission notice appear in supporting documentation. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 20 * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 21 * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY 22 * SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER 23 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF 24 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 25 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 26 * 27 * Except as contained in this notice, the name of a copyright holder 28 * shall not be used in advertising or otherwise to promote the sale, use 29 * or other dealings in this Software without prior written authorization 30 * of the copyright holder. 31 */ 32 33 34 package org.slf4j.impl; 35 36 import it.imolinfo.jbi4cics.jbi.Messages; 37 import java.text.MessageFormat; 38 import java.util.logging.Level; 39 import java.util.logging.LogRecord; 40 import java.util.logging.Logger; 41 import org.slf4j.Marker; 42 import org.slf4j.helpers.MarkerIgnoringBase; 43 import org.slf4j.spi.LocationAwareLogger; 44 45 /** 46 * A wrapper over {@link java.util.logging.Logger} in conformity with the 47 * {@link org.slf4j.Logger} interface. Note that the logging levels mentioned in 48 * this class refer to those defined in the <code>java.util.logging</code> 49 * package. 50 * <p> 51 * 52 * @author Ceki Gülcü 53 * @author Peter Royal 54 * @author <a href="mailto:acannone@imolinfo.it">Amedeo Cannone</a> 55 * @author <a href="mailto:mcimatti@imolinfo.it">Marco Cimatti</a> 56 */ 57 final class JDK14LoggerAdapter extends MarkerIgnoringBase 58 implements LocationAwareLogger, it.imolinfo.jbi4cics.Logger { 59 60 /** 61 * This class name. 62 */ 63 private static final String SELF = JDK14LoggerAdapter.class.getName(); 64 65 /** 66 * The super-class name of this class. 67 */ 68 private static final String SUPER = MarkerIgnoringBase.class.getName(); 69 70 /** 71 * The logger adapted by this instance. 72 */ 73 private final Logger logger; 74 75 /** 76 * The optional <code>Messages</code> available to apply I18N to logged 77 * messages. 78 */ 79 private final Messages messages; 80 81 /** 82 * Creates a new adapter for the specificed logger. 83 * 84 * @param logger the logger. Must be not <code>null</code>. 85 * @param messages the optional <code>Messages</code> instance, 86 * responsible to apply I18N to messages logged by 87 * <code>logger</code>. It may be <code>null</code>, so 88 * there isn't I18N on logged messages. 89 */ 90 JDK14LoggerAdapter(final Logger logger, final Messages messages) { 91 this.logger = logger; 92 this.messages = messages; 93 } 94 95 /** 96 * Gets the name of this <code>Logger</code>. 97 * 98 * @return the name of this <code>Logger</code> instance. 99 */ 100 public String getName() { 101 return logger.getName(); 102 } 103 104 /** 105 * Indicates if this <code>Logger</code> is applying internationalization 106 * to logged messages. 107 * 108 * @return <code>true</code> if and only if this instance is applying I18N 109 * to logged messages. 110 */ 111 private boolean isI18N() { 112 return (messages != null); 113 } 114 115 /** 116 * Formats the specified message, applying I18N if it is available for this 117 * logger. 118 * 119 * @param format the format string. 120 * @param args the optional arguments. 121 * @return the formatted message, eventually internationalized. 122 */ 123 private String formatMessage(final String format, final Object... args) { 124 String msg; 125 126 if (isI18N()) { 127 if (args.length == 0) { 128 msg = messages.getString(format); 129 } else { 130 msg = messages.getString(format, args); 131 } 132 } else { 133 if (args.length == 0) { 134 msg = format; 135 } else { 136 try { 137 msg = MessageFormat.format(format, args); 138 } catch (IllegalArgumentException e) { 139 msg = format; 140 } 141 } 142 } 143 return msg; 144 } 145 146 /** 147 * Is this logger instance enabled for the DEBUG level? 148 * 149 * @return <code>true</code> if and only if this 150 * <code>org.slf4j.Logger</code> is enabled for level DEBUG. 151 */ 152 public boolean isDebugEnabled() { 153 return logger.isLoggable(Level.FINE); 154 } 155 156 /** 157 * Log a message object at level DEBUG. 158 * 159 * @param msg the message string to be logged. 160 */ 161 public void debug(final String msg) { 162 log(SELF, Level.FINE, msg, null); 163 } 164 165 /** 166 * Log a message at level DEBUG according to the specified format and 167 * argument. 168 * <p> 169 * This form avoids superfluous object creation when the logger is disabled 170 * for level DEBUG. 171 * </p> 172 * 173 * @param format the format string. 174 * @param arg the argument. 175 */ 176 public void debug(final String format, final Object arg) { 177 if (isDebugEnabled()) { 178 179 // Debug level -> no I18N, argument formatting only 180 String msgStr = MessageFormat.format(format, arg); 181 182 log(SELF, Level.FINE, msgStr, null); 183 } 184 } 185 186 /** 187 * Log a message at level DEBUG according to the specified format and 188 * arguments. 189 * <p> 190 * This form avoids superfluous object creation when the logger is disabled 191 * for the DEBUG level. 192 * </p> 193 * 194 * @param format the format string. 195 * @param arg1 the first argument 196 * @param arg2 the second argument. 197 */ 198 public void debug( 199 final String format, final Object arg1, final Object arg2) { 200 if (isDebugEnabled()) { 201 202 // Debug level -> no I18N, argument formatting only 203 String msgStr = MessageFormat.format(format, arg1, arg2); 204 205 log(SELF, Level.FINE, msgStr, null); 206 } 207 } 208 209 /** 210 * Log a message at level DEBUG according to the specified format and 211 * arguments. 212 * <p> 213 * This form avoids superfluous object creation when the logger is disabled 214 * for the DEBUG level. 215 * </p> 216 * 217 * @param format the format string. 218 * @param args the arguments. 219 */ 220 public void debug(final String format, final Object[] args) { 221 if (isDebugEnabled()) { 222 223 // Debug level -> no I18N, argument formatting only 224 String msgStr = MessageFormat.format(format, args); 225 226 log(SELF, Level.FINE, msgStr, null); 227 } 228 } 229 230 /** 231 * Log an exception (throwable) at level DEBUG with an accompanying message. 232 * 233 * @param msg the message accompanying the exception. 234 * @param t the exception (throwable) to log. 235 */ 236 public void debug(final String msg, final Throwable t) { 237 log(SELF, Level.FINE, msg, t); 238 } 239 240 /** 241 * Is this logger instance enabled for the INFO level? 242 * 243 * @return <code>true</code> if and only if this 244 * <code>org.slf4j.Logger</code> is enabled for the INFO level. 245 */ 246 public boolean isInfoEnabled() { 247 return logger.isLoggable(Level.INFO); 248 } 249 250 /** 251 * Log a message object at the INFO level. 252 * 253 * @param msg the message string to be logged. 254 */ 255 public void info(final String msg) { 256 if (isInfoEnabled()) { 257 log(SELF, Level.INFO, formatMessage(msg), null); 258 } 259 } 260 261 /** 262 * Log a message at level INFO according to the specified format and 263 * argument. 264 * <p> 265 * This form avoids superfluous object creation when the logger is disabled 266 * for the INFO level. 267 * </p> 268 * 269 * @param format the format string. 270 * @param arg the argument. 271 */ 272 public void info(final String format, final Object arg) { 273 if (isInfoEnabled()) { 274 log(SELF, Level.INFO, formatMessage(format, arg), null); 275 } 276 } 277 278 /** 279 * Log a message at the INFO level according to the specified format and 280 * arguments. 281 * <p> 282 * This form avoids superfluous object creation when the logger is disabled 283 * for the INFO level. 284 * </p> 285 * 286 * @param format the format string. 287 * @param arg1 the first argument. 288 * @param arg2 the second argument. 289 */ 290 public void info( 291 final String format, final Object arg1, final Object arg2) { 292 if (isInfoEnabled()) { 293 log(SELF, Level.INFO, formatMessage(format, arg1, arg2), null); 294 } 295 } 296 297 /** 298 * Log a message at level INFO according to the specified format and 299 * arguments. 300 * <p> 301 * This form avoids superfluous object creation when the logger is disabled 302 * for the INFO level. 303 * </p> 304 * 305 * @param format the format string. 306 * @param args the arguments. 307 */ 308 public void info(final String format, final Object[] args) { 309 if (isInfoEnabled()) { 310 log(SELF, Level.INFO, formatMessage(format, args), null); 311 } 312 } 313 314 /** 315 * Log an exception (throwable) at the INFO level with an accompanying 316 * message. 317 * 318 * @param msg the message accompanying the exception 319 * @param t the exception (throwable) to log. 320 */ 321 public void info(final String msg, final Throwable t) { 322 if (isInfoEnabled()) { 323 log(SELF, Level.INFO, formatMessage(msg), t); 324 } 325 } 326 327 /** 328 * Is this logger instance enabled for the WARN level? 329 * 330 * @return <code>true</code> if and only if this 331 * <code>org.slf4j.Logger</code> is enabled for the WARN level. 332 */ 333 public boolean isWarnEnabled() { 334 return logger.isLoggable(Level.WARNING); 335 } 336 337 /** 338 * Log a message object at the WARN level. 339 * 340 * @param msg the message string to be logged. 341 */ 342 public void warn(final String msg) { 343 if (isWarnEnabled()) { 344 log(SELF, Level.WARNING, formatMessage(msg), null); 345 } 346 } 347 348 /** 349 * Log a message at the WARN level according to the specified format and 350 * argument. 351 * <p> 352 * This form avoids superfluous object creation when the logger is disabled 353 * for the WARN level. 354 * </p> 355 * 356 * @param format the format string. 357 * @param arg the argument. 358 */ 359 public void warn(final String format, final Object arg) { 360 if (isWarnEnabled()) { 361 log(SELF, Level.WARNING, formatMessage(format, arg), null); 362 } 363 } 364 365 /** 366 * Log a message at the WARN level according to the specified format and 367 * arguments. 368 * <p> 369 * This form avoids superfluous object creation when the logger is disabled 370 * for the WARN level. 371 * </p> 372 * 373 * @param format the format string. 374 * @param arg1 the first argument. 375 * @param arg2 the second argument. 376 */ 377 public void warn( 378 final String format, final Object arg1, final Object arg2) { 379 if (isWarnEnabled()) { 380 log(SELF, Level.WARNING, formatMessage(format, arg1, arg2), null); 381 } 382 } 383 384 /** 385 * Log a message at level WARN according to the specified format and 386 * arguments. 387 * <p> 388 * This form avoids superfluous object creation when the logger is disabled 389 * for the WARN level. 390 * </p> 391 * 392 * @param format the format string. 393 * @param args the arguments. 394 */ 395 public void warn(final String format, final Object[] args) { 396 if (isWarnEnabled()) { 397 log(SELF, Level.WARNING, formatMessage(format, args), null); 398 } 399 } 400 401 /** 402 * Log an exception (throwable) at the WARN level with an accompanying 403 * message. 404 * 405 * @param msg the message accompanying the exception. 406 * @param t the exception (throwable) to log. 407 */ 408 public void warn(final String msg, final Throwable t) { 409 if (isWarnEnabled()) { 410 log(SELF, Level.WARNING, formatMessage(msg), t); 411 } 412 } 413 414 /** 415 * Is this logger instance enabled for level ERROR? 416 * 417 * @return <code>true</code> if and only if this 418 * <code>org.slf4j.Logger</code> is enabled for level ERROR. 419 */ 420 public boolean isErrorEnabled() { 421 return logger.isLoggable(Level.SEVERE); 422 } 423 424 /** 425 * Log a message object at the ERROR level. 426 * 427 * @param msg the message string to be logged. 428 */ 429 public void error(final String msg) { 430 if (isErrorEnabled()) { 431 log(SELF, Level.SEVERE, formatMessage(msg), null); 432 } 433 } 434 435 /** 436 * Log a message at the ERROR level according to the specified format 437 * and argument. 438 * <p> 439 * This form avoids superfluous object creation when the logger is disabled 440 * for the ERROR level. 441 * </p> 442 * 443 * @param format the format string. 444 * @param arg the argument. 445 */ 446 public void error(final String format, final Object arg) { 447 if (isErrorEnabled()) { 448 log(SELF, Level.SEVERE, formatMessage(format, arg), null); 449 } 450 } 451 452 /** 453 * Log a message at the ERROR level according to the specified format and 454 * arguments. 455 * <p> 456 * This form avoids superfluous object creation when the logger is disabled 457 * for the ERROR level. 458 * </p> 459 * 460 * @param format the format string. 461 * @param arg1 the first argument. 462 * @param arg2 the second argument. 463 */ 464 public void error( 465 final String format, final Object arg1, final Object arg2) { 466 if (isErrorEnabled()) { 467 log(SELF, Level.SEVERE, formatMessage(format, arg1, arg2), null); 468 } 469 } 470 471 /** 472 * Log a message at level ERROR according to the specified format and 473 * arguments. 474 * <p> 475 * This form avoids superfluous object creation when the logger is disabled 476 * for the ERROR level. 477 * </p> 478 * 479 * @param format the format string. 480 * @param args the arguments. 481 */ 482 public void error(final String format, final Object[] args) { 483 if (isErrorEnabled()) { 484 log(SELF, Level.SEVERE, formatMessage(format, args), null); 485 } 486 } 487 488 /** 489 * Log an exception (throwable) at the ERROR level with an accompanying 490 * message. 491 * 492 * @param msg the message accompanying the exception. 493 * @param t the exception (throwable) to log. 494 */ 495 public void error(final String msg, final Throwable t) { 496 if (isErrorEnabled()) { 497 log(SELF, Level.SEVERE, formatMessage(msg), t); 498 } 499 } 500 501 /** 502 * Log the message at the specified level with the specified throwable if 503 * any. This method creates a <code>java.util.logging.LogRecord</code> and 504 * fills in caller date before calling this instance's JDK14 logger. 505 * <p> 506 * See bug report #13 for more details. 507 * 508 * @param callerFQCN the fully qualified class name of the <b>caller</b>. 509 * @param level the level. 510 * @param msg the message. 511 * @param t the exception (throwable). 512 */ 513 private void log(final String callerFQCN, final Level level, 514 final String msg, final Throwable t) { 515 516 // Millis and thread are filled by the constructor 517 LogRecord record = new LogRecord(level, msg); 518 519 record.setLoggerName(getName()); 520 record.setThrown(t); 521 fillCallerData(callerFQCN, record); 522 logger.log(record); 523 } 524 525 /** 526 * Fill in caller data if possible. 527 * 528 * @param callerFQCN the fully qualified class name of the <b>caller</b>. 529 * @param record the record to update. 530 */ 531 private static void fillCallerData(final String callerFQCN, 532 final LogRecord record) { 533 StackTraceElement[] steArray = new Throwable().getStackTrace(); 534 int length = steArray.length; 535 int selfIndex = -1; 536 537 for (int i = 0; i < length; i++) { 538 final String className = steArray[i].getClassName(); 539 540 if (className.equals(callerFQCN) || className.equals(SUPER)) { 541 selfIndex = i; 542 break; 543 } 544 } 545 for (int i = selfIndex + 1; i < length; i++) { 546 final String className = steArray[i].getClassName(); 547 548 if (!(className.equals(callerFQCN) || className.equals(SUPER))) { 549 StackTraceElement ste = steArray[i]; 550 551 /* 552 * Setting the class name has the side effect of setting the 553 * needToInferCaller variable to false 554 */ 555 record.setSourceClassName(ste.getClassName()); 556 record.setSourceMethodName(ste.getMethodName()); 557 break; 558 } 559 } 560 } 561 562 /** 563 * Printing method which support for location information. 564 * 565 * @param marker the marker. 566 * @param callerFQCN the fully qualified class name of the <b>caller</b>. 567 * @param level the level. 568 * @param msg the message. 569 * @param t the exception (throwable). 570 */ 571 public void log(final Marker marker, final String callerFQCN, 572 final int level, final String msg, final Throwable t) { 573 Level julLevel; 574 575 switch (level) { 576 case LocationAwareLogger.DEBUG_INT: 577 julLevel = Level.FINE; 578 break; 579 580 case LocationAwareLogger.INFO_INT: 581 julLevel = Level.INFO; 582 break; 583 584 case LocationAwareLogger.WARN_INT: 585 julLevel = Level.WARNING; 586 break; 587 588 case LocationAwareLogger.ERROR_INT: 589 julLevel = Level.SEVERE; 590 break; 591 592 default: 593 throw new IllegalArgumentException( 594 "Level number " + level + " is not recognized."); 595 } 596 log(callerFQCN, julLevel, msg, t); 597 } 598 599 600 // New methods added to those provided by SLF4J: we want to log a formatted 601 // string and a Throwable 602 603 604 /** 605 * Log an exception (throwable) at level DEBUG with an accompanying message 606 * according to the specified format and arguments. 607 * <p> 608 * This form avoids superfluous object creation when the logger is disabled 609 * for the DEBUG level. 610 * </p> 611 * 612 * @param format the format string. 613 * @param args the arguments. 614 * @param t the exception (throwable) to log. 615 */ 616 public void debug( 617 final String format, final Object[] args, final Throwable t) { 618 if (isDebugEnabled()) { 619 String msgStr = MessageFormat.format(format, args); 620 621 log(SELF, Level.FINE, msgStr, t); 622 } 623 } 624 625 /** 626 * Log an exception (throwable) at level INFO with an accompanying message 627 * according to the specified format and arguments. 628 * <p> 629 * This form avoids superfluous object creation when the logger is disabled 630 * for the INFO level. 631 * </p> 632 * 633 * @param format the format string. 634 * @param args the arguments. 635 * @param t the exception (throwable) to log. 636 */ 637 public void info( 638 final String format, final Object[] args, final Throwable t) { 639 if (isInfoEnabled()) { 640 log(SELF, Level.INFO, formatMessage(format, args), t); 641 } 642 } 643 644 /** 645 * Log an exception (throwable) at level WARN with an accompanying message 646 * according to the specified format and arguments. 647 * <p> 648 * This form avoids superfluous object creation when the logger is disabled 649 * for the WARN level. 650 * </p> 651 * 652 * @param format the format string. 653 * @param args the arguments. 654 * @param t the exception (throwable) to log. 655 */ 656 public void warn( 657 final String format, final Object[] args, final Throwable t) { 658 if (isWarnEnabled()) { 659 log(SELF, Level.WARNING, formatMessage(format, args), t); 660 } 661 } 662 663 /** 664 * Log an exception (throwable) at level ERROR with an accompanying message 665 * according to the specified format and arguments. 666 * <p> 667 * This form avoids superfluous object creation when the logger is disabled 668 * for the ERROR level. 669 * </p> 670 * 671 * @param format the format string. 672 * @param args the arguments. 673 * @param t the exception (throwable) to log. 674 */ 675 public void error( 676 final String format, final Object[] args, final Throwable t) { 677 if (isErrorEnabled()) { 678 log(SELF, Level.SEVERE, formatMessage(format, args), t); 679 } 680 } 681 }