1 /* 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.istack.internal.logging; 27 28 import com.sun.istack.internal.NotNull; 29 30 import java.util.StringTokenizer; 31 import java.util.logging.Level; 32 33 /** 34 * This is a helper class that provides some convenience methods wrapped around the 35 * standard {@link java.util.logging.Logger} interface. 36 * 37 * The class also makes sure that logger names of each Metro subsystem are consistent 38 * with each other. 39 * 40 * @author Marek Potociar <marek.potociar at sun.com> 41 * @author Fabian Ritzmann 42 */ 43 public class Logger { 44 45 private static final String WS_LOGGING_SUBSYSTEM_NAME_ROOT = "com.sun.metro"; 46 private static final String ROOT_WS_PACKAGE = "com.sun.xml.internal.ws."; 47 // 48 private static final Level METHOD_CALL_LEVEL_VALUE = Level.FINEST; 49 // 50 private final String componentClassName; 51 private final java.util.logging.Logger logger; 52 53 /** 54 * Prevents creation of a new instance of this Logger unless used by a subclass. 55 */ 56 protected Logger(final String systemLoggerName, final String componentName) { 57 this.componentClassName = "[" + componentName + "] "; 58 this.logger = java.util.logging.Logger.getLogger(systemLoggerName); 59 } 60 61 /** 62 * <p> 63 * The factory method returns preconfigured Logger wrapper for the class. Method calls 64 * {@link #getSystemLoggerName(java.lang.Class)} to generate default logger name. 65 * </p> 66 * <p> 67 * Since there is no caching implemented, it is advised that the method is called only once 68 * per a class in order to initialize a final static logger variable, which is then used 69 * through the class to perform actual logging tasks. 70 * </p> 71 * 72 * @param componentClass class of the component that will use the logger instance. Must not be {@code null}. 73 * @return logger instance preconfigured for use with the component 74 * @throws NullPointerException if the componentClass parameter is {@code null}. 75 */ 76 public static @NotNull Logger getLogger(final @NotNull Class<?> componentClass) { 77 return new Logger(getSystemLoggerName(componentClass), componentClass.getName()); 78 } 79 80 /** 81 * The factory method returns preconfigured Logger wrapper for the class. Since there is no caching implemented, 82 * it is advised that the method is called only once per a class in order to initialize a final static logger variable, 83 * which is then used through the class to perform actual logging tasks. 84 * 85 * This method should be only used in a special cases when overriding of a default logger name derived from the 86 * package of the component class is needed. For all common use cases please use {@link #getLogger(java.lang.Class)} 87 * method. 88 * 89 * @param customLoggerName custom name of the logger. 90 * @param componentClass class of the component that will use the logger instance. Must not be {@code null}. 91 * @return logger instance preconfigured for use with the component 92 * @throws NullPointerException if the componentClass parameter is {@code null}. 93 * 94 * @see #getLogger(java.lang.Class) 95 */ 96 public static @NotNull Logger getLogger(final @NotNull String customLoggerName, final @NotNull Class<?> componentClass) { 97 return new Logger(customLoggerName, componentClass.getName()); 98 } 99 100 /** 101 * Calculates the subsystem suffix based on the package of the component class 102 * @param componentClass class of the component that will use the logger instance. Must not be {@code null}. 103 * @return system logger name for the given {@code componentClass} instance 104 */ 105 static final String getSystemLoggerName(@NotNull Class<?> componentClass) { 106 StringBuilder sb = new StringBuilder(componentClass.getPackage().getName()); 107 final int lastIndexOfWsPackage = sb.lastIndexOf(ROOT_WS_PACKAGE); 108 if (lastIndexOfWsPackage > -1) { 109 sb.replace(0, lastIndexOfWsPackage + ROOT_WS_PACKAGE.length(), ""); 110 111 StringTokenizer st = new StringTokenizer(sb.toString(), "."); 112 sb = new StringBuilder(WS_LOGGING_SUBSYSTEM_NAME_ROOT).append("."); 113 if (st.hasMoreTokens()) { 114 String token = st.nextToken(); 115 if ("api".equals(token)) { 116 token = st.nextToken(); 117 } 118 sb.append(token); 119 } 120 } 121 122 return sb.toString(); 123 } 124 125 public void log(final Level level, final String message) { 126 if (!this.logger.isLoggable(level)) { 127 return; 128 } 129 logger.logp(level, componentClassName, getCallerMethodName(), message); 130 } 131 132 public void log(final Level level, final String message, Object param1) { 133 if (!this.logger.isLoggable(level)) { 134 return; 135 } 136 logger.logp(level, componentClassName, getCallerMethodName(), message, param1); 137 } 138 139 public void log(final Level level, final String message, Object[] params) { 140 if (!this.logger.isLoggable(level)) { 141 return; 142 } 143 logger.logp(level, componentClassName, getCallerMethodName(), message, params); 144 } 145 146 public void log(final Level level, final String message, final Throwable thrown) { 147 if (!this.logger.isLoggable(level)) { 148 return; 149 } 150 logger.logp(level, componentClassName, getCallerMethodName(), message, thrown); 151 } 152 153 public void finest(final String message) { 154 if (!this.logger.isLoggable(Level.FINEST)) { 155 return; 156 } 157 logger.logp(Level.FINEST, componentClassName, getCallerMethodName(), message); 158 } 159 160 public void finest(final String message, Object[] params) { 161 if (!this.logger.isLoggable(Level.FINEST)) { 162 return; 163 } 164 logger.logp(Level.FINEST, componentClassName, getCallerMethodName(), message, params); 165 } 166 167 public void finest(final String message, final Throwable thrown) { 168 if (!this.logger.isLoggable(Level.FINEST)) { 169 return; 170 } 171 logger.logp(Level.FINEST, componentClassName, getCallerMethodName(), message, thrown); 172 } 173 174 public void finer(final String message) { 175 if (!this.logger.isLoggable(Level.FINER)) { 176 return; 177 } 178 logger.logp(Level.FINER, componentClassName, getCallerMethodName(), message); 179 } 180 181 public void finer(final String message, Object[] params) { 182 if (!this.logger.isLoggable(Level.FINER)) { 183 return; 184 } 185 logger.logp(Level.FINER, componentClassName, getCallerMethodName(), message, params); 186 } 187 188 public void finer(final String message, final Throwable thrown) { 189 if (!this.logger.isLoggable(Level.FINER)) { 190 return; 191 } 192 logger.logp(Level.FINER, componentClassName, getCallerMethodName(), message, thrown); 193 } 194 195 public void fine(final String message) { 196 if (!this.logger.isLoggable(Level.FINE)) { 197 return; 198 } 199 logger.logp(Level.FINE, componentClassName, getCallerMethodName(), message); 200 } 201 202 public void fine(final String message, final Throwable thrown) { 203 if (!this.logger.isLoggable(Level.FINE)) { 204 return; 205 } 206 logger.logp(Level.FINE, componentClassName, getCallerMethodName(), message, thrown); 207 } 208 209 public void info(final String message) { 210 if (!this.logger.isLoggable(Level.INFO)) { 211 return; 212 } 213 logger.logp(Level.INFO, componentClassName, getCallerMethodName(), message); 214 } 215 216 public void info(final String message, Object[] params) { 217 if (!this.logger.isLoggable(Level.INFO)) { 218 return; 219 } 220 logger.logp(Level.INFO, componentClassName, getCallerMethodName(), message, params); 221 } 222 223 public void info(final String message, final Throwable thrown) { 224 if (!this.logger.isLoggable(Level.INFO)) { 225 return; 226 } 227 logger.logp(Level.INFO, componentClassName, getCallerMethodName(), message, thrown); 228 } 229 230 public void config(final String message) { 231 if (!this.logger.isLoggable(Level.CONFIG)) { 232 return; 233 } 234 logger.logp(Level.CONFIG, componentClassName, getCallerMethodName(), message); 235 } 236 237 public void config(final String message, Object[] params) { 238 if (!this.logger.isLoggable(Level.CONFIG)) { 239 return; 240 } 241 logger.logp(Level.CONFIG, componentClassName, getCallerMethodName(), message, params); 242 } 243 244 public void config(final String message, final Throwable thrown) { 245 if (!this.logger.isLoggable(Level.CONFIG)) { 246 return; 247 } 248 logger.logp(Level.CONFIG, componentClassName, getCallerMethodName(), message, thrown); 249 } 250 251 public void warning(final String message) { 252 if (!this.logger.isLoggable(Level.WARNING)) { 253 return; 254 } 255 logger.logp(Level.WARNING, componentClassName, getCallerMethodName(), message); 256 } 257 258 public void warning(final String message, Object[] params) { 259 if (!this.logger.isLoggable(Level.WARNING)) { 260 return; 261 } 262 logger.logp(Level.WARNING, componentClassName, getCallerMethodName(), message, params); 263 } 264 265 public void warning(final String message, final Throwable thrown) { 266 if (!this.logger.isLoggable(Level.WARNING)) { 267 return; 268 } 269 logger.logp(Level.WARNING, componentClassName, getCallerMethodName(), message, thrown); 270 } 271 272 public void severe(final String message) { 273 if (!this.logger.isLoggable(Level.SEVERE)) { 274 return; 275 } 276 logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), message); 277 } 278 279 public void severe(final String message, Object[] params) { 280 if (!this.logger.isLoggable(Level.SEVERE)) { 281 return; 282 } 283 logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), message, params); 284 } 285 286 public void severe(final String message, final Throwable thrown) { 287 if (!this.logger.isLoggable(Level.SEVERE)) { 288 return; 289 } 290 logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), message, thrown); 291 } 292 293 public boolean isMethodCallLoggable() { 294 return this.logger.isLoggable(METHOD_CALL_LEVEL_VALUE); 295 } 296 297 public boolean isLoggable(final Level level) { 298 return this.logger.isLoggable(level); 299 } 300 301 public void setLevel(final Level level) { 302 this.logger.setLevel(level); 303 } 304 305 public void entering() { 306 if (!this.logger.isLoggable(METHOD_CALL_LEVEL_VALUE)) { 307 return; 308 } 309 310 logger.entering(componentClassName, getCallerMethodName()); 311 } 312 313 public void entering(final Object... parameters) { 314 if (!this.logger.isLoggable(METHOD_CALL_LEVEL_VALUE)) { 315 return; 316 } 317 318 logger.entering(componentClassName, getCallerMethodName(), parameters); 319 } 320 321 public void exiting() { 322 if (!this.logger.isLoggable(METHOD_CALL_LEVEL_VALUE)) { 323 return; 324 } 325 logger.exiting(componentClassName, getCallerMethodName()); 326 } 327 328 public void exiting(final Object result) { 329 if (!this.logger.isLoggable(METHOD_CALL_LEVEL_VALUE)) { 330 return; 331 } 332 logger.exiting(componentClassName, getCallerMethodName(), result); 333 } 334 335 /** 336 * Method logs {@code exception}'s message as a {@code SEVERE} logging level 337 * message. 338 * <p/> 339 * If {@code cause} parameter is not {@code null}, it is logged as well and 340 * {@code exception} original cause is initialized with instance referenced 341 * by {@code cause} parameter. 342 * 343 * @param exception exception whose message should be logged. Must not be 344 * {@code null}. 345 * @param cause initial cause of the exception that should be logged as well 346 * and set as {@code exception}'s original cause. May be {@code null}. 347 * @return the same exception instance that was passed in as the {@code exception} 348 * parameter. 349 */ 350 public <T extends Throwable> T logSevereException(final T exception, final Throwable cause) { 351 if (this.logger.isLoggable(Level.SEVERE)) { 352 if (cause == null) { 353 logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), exception.getMessage()); 354 } else { 355 exception.initCause(cause); 356 logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), exception.getMessage(), cause); 357 } 358 } 359 360 return exception; 361 } 362 363 /** 364 * Method logs {@code exception}'s message as a {@code SEVERE} logging level 365 * message. 366 * <p/> 367 * If {@code logCause} parameter is {@code true}, {@code exception}'s original 368 * cause is logged as well (if exists). This may be used in cases when 369 * {@code exception}'s class provides constructor to initialize the original 370 * cause. In such case you do not need to use 371 * {@link #logSevereException(Throwable, Throwable)} 372 * method version but you might still want to log the original cause as well. 373 * 374 * @param exception exception whose message should be logged. Must not be 375 * {@code null}. 376 * @param logCause deterimnes whether initial cause of the exception should 377 * be logged as well 378 * @return the same exception instance that was passed in as the {@code exception} 379 * parameter. 380 */ 381 public <T extends Throwable> T logSevereException(final T exception, final boolean logCause) { 382 if (this.logger.isLoggable(Level.SEVERE)) { 383 if (logCause && exception.getCause() != null) { 384 logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), exception.getMessage(), exception.getCause()); 385 } else { 386 logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), exception.getMessage()); 387 } 388 } 389 390 return exception; 391 } 392 393 /** 394 * Same as {@link #logSevereException(Throwable, boolean) logSevereException(exception, true)}. 395 */ 396 public <T extends Throwable> T logSevereException(final T exception) { 397 if (this.logger.isLoggable(Level.SEVERE)) { 398 if (exception.getCause() == null) { 399 logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), exception.getMessage()); 400 } else { 401 logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), exception.getMessage(), exception.getCause()); 402 } 403 } 404 405 return exception; 406 } 407 408 /** 409 * Method logs {@code exception}'s message at the logging level specified by the 410 * {@code level} argument. 411 * <p/> 412 * If {@code cause} parameter is not {@code null}, it is logged as well and 413 * {@code exception} original cause is initialized with instance referenced 414 * by {@code cause} parameter. 415 * 416 * @param exception exception whose message should be logged. Must not be 417 * {@code null}. 418 * @param cause initial cause of the exception that should be logged as well 419 * and set as {@code exception}'s original cause. May be {@code null}. 420 * @param level loging level which should be used for logging 421 * @return the same exception instance that was passed in as the {@code exception} 422 * parameter. 423 */ 424 public <T extends Throwable> T logException(final T exception, final Throwable cause, final Level level) { 425 if (this.logger.isLoggable(level)) { 426 if (cause == null) { 427 logger.logp(level, componentClassName, getCallerMethodName(), exception.getMessage()); 428 } else { 429 exception.initCause(cause); 430 logger.logp(level, componentClassName, getCallerMethodName(), exception.getMessage(), cause); 431 } 432 } 433 434 return exception; 435 } 436 437 /** 438 * Method logs {@code exception}'s message at the logging level specified by the 439 * {@code level} argument. 440 * <p/> 441 * If {@code logCause} parameter is {@code true}, {@code exception}'s original 442 * cause is logged as well (if exists). This may be used in cases when 443 * {@code exception}'s class provides constructor to initialize the original 444 * cause. In such case you do not need to use 445 * {@link #logException(Throwable, Throwable, Level) logException(exception, cause, level)} 446 * method version but you might still want to log the original cause as well. 447 * 448 * @param exception exception whose message should be logged. Must not be 449 * {@code null}. 450 * @param logCause deterimnes whether initial cause of the exception should 451 * be logged as well 452 * @param level loging level which should be used for logging 453 * @return the same exception instance that was passed in as the {@code exception} 454 * parameter. 455 */ 456 public <T extends Throwable> T logException(final T exception, final boolean logCause, final Level level) { 457 if (this.logger.isLoggable(level)) { 458 if (logCause && exception.getCause() != null) { 459 logger.logp(level, componentClassName, getCallerMethodName(), exception.getMessage(), exception.getCause()); 460 } else { 461 logger.logp(level, componentClassName, getCallerMethodName(), exception.getMessage()); 462 } 463 } 464 465 return exception; 466 } 467 468 /** 469 * Same as {@link #logException(Throwable, Throwable, Level) 470 * logException(exception, true, level)}. 471 */ 472 public <T extends Throwable> T logException(final T exception, final Level level) { 473 if (this.logger.isLoggable(level)) { 474 if (exception.getCause() == null) { 475 logger.logp(level, componentClassName, getCallerMethodName(), exception.getMessage()); 476 } else { 477 logger.logp(level, componentClassName, getCallerMethodName(), exception.getMessage(), exception.getCause()); 478 } 479 } 480 481 return exception; 482 } 483 484 /** 485 * Function returns the name of the caller method for the method executing this 486 * function. 487 * 488 * @return caller method name from the call stack of the current {@link Thread}. 489 */ 490 private static String getCallerMethodName() { 491 return getStackMethodName(5); 492 } 493 494 /** 495 * Method returns the name of the method that is on the {@code methodIndexInStack} 496 * position in the call stack of the current {@link Thread}. 497 * 498 * @param methodIndexInStack index to the call stack to get the method name for. 499 * @return the name of the method that is on the {@code methodIndexInStack} 500 * position in the call stack of the current {@link Thread}. 501 */ 502 private static String getStackMethodName(final int methodIndexInStack) { 503 final String methodName; 504 505 final StackTraceElement[] stack = Thread.currentThread().getStackTrace(); 506 if (stack.length > methodIndexInStack + 1) { 507 methodName = stack[methodIndexInStack].getMethodName(); 508 } else { 509 methodName = "UNKNOWN METHOD"; 510 } 511 512 return methodName; 513 } 514 515 }