1 /*
   2  * Copyright (c) 2000, 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 java.util.logging;
  27 import java.time.Instant;
  28 import java.util.*;
  29 import java.util.concurrent.atomic.AtomicInteger;
  30 import java.util.concurrent.atomic.AtomicLong;
  31 import java.io.*;
  32 import java.time.Clock;
  33 import java.util.function.Predicate;
  34 
  35 /**
  36  * LogRecord objects are used to pass logging requests between
  37  * the logging framework and individual log Handlers.
  38  * <p>
  39  * When a LogRecord is passed into the logging framework it
  40  * logically belongs to the framework and should no longer be
  41  * used or updated by the client application.
  42  * <p>
  43  * Note that if the client application has not specified an
  44  * explicit source method name and source class name, then the
  45  * LogRecord class will infer them automatically when they are
  46  * first accessed (due to a call on getSourceMethodName or
  47  * getSourceClassName) by analyzing the call stack.  Therefore,
  48  * if a logging Handler wants to pass off a LogRecord to another
  49  * thread, or to transmit it over RMI, and if it wishes to subsequently
  50  * obtain method name or class name information it should call
  51  * one of getSourceClassName or getSourceMethodName to force
  52  * the values to be filled in.
  53  * <p>
  54  * <b> Serialization notes:</b>
  55  * <ul>
  56  * <li>The LogRecord class is serializable.
  57  *
  58  * <li> Because objects in the parameters array may not be serializable,
  59  * during serialization all objects in the parameters array are
  60  * written as the corresponding Strings (using Object.toString).
  61  *
  62  * <li> The ResourceBundle is not transmitted as part of the serialized
  63  * form, but the resource bundle name is, and the recipient object's
  64  * readObject method will attempt to locate a suitable resource bundle.
  65  *
  66  * </ul>
  67  *
  68  * @since 1.4
  69  */
  70 
  71 public class LogRecord implements java.io.Serializable {
  72     private static final AtomicLong globalSequenceNumber
  73         = new AtomicLong(0);
  74 
  75     /**
  76      * The default value of threadID will be the current thread's
  77      * thread id, for ease of correlation, unless it is greater than
  78      * MIN_SEQUENTIAL_THREAD_ID, in which case we try harder to keep
  79      * our promise to keep threadIDs unique by avoiding collisions due
  80      * to 32-bit wraparound.  Unfortunately, LogRecord.getThreadID()
  81      * returns int, while Thread.getId() returns long.
  82      */
  83     private static final int MIN_SEQUENTIAL_THREAD_ID = Integer.MAX_VALUE / 2;
  84 
  85     private static final AtomicInteger nextThreadId
  86         = new AtomicInteger(MIN_SEQUENTIAL_THREAD_ID);
  87 
  88     private static final ThreadLocal<Integer> threadIds = new ThreadLocal<>();
  89 
  90     /**
  91      * Logging message level
  92      */
  93     private Level level;
  94 
  95     /**
  96      * Sequence number
  97      */
  98     private long sequenceNumber;
  99 
 100     /**
 101      * Class that issued logging call
 102      */
 103     private String sourceClassName;
 104 
 105     /**
 106      * Method that issued logging call
 107      */
 108     private String sourceMethodName;
 109 
 110     /**
 111      * Non-localized raw message text
 112      */
 113     private String message;
 114 
 115     /**
 116      * Thread ID for thread that issued logging call.
 117      */
 118     private int threadID;
 119 
 120     /**
 121      * The Throwable (if any) associated with log message
 122      */
 123     private Throwable thrown;
 124 
 125     /**
 126      * Name of the source Logger.
 127      */
 128     private String loggerName;
 129 
 130     /**
 131      * Resource bundle name to localized log message.
 132      */
 133     private String resourceBundleName;
 134 
 135     /**
 136      * Event time.
 137      * @since 1.9
 138      */
 139     private Instant instant;
 140 
 141     /**
 142      * @serialField level Level Logging message level
 143      * @serialField sequenceNumber long Sequence number
 144      * @serialField sourceClassName String Class that issued logging call
 145      * @serialField sourceMethodName String Method that issued logging call
 146      * @serialField message String Non-localized raw message text
 147      * @serialField threadID int Thread ID for thread that issued logging call
 148      * @serialField millis long Truncated event time in milliseconds since 1970
 149      *              - calculated as getInstant().toEpochMilli().
 150      *               The event time instant can be reconstructed using
 151      * <code>Instant.ofEpochSecond(millis/1000, (millis % 1000) * 1000_000 + nanoAdjustment)</code>
 152      * @serialField nanoAdjustment int Nanoseconds adjustment to the millisecond of
 153      *              event time - calculated as getInstant().getNano() % 1000_000
 154      *               The event time instant can be reconstructed using
 155      * <code>Instant.ofEpochSecond(millis/1000, (millis % 1000) * 1000_000 + nanoAdjustment)</code>
 156      *              <p>
 157      *              Since: 1.9
 158      * @serialField thrown Throwable The Throwable (if any) associated with log
 159      *              message
 160      * @serialField loggerName String Name of the source Logger
 161      * @serialField resourceBundleName String Resource bundle name to localized
 162      *              log message
 163      */
 164     private static final ObjectStreamField[] serialPersistentFields =
 165         new ObjectStreamField[] {
 166             new ObjectStreamField("level", Level.class),
 167             new ObjectStreamField("sequenceNumber", long.class),
 168             new ObjectStreamField("sourceClassName", String.class),
 169             new ObjectStreamField("sourceMethodName", String.class),
 170             new ObjectStreamField("message", String.class),
 171             new ObjectStreamField("threadID", int.class),
 172             new ObjectStreamField("millis", long.class),
 173             new ObjectStreamField("nanoAdjustment", int.class),
 174             new ObjectStreamField("thrown", Throwable.class),
 175             new ObjectStreamField("loggerName", String.class),
 176             new ObjectStreamField("resourceBundleName", String.class),
 177         };
 178 
 179     private transient boolean needToInferCaller;
 180     private transient Object parameters[];
 181     private transient ResourceBundle resourceBundle;
 182 
 183     /**
 184      * Returns the default value for a new LogRecord's threadID.
 185      */
 186     private int defaultThreadID() {
 187         long tid = Thread.currentThread().getId();
 188         if (tid < MIN_SEQUENTIAL_THREAD_ID) {
 189             return (int) tid;
 190         } else {
 191             Integer id = threadIds.get();
 192             if (id == null) {
 193                 id = nextThreadId.getAndIncrement();
 194                 threadIds.set(id);
 195             }
 196             return id;
 197         }
 198     }
 199 
 200     /**
 201      * Construct a LogRecord with the given level and message values.
 202      * <p>
 203      * The sequence property will be initialized with a new unique value.
 204      * These sequence values are allocated in increasing order within a VM.
 205      * <p>
 206      * Since JDK 1.9, the event time is represented by an {@link Instant}.
 207      * The instant property will be initialized to the {@linkplain
 208      * Instant#now() current instant}, using the best available
 209      * {@linkplain Clock#systemUTC() clock} on the system.
 210      * <p>
 211      * The thread ID property will be initialized with a unique ID for
 212      * the current thread.
 213      * <p>
 214      * All other properties will be initialized to "null".
 215      *
 216      * @param level  a logging level value
 217      * @param msg  the raw non-localized logging message (may be null)
 218      * @see java.time.Clock#systemUTC()
 219      */
 220     public LogRecord(Level level, String msg) {
 221         this.level = Objects.requireNonNull(level);
 222         message = msg;
 223         // Assign a thread ID and a unique sequence number.
 224         sequenceNumber = globalSequenceNumber.getAndIncrement();
 225         threadID = defaultThreadID();
 226         instant = Instant.now();
 227         needToInferCaller = true;
 228    }
 229 
 230     /**
 231      * Get the source Logger's name.
 232      *
 233      * @return source logger name (may be null)
 234      */
 235     public String getLoggerName() {
 236         return loggerName;
 237     }
 238 
 239     /**
 240      * Set the source Logger's name.
 241      *
 242      * @param name   the source logger name (may be null)
 243      */
 244     public void setLoggerName(String name) {
 245         loggerName = name;
 246     }
 247 
 248     /**
 249      * Get the localization resource bundle
 250      * <p>
 251      * This is the ResourceBundle that should be used to localize
 252      * the message string before formatting it.  The result may
 253      * be null if the message is not localizable, or if no suitable
 254      * ResourceBundle is available.
 255      * @return the localization resource bundle
 256      */
 257     public ResourceBundle getResourceBundle() {
 258         return resourceBundle;
 259     }
 260 
 261     /**
 262      * Set the localization resource bundle.
 263      *
 264      * @param bundle  localization bundle (may be null)
 265      */
 266     public void setResourceBundle(ResourceBundle bundle) {
 267         resourceBundle = bundle;
 268     }
 269 
 270     /**
 271      * Get the localization resource bundle name
 272      * <p>
 273      * This is the name for the ResourceBundle that should be
 274      * used to localize the message string before formatting it.
 275      * The result may be null if the message is not localizable.
 276      * @return the localization resource bundle name
 277      */
 278     public String getResourceBundleName() {
 279         return resourceBundleName;
 280     }
 281 
 282     /**
 283      * Set the localization resource bundle name.
 284      *
 285      * @param name  localization bundle name (may be null)
 286      */
 287     public void setResourceBundleName(String name) {
 288         resourceBundleName = name;
 289     }
 290 
 291     /**
 292      * Get the logging message level, for example Level.SEVERE.
 293      * @return the logging message level
 294      */
 295     public Level getLevel() {
 296         return level;
 297     }
 298 
 299     /**
 300      * Set the logging message level, for example Level.SEVERE.
 301      * @param level the logging message level
 302      */
 303     public void setLevel(Level level) {
 304         if (level == null) {
 305             throw new NullPointerException();
 306         }
 307         this.level = level;
 308     }
 309 
 310     /**
 311      * Get the sequence number.
 312      * <p>
 313      * Sequence numbers are normally assigned in the LogRecord
 314      * constructor, which assigns unique sequence numbers to
 315      * each new LogRecord in increasing order.
 316      * @return the sequence number
 317      */
 318     public long getSequenceNumber() {
 319         return sequenceNumber;
 320     }
 321 
 322     /**
 323      * Set the sequence number.
 324      * <p>
 325      * Sequence numbers are normally assigned in the LogRecord constructor,
 326      * so it should not normally be necessary to use this method.
 327      * @param seq the sequence number
 328      */
 329     public void setSequenceNumber(long seq) {
 330         sequenceNumber = seq;
 331     }
 332 
 333     /**
 334      * Get the  name of the class that (allegedly) issued the logging request.
 335      * <p>
 336      * Note that this sourceClassName is not verified and may be spoofed.
 337      * This information may either have been provided as part of the
 338      * logging call, or it may have been inferred automatically by the
 339      * logging framework.  In the latter case, the information may only
 340      * be approximate and may in fact describe an earlier call on the
 341      * stack frame.
 342      * <p>
 343      * May be null if no information could be obtained.
 344      *
 345      * @return the source class name
 346      */
 347     public String getSourceClassName() {
 348         if (needToInferCaller) {
 349             inferCaller();
 350         }
 351         return sourceClassName;
 352     }
 353 
 354     /**
 355      * Set the name of the class that (allegedly) issued the logging request.
 356      *
 357      * @param sourceClassName the source class name (may be null)
 358      */
 359     public void setSourceClassName(String sourceClassName) {
 360         this.sourceClassName = sourceClassName;
 361         needToInferCaller = false;
 362     }
 363 
 364     /**
 365      * Get the  name of the method that (allegedly) issued the logging request.
 366      * <p>
 367      * Note that this sourceMethodName is not verified and may be spoofed.
 368      * This information may either have been provided as part of the
 369      * logging call, or it may have been inferred automatically by the
 370      * logging framework.  In the latter case, the information may only
 371      * be approximate and may in fact describe an earlier call on the
 372      * stack frame.
 373      * <p>
 374      * May be null if no information could be obtained.
 375      *
 376      * @return the source method name
 377      */
 378     public String getSourceMethodName() {
 379         if (needToInferCaller) {
 380             inferCaller();
 381         }
 382         return sourceMethodName;
 383     }
 384 
 385     /**
 386      * Set the name of the method that (allegedly) issued the logging request.
 387      *
 388      * @param sourceMethodName the source method name (may be null)
 389      */
 390     public void setSourceMethodName(String sourceMethodName) {
 391         this.sourceMethodName = sourceMethodName;
 392         needToInferCaller = false;
 393     }
 394 
 395     /**
 396      * Get the "raw" log message, before localization or formatting.
 397      * <p>
 398      * May be null, which is equivalent to the empty string "".
 399      * <p>
 400      * This message may be either the final text or a localization key.
 401      * <p>
 402      * During formatting, if the source logger has a localization
 403      * ResourceBundle and if that ResourceBundle has an entry for
 404      * this message string, then the message string is replaced
 405      * with the localized value.
 406      *
 407      * @return the raw message string
 408      */
 409     public String getMessage() {
 410         return message;
 411     }
 412 
 413     /**
 414      * Set the "raw" log message, before localization or formatting.
 415      *
 416      * @param message the raw message string (may be null)
 417      */
 418     public void setMessage(String message) {
 419         this.message = message;
 420     }
 421 
 422     /**
 423      * Get the parameters to the log message.
 424      *
 425      * @return the log message parameters.  May be null if
 426      *                  there are no parameters.
 427      */
 428     public Object[] getParameters() {
 429         return parameters;
 430     }
 431 
 432     /**
 433      * Set the parameters to the log message.
 434      *
 435      * @param parameters the log message parameters. (may be null)
 436      */
 437     public void setParameters(Object parameters[]) {
 438         this.parameters = parameters;
 439     }
 440 
 441     /**
 442      * Get an identifier for the thread where the message originated.
 443      * <p>
 444      * This is a thread identifier within the Java VM and may or
 445      * may not map to any operating system ID.
 446      *
 447      * @return thread ID
 448      */
 449     public int getThreadID() {
 450         return threadID;
 451     }
 452 
 453     /**
 454      * Set an identifier for the thread where the message originated.
 455      * @param threadID  the thread ID
 456      */
 457     public void setThreadID(int threadID) {
 458         this.threadID = threadID;
 459     }
 460 
 461     /**
 462      * Get truncated event time in milliseconds since 1970.
 463      *
 464      * @return truncated event time in millis since 1970
 465      *
 466      * @implSpec This is equivalent to calling
 467      *      {@link #getInstant() getInstant().toEpochMilli()}.
 468      *
 469      * @deprecated To get the full nanosecond resolution event time,
 470      *             use {@link #getInstant()}.
 471      *
 472      * @see #getInstant()
 473      */
 474     @Deprecated
 475     public long getMillis() {
 476         return instant.toEpochMilli();
 477     }
 478 
 479     /**
 480      * Set event time.
 481      *
 482      * @param millis event time in millis since 1970.
 483      *
 484      * @implSpec This is equivalent to calling
 485      *      {@link #setInstant(java.time.Instant)
 486      *      setInstant(Instant.ofEpochMilli(millis))}.
 487      *
 488      * @deprecated To set event time with nanosecond resolution,
 489      *             use {@link #setInstant(java.time.Instant)}.
 490      *
 491      * @see #setInstant(java.time.Instant)
 492      */
 493     @Deprecated
 494     public void setMillis(long millis) {
 495         this.instant = Instant.ofEpochMilli(millis);
 496     }
 497 
 498     /**
 499      * Gets the instant that the event occurred.
 500      *
 501      * @return the instant that the event occurred.
 502      *
 503      * @since 1.9
 504      */
 505     public Instant getInstant() {
 506         return instant;
 507     }
 508 
 509     /**
 510      * Sets the instant that the event occurred.
 511      *
 512      * @param instant the instant that the event occurred.
 513      *
 514      * @throws NullPointerException if {@code instant} is null.
 515      * @since 1.9
 516      */
 517     public void setInstant(Instant instant) {
 518         this.instant = Objects.requireNonNull(instant);
 519     }
 520 
 521     /**
 522      * Get any throwable associated with the log record.
 523      * <p>
 524      * If the event involved an exception, this will be the
 525      * exception object. Otherwise null.
 526      *
 527      * @return a throwable
 528      */
 529     public Throwable getThrown() {
 530         return thrown;
 531     }
 532 
 533     /**
 534      * Set a throwable associated with the log event.
 535      *
 536      * @param thrown  a throwable (may be null)
 537      */
 538     public void setThrown(Throwable thrown) {
 539         this.thrown = thrown;
 540     }
 541 
 542     private static final long serialVersionUID = 5372048053134512534L;
 543 
 544     /**
 545      * @serialData Serialized fields, followed by a two byte version number
 546      * (major byte, followed by minor byte), followed by information on
 547      * the log record parameter array.  If there is no parameter array,
 548      * then -1 is written.  If there is a parameter array (possible of zero
 549      * length) then the array length is written as an integer, followed
 550      * by String values for each parameter.  If a parameter is null, then
 551      * a null String is written.  Otherwise the output of Object.toString()
 552      * is written.
 553      */
 554     private void writeObject(ObjectOutputStream out) throws IOException {
 555         // We have to write serialized fields first.
 556         ObjectOutputStream.PutField pf = out.putFields();
 557         pf.put("level", level);
 558         pf.put("sequenceNumber", sequenceNumber);
 559         pf.put("sourceClassName", sourceClassName);
 560         pf.put("sourceMethodName", sourceMethodName);
 561         pf.put("message", message);
 562         pf.put("threadID", threadID);
 563         pf.put("millis", instant.toEpochMilli());
 564         pf.put("nanoAdjustment", instant.getNano() % 1000_000);
 565         pf.put("thrown", thrown);
 566         pf.put("loggerName", loggerName);
 567         pf.put("resourceBundleName", resourceBundleName);
 568         out.writeFields();
 569 
 570         // Write our version number.
 571         out.writeByte(1);
 572         out.writeByte(0);
 573         if (parameters == null) {
 574             out.writeInt(-1);
 575             return;
 576         }
 577         out.writeInt(parameters.length);
 578         // Write string values for the parameters.
 579         for (Object parameter : parameters) {
 580             out.writeObject(Objects.toString(parameter, null));
 581         }
 582     }
 583 
 584     private void readObject(ObjectInputStream in)
 585                         throws IOException, ClassNotFoundException {
 586         // We have to read serialized fields first.
 587         ObjectInputStream.GetField gf = in.readFields();
 588         level = (Level) gf.get("level", null);
 589         sequenceNumber = gf.get("sequenceNumber", 0L);
 590         sourceClassName = (String) gf.get("sourceClassName", null);
 591         sourceMethodName = (String) gf.get("sourceMethodName", null);
 592         message = (String) gf.get("message", null);
 593         threadID = gf.get("threadID", 0);
 594         long millis = gf.get("millis", 0L);
 595         int nanoOfMilli = gf.get("nanoAdjustment", 0);
 596         instant = Instant.ofEpochSecond(
 597             millis / 1000L, (millis % 1000L) * 1000_000L + nanoOfMilli);
 598         thrown = (Throwable) gf.get("thrown", null);
 599         loggerName = (String) gf.get("loggerName", null);
 600         resourceBundleName = (String) gf.get("resourceBundleName", null);
 601 
 602         // Read version number.
 603         byte major = in.readByte();
 604         byte minor = in.readByte();
 605         if (major != 1) {
 606             throw new IOException("LogRecord: bad version: " + major + "." + minor);
 607         }
 608         int len = in.readInt();
 609         if (len == -1) {
 610             parameters = null;
 611         } else {
 612             parameters = new Object[len];
 613             for (int i = 0; i < parameters.length; i++) {
 614                 parameters[i] = in.readObject();
 615             }
 616         }
 617         // If necessary, try to regenerate the resource bundle.
 618         if (resourceBundleName != null) {
 619             try {
 620                 // use system class loader to ensure the ResourceBundle
 621                 // instance is a different instance than null loader uses
 622                 final ResourceBundle bundle =
 623                         ResourceBundle.getBundle(resourceBundleName,
 624                                 Locale.getDefault(),
 625                                 ClassLoader.getSystemClassLoader());
 626                 resourceBundle = bundle;
 627             } catch (MissingResourceException ex) {
 628                 // This is not a good place to throw an exception,
 629                 // so we simply leave the resourceBundle null.
 630                 resourceBundle = null;
 631             }
 632         }
 633 
 634         needToInferCaller = false;
 635     }
 636 
 637     // Private method to infer the caller's class and method names
 638     private void inferCaller() {
 639         needToInferCaller = false;
 640         // Skip all frames until we have found the first logger frame.
 641         Optional<StackWalker.StackFrame> frame = new CallerFinder().get();
 642         frame.ifPresent(f -> {
 643             setSourceClassName(f.getClassName());
 644             setSourceMethodName(f.getMethodName());
 645         });
 646 
 647         // We haven't found a suitable frame, so just punt.  This is
 648         // OK as we are only committed to making a "best effort" here.
 649     }
 650 
 651     /*
 652      * CallerFinder is a stateful predicate.
 653      */
 654     static final class CallerFinder implements Predicate<StackWalker.StackFrame> {
 655         static final StackWalker WALKER = StackWalker.getInstance();
 656 
 657         /**
 658          * Returns StackFrame of the caller's frame.
 659          * @return StackFrame of the caller's frame.
 660          */
 661         Optional<StackWalker.StackFrame> get() {
 662             return WALKER.walk((s) -> s.filter(this).findFirst());
 663         }
 664 
 665         private boolean lookingForLogger = true;
 666         /**
 667          * Returns true if we have found the caller's frame, false if the frame
 668          * must be skipped.
 669          *
 670          * @param t The frame info.
 671          * @return true if we have found the caller's frame, false if the frame
 672          * must be skipped.
 673          */
 674         @Override
 675         public boolean test(StackWalker.StackFrame t) {
 676             final String cname = t.getClassName();
 677             // We should skip all frames until we have found the logger,
 678             // because these frames could be frames introduced by e.g. custom
 679             // sub classes of Handler.
 680             if (lookingForLogger) {
 681                 lookingForLogger = !cname.equals("java.util.logging.Logger") &&
 682                         !cname.startsWith("java.util.logging.LoggingProxyImpl") &&
 683                         !cname.startsWith("sun.util.logging.");
 684                 return false;
 685             }
 686             // Once the logger is found - we should skip all frames that
 687             // point to packages which contain artifacts that could be
 688             // inserted between the logger and its caller. These could be
 689             // logger wrappers from j.u.l or sun.uti.logging (e.g. the
 690             // PlatformLogger or artifacts between the PlatformLogger and
 691             // the actual logger) or frames inserted by use of reflection
 692             // and/or doPrivileged calls.
 693             return !cname.startsWith("java.util.logging.")
 694                     && !cname.startsWith("sun.util.logging.")
 695                     && !cname.startsWith("java.security.AccessController");
 696         }
 697     }
 698 }