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.jbi4ejb.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.jbi4ejb.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. 85 * @param messages the optional <code>Messages</code> 86 * instance, responsible to apply I18N to 87 * messages logged by <code>logger</code>. It 88 * may be <code>null</code>, so there isn't 89 * I18N on logged messages. 90 * @throws NullPointerException if <code>logger</code> is 91 * <code>null</code>. 92 */ 93 JDK14LoggerAdapter(final Logger logger, final Messages messages) { 94 if (logger == null) { 95 throw new NullPointerException("Log4j logger null"); 96 } 97 98 this.logger = logger; 99 this.messages = messages; 100 } 101 102 /** 103 * Gets the name of this <code>Logger</code>. 104 * 105 * @return the name of this <code>Logger</code> instance. 106 */ 107 public String getName() { 108 return logger.getName(); 109 } 110 111 /** 112 * Indicates if this <code>Logger</code> is applying internationalization 113 * to logged messages. 114 * 115 * @return <code>true</code> if and only if this instance is applying I18N 116 * to logged messages. 117 */ 118 private boolean isI18N() { 119 return (messages != null); 120 } 121 122 /** 123 * Formats the specified message, applying I18N if it is available for this 124 * logger. 125 * 126 * @param format the format string. 127 * @param args the optional arguments. 128 * @return the formatted message, eventually internationalized. 129 */ 130 private String formatMessage(final String format, final Object... args) { 131 String msg; 132 133 if (isI18N()) { 134 if (args.length == 0) { 135 msg = messages.getString(format); 136 } else { 137 msg = messages.getString(format, args); 138 } 139 } else { 140 if (args.length == 0) { 141 msg = format; 142 } else { 143 try { 144 msg = MessageFormat.format(format, args); 145 } catch (IllegalArgumentException e) { 146 msg = format; 147 } 148 } 149 } 150 return msg; 151 } 152 153 /** 154 * Is this logger instance enabled for the DEBUG level? 155 * 156 * @return <code>true</code> if and only if this 157 * <code>org.slf4j.Logger</code> is enabled for level DEBUG. 158 */ 159 public boolean isDebugEnabled() { 160 return logger.isLoggable(Level.FINE); 161 } 162 163 /** 164 * Log a message object at level DEBUG. 165 * 166 * @param msg the message string to be logged. 167 */ 168 public void debug(final String msg) { 169 log(SELF, Level.FINE, msg, null); 170 } 171 172 /** 173 * Log a message at level DEBUG according to the specified format and 174 * argument. 175 * <p> 176 * This form avoids superfluous object creation when the logger is disabled 177 * for level DEBUG. 178 * </p> 179 * 180 * @param format the format string. 181 * @param arg the argument. 182 */ 183 public void debug(final String format, final Object arg) { 184 if (isDebugEnabled()) { 185 String msgStr = MessageFormat.format(format, arg); 186 187 log(SELF, Level.FINE, msgStr, null); 188 } 189 } 190 191 /** 192 * Log a message at level DEBUG according to the specified format and 193 * arguments. 194 * <p> 195 * This form avoids superfluous object creation when the logger is disabled 196 * for the DEBUG level. 197 * </p> 198 * 199 * @param format the format string. 200 * @param arg1 the first argument 201 * @param arg2 the second argument. 202 */ 203 public void debug( 204 final String format, final Object arg1, final Object arg2) { 205 if (isDebugEnabled()) { 206 String msgStr = MessageFormat.format(format, arg1, arg2); 207 208 log(SELF, Level.FINE, msgStr, null); 209 } 210 } 211 212 /** 213 * Log a message at level DEBUG according to the specified format and 214 * arguments. 215 * <p> 216 * This form avoids superfluous object creation when the logger is disabled 217 * for the DEBUG level. 218 * </p> 219 * 220 * @param format the format string. 221 * @param args the arguments. 222 */ 223 public void debug(final String format, final Object[] args) { 224 if (isDebugEnabled()) { 225 String msgStr = MessageFormat.format(format, args); 226 227 log(SELF, Level.FINE, msgStr, null); 228 } 229 } 230 231 /** 232 * Log an exception (throwable) at level DEBUG with an accompanying message. 233 * 234 * @param msg the message accompanying the exception. 235 * @param t the exception (throwable) to log. 236 */ 237 public void debug(final String msg, final Throwable t) { 238 log(SELF, Level.FINE, msg, t); 239 } 240 241 /** 242 * Is this logger instance enabled for the INFO level? 243 * 244 * @return <code>true</code> if and only if this 245 * <code>org.slf4j.Logger</code> is enabled for the INFO level. 246 */ 247 public boolean isInfoEnabled() { 248 return logger.isLoggable(Level.INFO); 249 } 250 251 /** 252 * Log a message object at the INFO level. 253 * 254 * @param msg the message string to be logged. 255 */ 256 public void info(final String msg) { 257 if (isInfoEnabled()) { 258 log(SELF, Level.INFO, formatMessage(msg), null); 259 } 260 } 261 262 /** 263 * Log a message at level INFO according to the specified format and 264 * argument. 265 * <p> 266 * This form avoids superfluous object creation when the logger is disabled 267 * for the INFO level. 268 * </p> 269 * 270 * @param format the format string. 271 * @param arg the argument. 272 */ 273 public void info(final String format, final Object arg) { 274 if (isInfoEnabled()) { 275 log(SELF, Level.INFO, formatMessage(format, arg), null); 276 } 277 } 278 279 /** 280 * Log a message at the INFO level according to the specified format and 281 * arguments. 282 * <p> 283 * This form avoids superfluous object creation when the logger is disabled 284 * for the INFO level. 285 * </p> 286 * 287 * @param format the format string. 288 * @param arg1 the first argument. 289 * @param arg2 the second argument. 290 */ 291 public void info( 292 final String format, final Object arg1, final Object arg2) { 293 if (isInfoEnabled()) { 294 log(SELF, Level.INFO, formatMessage(format, arg1, arg2), null); 295 } 296 } 297 298 /** 299 * Log a message at level INFO according to the specified format and 300 * arguments. 301 * <p> 302 * This form avoids superfluous object creation when the logger is disabled 303 * for the INFO level. 304 * </p> 305 * 306 * @param format the format string. 307 * @param args the arguments. 308 */ 309 public void info(final String format, final Object[] args) { 310 if (isInfoEnabled()) { 311 log(SELF, Level.INFO, formatMessage(format, args), null); 312 } 313 } 314 315 /** 316 * Log an exception (throwable) at the INFO level with an accompanying 317 * message. 318 * 319 * @param msg the message accompanying the exception 320 * @param t the exception (throwable) to log. 321 */ 322 public void info(final String msg, final Throwable t) { 323 if (isInfoEnabled()) { 324 log(SELF, Level.INFO, formatMessage(msg), t); 325 } 326 } 327 328 /** 329 * Is this logger instance enabled for the WARN level? 330 * 331 * @return <code>true</code> if and only if this 332 * <code>org.slf4j.Logger</code> is enabled for the WARN level. 333 */ 334 public boolean isWarnEnabled() { 335 return logger.isLoggable(Level.WARNING); 336 } 337 338 /** 339 * Log a message object at the WARN level. 340 * 341 * @param msg the message string to be logged. 342 */ 343 public void warn(final String msg) { 344 if (isWarnEnabled()) { 345 log(SELF, Level.WARNING, formatMessage(msg), null); 346 } 347 } 348 349 /** 350 * Log a message at the WARN level according to the specified format and 351 * argument. 352 * <p> 353 * This form avoids superfluous object creation when the logger is disabled 354 * for the WARN level. 355 * </p> 356 * 357 * @param format the format string. 358 * @param arg the argument. 359 */ 360 public void warn(final String format, final Object arg) { 361 if (isWarnEnabled()) { 362 log(SELF, Level.WARNING, formatMessage(format, arg), null); 363 } 364 } 365 366 /** 367 * Log a message at the WARN level according to the specified format and 368 * arguments. 369 * <p> 370 * This form avoids superfluous object creation when the logger is disabled 371 * for the WARN level. 372 * </p> 373 * 374 * @param format the format string. 375 * @param arg1 the first argument. 376 * @param arg2 the second argument. 377 */ 378 public void warn( 379 final String format, final Object arg1, final Object arg2) { 380 if (isWarnEnabled()) { 381 log(SELF, Level.WARNING, formatMessage(format, arg1, arg2), null); 382 } 383 } 384 385 /** 386 * Log a message at level WARN according to the specified format and 387 * arguments. 388 * <p> 389 * This form avoids superfluous object creation when the logger is disabled 390 * for the WARN level. 391 * </p> 392 * 393 * @param format the format string. 394 * @param args the arguments. 395 */ 396 public void warn(final String format, final Object[] args) { 397 if (isWarnEnabled()) { 398 log(SELF, Level.WARNING, formatMessage(format, args), null); 399 } 400 } 401 402 /** 403 * Log an exception (throwable) at the WARN level with an accompanying 404 * message. 405 * 406 * @param msg the message accompanying the exception. 407 * @param t the exception (throwable) to log. 408 */ 409 public void warn(final String msg, final Throwable t) { 410 if (isWarnEnabled()) { 411 log(SELF, Level.WARNING, formatMessage(msg), t); 412 } 413 } 414 415 /** 416 * Is this logger instance enabled for level ERROR? 417 * 418 * @return <code>true</code> if and only if this 419 * <code>org.slf4j.Logger</code> is enabled for level ERROR. 420 */ 421 public boolean isErrorEnabled() { 422 return logger.isLoggable(Level.SEVERE); 423 } 424 425 /** 426 * Log a message object at the ERROR level. 427 * 428 * @param msg the message string to be logged. 429 */ 430 public void error(final String msg) { 431 if (isErrorEnabled()) { 432 log(SELF, Level.SEVERE, formatMessage(msg), null); 433 } 434 } 435 436 /** 437 * Log a message at the ERROR level according to the specified format 438 * and argument. 439 * <p> 440 * This form avoids superfluous object creation when the logger is disabled 441 * for the ERROR level. 442 * </p> 443 * 444 * @param format the format string. 445 * @param arg the argument. 446 */ 447 public void error(final String format, final Object arg) { 448 if (isErrorEnabled()) { 449 log(SELF, Level.SEVERE, formatMessage(format, arg), null); 450 } 451 } 452 453 /** 454 * Log a message at the ERROR level according to the specified format and 455 * arguments. 456 * <p> 457 * This form avoids superfluous object creation when the logger is disabled 458 * for the ERROR level. 459 * </p> 460 * 461 * @param format the format string. 462 * @param arg1 the first argument. 463 * @param arg2 the second argument. 464 */ 465 public void error( 466 final String format, final Object arg1, final Object arg2) { 467 if (isErrorEnabled()) { 468 log(SELF, Level.SEVERE, formatMessage(format, arg1, arg2), null); 469 } 470 } 471 472 /** 473 * Log a message at level ERROR according to the specified format and 474 * arguments. 475 * <p> 476 * This form avoids superfluous object creation when the logger is disabled 477 * for the ERROR level. 478 * </p> 479 * 480 * @param format the format string. 481 * @param args the arguments. 482 */ 483 public void error(final String format, final Object[] args) { 484 if (isErrorEnabled()) { 485 log(SELF, Level.SEVERE, formatMessage(format, args), null); 486 } 487 } 488 489 /** 490 * Log an exception (throwable) at the ERROR level with an accompanying 491 * message. 492 * 493 * @param msg the message accompanying the exception. 494 * @param t the exception (throwable) to log. 495 */ 496 public void error(final String msg, final Throwable t) { 497 if (isErrorEnabled()) { 498 log(SELF, Level.SEVERE, formatMessage(msg), t); 499 } 500 } 501 502 /** 503 * Log the message at the specified level with the specified throwable if 504 * any. This method creates a <code>java.util.logging.LogRecord</code> and 505 * fills in caller date before calling this instance's JDK14 logger. 506 * <p> 507 * See bug report #13 for more details. 508 * 509 * @param callerFQCN the fully qualified class name of the <b>caller</b>. 510 * @param level the level. 511 * @param msg the message. 512 * @param t the exception (throwable). 513 */ 514 private void log(final String callerFQCN, final Level level, 515 final String msg, final Throwable t) { 516 517 // Millis and thread are filled by the constructor 518 LogRecord record = new LogRecord(level, msg); 519 520 record.setLoggerName(getName()); 521 record.setThrown(t); 522 fillCallerData(callerFQCN, record); 523 logger.log(record); 524 } 525 526 /** 527 * Fill in caller data if possible. 528 * 529 * @param callerFQCN the fully qualified class name of the <b>caller</b>. 530 * @param record the record to update. 531 */ 532 private static void fillCallerData(final String callerFQCN, 533 final LogRecord record) { 534 StackTraceElement[] steArray = new Throwable().getStackTrace(); 535 int length = steArray.length; 536 int selfIndex = -1; 537 538 for (int i = 0; i < length; i++) { 539 final String className = steArray[i].getClassName(); 540 541 if (className.equals(callerFQCN) || className.equals(SUPER)) { 542 selfIndex = i; 543 break; 544 } 545 } 546 for (int i = selfIndex + 1; i < length; i++) { 547 final String className = steArray[i].getClassName(); 548 549 if (!(className.equals(callerFQCN) || className.equals(SUPER))) { 550 StackTraceElement ste = steArray[i]; 551 552 /* 553 * Setting the class name has the side effect of setting the 554 * needToInferCaller variable to false 555 */ 556 record.setSourceClassName(ste.getClassName()); 557 record.setSourceMethodName(ste.getMethodName()); 558 break; 559 } 560 } 561 } 562 563 /** 564 * Printing method which support for location information. 565 * 566 * @param marker the marker. 567 * @param callerFQCN the fully qualified class name of the <b>caller</b>. 568 * @param level the level. 569 * @param msg the message. 570 * @param t the exception (throwable). 571 */ 572 public void log(final Marker marker, final String callerFQCN, 573 final int level, final String msg, final Throwable t) { 574 Level julLevel; 575 576 switch (level) { 577 case LocationAwareLogger.DEBUG_INT: 578 julLevel = Level.FINE; 579 break; 580 581 case LocationAwareLogger.INFO_INT: 582 julLevel = Level.INFO; 583 break; 584 585 case LocationAwareLogger.WARN_INT: 586 julLevel = Level.WARNING; 587 break; 588 589 case LocationAwareLogger.ERROR_INT: 590 julLevel = Level.SEVERE; 591 break; 592 593 default: 594 throw new IllegalArgumentException( 595 "Level number " + level + " is not recognized."); 596 } 597 log(callerFQCN, julLevel, msg, t); 598 } 599 600 601 // New methods added to those provided by SLF4J: we want to log a formatted 602 // string and a Throwable 603 604 605 /** 606 * Log an exception (throwable) at level DEBUG with an accompanying message 607 * according to the specified format and arguments. 608 * <p> 609 * This form avoids superfluous object creation when the logger is disabled 610 * for the DEBUG level. 611 * </p> 612 * 613 * @param format the format string. 614 * @param args the arguments. 615 * @param t the exception (throwable) to log. 616 */ 617 public void debug( 618 final String format, final Object[] args, final Throwable t) { 619 if (isDebugEnabled()) { 620 String msgStr = MessageFormat.format(format, args); 621 622 log(SELF, Level.FINE, msgStr, t); 623 } 624 } 625 626 /** 627 * Log an exception (throwable) at level INFO with an accompanying message 628 * according to the specified format and arguments. 629 * <p> 630 * This form avoids superfluous object creation when the logger is disabled 631 * for the INFO level. 632 * </p> 633 * 634 * @param format the format string. 635 * @param args the arguments. 636 * @param t the exception (throwable) to log. 637 */ 638 public void info( 639 final String format, final Object[] args, final Throwable t) { 640 if (isInfoEnabled()) { 641 log(SELF, Level.INFO, formatMessage(format, args), t); 642 } 643 } 644 645 /** 646 * Log an exception (throwable) at level WARN with an accompanying message 647 * according to the specified format and arguments. 648 * <p> 649 * This form avoids superfluous object creation when the logger is disabled 650 * for the WARN level. 651 * </p> 652 * 653 * @param format the format string. 654 * @param args the arguments. 655 * @param t the exception (throwable) to log. 656 */ 657 public void warn( 658 final String format, final Object[] args, final Throwable t) { 659 if (isWarnEnabled()) { 660 log(SELF, Level.WARNING, formatMessage(format, args), t); 661 } 662 } 663 664 /** 665 * Log an exception (throwable) at level ERROR with an accompanying message 666 * according to the specified format and arguments. 667 * <p> 668 * This form avoids superfluous object creation when the logger is disabled 669 * for the ERROR level. 670 * </p> 671 * 672 * @param format the format string. 673 * @param args the arguments. 674 * @param t the exception (throwable) to log. 675 */ 676 public void error( 677 final String format, final Object[] args, final Throwable t) { 678 if (isErrorEnabled()) { 679 log(SELF, Level.SEVERE, formatMessage(format, args), t); 680 } 681 } 682 }