8245302: Upgrade LogRecord to support long thread ids and remove its usage of ThreadLocal

Java.util.logging.LogRecord has been updated to use long thread ids instead of int thread id

Reviewed-by: alanb, dfuchs
This commit is contained in:
Rahul Yadav 2020-07-03 10:19:54 +01:00 committed by Patrick Concannon
parent f23c983a46
commit e2072bba70
4 changed files with 495 additions and 42 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,7 +26,6 @@
package java.util.logging;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.io.*;
import java.security.AccessController;
@ -75,21 +74,6 @@ public class LogRecord implements java.io.Serializable {
private static final AtomicLong globalSequenceNumber
= new AtomicLong(0);
/**
* The default value of threadID will be the current thread's
* thread id, for ease of correlation, unless it is greater than
* MIN_SEQUENTIAL_THREAD_ID, in which case we try harder to keep
* our promise to keep threadIDs unique by avoiding collisions due
* to 32-bit wraparound. Unfortunately, LogRecord.getThreadID()
* returns int, while Thread.getId() returns long.
*/
private static final int MIN_SEQUENTIAL_THREAD_ID = Integer.MAX_VALUE / 2;
private static final AtomicInteger nextThreadId
= new AtomicInteger(MIN_SEQUENTIAL_THREAD_ID);
private static final ThreadLocal<Integer> threadIds = new ThreadLocal<>();
/**
* Logging message level
*/
@ -120,6 +104,11 @@ public class LogRecord implements java.io.Serializable {
*/
private int threadID;
/**
* long value of Thread ID for thread that issued logging call.
*/
private long longThreadID;
/**
* The Throwable (if any) associated with log message
*/
@ -147,7 +136,10 @@ public class LogRecord implements java.io.Serializable {
* @serialField sourceClassName String Class that issued logging call
* @serialField sourceMethodName String Method that issued logging call
* @serialField message String Non-localized raw message text
* @serialField threadID int Thread ID for thread that issued logging call
* @serialField threadID int this is deprecated and is available for backward compatibility.
* Values may have been synthesized. If present, {@code longThreadID} represents
* the actual thread id.
* @serialField longThreadID long Thread ID for thread that issued logging call
* @serialField millis long Truncated event time in milliseconds since 1970
* - calculated as getInstant().toEpochMilli().
* The event time instant can be reconstructed using
@ -164,6 +156,7 @@ public class LogRecord implements java.io.Serializable {
* @serialField resourceBundleName String Resource bundle name to localized
* log message
*/
@Serial
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[] {
new ObjectStreamField("level", Level.class),
@ -172,6 +165,7 @@ public class LogRecord implements java.io.Serializable {
new ObjectStreamField("sourceMethodName", String.class),
new ObjectStreamField("message", String.class),
new ObjectStreamField("threadID", int.class),
new ObjectStreamField("longThreadID", long.class),
new ObjectStreamField("millis", long.class),
new ObjectStreamField("nanoAdjustment", int.class),
new ObjectStreamField("thrown", Throwable.class),
@ -184,20 +178,22 @@ public class LogRecord implements java.io.Serializable {
private transient ResourceBundle resourceBundle;
/**
* Returns the default value for a new LogRecord's threadID.
* Synthesizes a pseudo unique integer value from a long {@code id} value.
* For backward compatibility with previous releases,the returned integer is
* such that for any positive long less than or equals to {@code Integer.MAX_VALUE},
* the returned integer is equal to the original value.
* Otherwise - it is synthesized with a best effort hashing algorithm,
* and the returned value is negative.
* Calling this method multiple times with the same value always yields the same result.
*
* @return thread id
*/
private int defaultThreadID() {
long tid = Thread.currentThread().getId();
if (tid < MIN_SEQUENTIAL_THREAD_ID) {
return (int) tid;
} else {
Integer id = threadIds.get();
if (id == null) {
id = nextThreadId.getAndIncrement();
threadIds.set(id);
}
return id;
}
private int shortThreadID(long id) {
if (id >= 0 && id <= Integer.MAX_VALUE)
return (int) id;
int hash = Long.hashCode(id);
return hash < 0 ? hash : (-1 - hash);
}
/**
@ -225,10 +221,13 @@ public class LogRecord implements java.io.Serializable {
message = msg;
// Assign a thread ID and a unique sequence number.
sequenceNumber = globalSequenceNumber.getAndIncrement();
threadID = defaultThreadID();
long id = Thread.currentThread().getId();
// threadID is deprecated and this value is synthesised for backward compatibility
threadID = shortThreadID(id);
longThreadID = id;
instant = Instant.now();
needToInferCaller = true;
}
}
/**
* Get the source Logger's name.
@ -447,8 +446,12 @@ public class LogRecord implements java.io.Serializable {
* This is a thread identifier within the Java VM and may or
* may not map to any operating system ID.
*
* @deprecated Values returned by this method may be synthesized,
* and may not correspond to the actual {@linkplain Thread#getId() thread id},
* use {@link #getLongThreadID()} instead.
* @return thread ID
*/
@Deprecated(since = "16")
public int getThreadID() {
return threadID;
}
@ -456,9 +459,41 @@ public class LogRecord implements java.io.Serializable {
/**
* Set an identifier for the thread where the message originated.
* @param threadID the thread ID
*
* @deprecated This method doesn't allow to pass a long {@linkplain Thread#getId() thread id},
* use {@link #setLongThreadID(long)} instead.
*/
@Deprecated(since = "16")
public void setThreadID(int threadID) {
this.threadID = threadID;
this.longThreadID = threadID;
}
/**
* Get a thread identifier for the thread where message originated
*
* <p>
* This is a thread identifier within the Java VM and may or
* may not map to any operating system ID.
*
* @return thread ID
* @since 16
*/
public long getLongThreadID() {
return longThreadID;
}
/**
* Set an identifier for the thread where the message originated.
*
* @param longThreadID the thread ID
* @return this LogRecord
* @since 16
*/
public LogRecord setLongThreadID(long longThreadID) {
this.threadID = shortThreadID(longThreadID);
this.longThreadID = longThreadID;
return this;
}
/**
@ -552,6 +587,7 @@ public class LogRecord implements java.io.Serializable {
this.thrown = thrown;
}
@Serial
private static final long serialVersionUID = 5372048053134512534L;
/**
@ -564,6 +600,7 @@ public class LogRecord implements java.io.Serializable {
* a null String is written. Otherwise the output of Object.toString()
* is written.
*/
@Serial
private void writeObject(ObjectOutputStream out) throws IOException {
// We have to write serialized fields first.
ObjectOutputStream.PutField pf = out.putFields();
@ -573,6 +610,7 @@ public class LogRecord implements java.io.Serializable {
pf.put("sourceMethodName", sourceMethodName);
pf.put("message", message);
pf.put("threadID", threadID);
pf.put("longThreadID", longThreadID);
pf.put("millis", instant.toEpochMilli());
pf.put("nanoAdjustment", instant.getNano() % 1000_000);
pf.put("thrown", thrown);
@ -594,8 +632,25 @@ public class LogRecord implements java.io.Serializable {
}
}
/**
* Initializes the LogRecord from deserialized data.
* <ul>
* <li>If {@code longThreadID} is present in the serial form, its value
* takes precedence over {@code threadID} and a value for {@code threadID}
* is synthesized from it, such that for {@code longThreadID} values between
* {@code 0} and {@code Integer.MAX_VALUE} inclusive, {@code longThreadID}
* and {@code threadID} will have the same value. For values outside of this
* range a negative synthesized value will be deterministically derived
* from {@code longThreadID}.
* <li>Otherwise, when only {@code threadID} is
* present, {@code longThreadID} is initialized with the value of
* {@code threadID} which may be anything between {@code Integer.MIN_VALUE}
* and {Integer.MAX_VALUE}.
* </ul>
*/
@Serial
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
throws IOException, ClassNotFoundException {
// We have to read serialized fields first.
ObjectInputStream.GetField gf = in.readFields();
level = (Level) gf.get("level", null);
@ -603,7 +658,14 @@ public class LogRecord implements java.io.Serializable {
sourceClassName = (String) gf.get("sourceClassName", null);
sourceMethodName = (String) gf.get("sourceMethodName", null);
message = (String) gf.get("message", null);
threadID = gf.get("threadID", 0);
// If longthreadID is not present, it will be initialised with threadID value
// If longthreadID is present, threadID might have a synthesized value
int threadID = gf.get("threadID", 0);
long longThreadID = gf.get("longThreadID", (long)threadID);
if (threadID != longThreadID)
threadID = shortThreadID(longThreadID);
this.threadID = threadID;
this.longThreadID = longThreadID;
long millis = gf.get("millis", 0L);
int nanoOfMilli = gf.get("nanoAdjustment", 0);
instant = Instant.ofEpochSecond(
@ -641,9 +703,9 @@ public class LogRecord implements java.io.Serializable {
// use system class loader to ensure the ResourceBundle
// instance is a different instance than null loader uses
final ResourceBundle bundle =
ResourceBundle.getBundle(resourceBundleName,
Locale.getDefault(),
ClassLoader.getSystemClassLoader());
ResourceBundle.getBundle(resourceBundleName,
Locale.getDefault(),
ClassLoader.getSystemClassLoader());
resourceBundle = bundle;
} catch (MissingResourceException ex) {
// This is not a good place to throw an exception,
@ -697,7 +759,7 @@ public class LogRecord implements java.io.Serializable {
private static final StackWalker WALKER;
static {
final PrivilegedAction<StackWalker> action =
() -> StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
() -> StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
WALKER = AccessController.doPrivileged(action);
}
@ -736,7 +798,7 @@ public class LogRecord implements java.io.Serializable {
private boolean isLoggerImplFrame(String cname) {
return (cname.equals("java.util.logging.Logger") ||
cname.startsWith("sun.util.logging.PlatformLogger"));
cname.startsWith("sun.util.logging.PlatformLogger"));
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -219,7 +219,7 @@ public class XMLFormatter extends Formatter {
}
sb.append(" <thread>");
sb.append(record.getThreadID());
sb.append(record.getLongThreadID());
sb.append("</thread>\n");
if (record.getMessage() != null) {

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8245302
* @summary test the relationship between
* thread id long and int methods
* @build LogRecordThreadIdTest
* @run testng/othervm LogRecordThreadIdTest
*/
import java.util.logging.Level;
import java.util.logging.LogRecord;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotEquals;
public class LogRecordThreadIdTest {
LogRecord record, record1, record2;
@BeforeTest
public void setUp() throws Exception {
record = new LogRecord(Level.INFO, "record");
record1 = new LogRecord(Level.INFO, "record1");
record2 = new LogRecord(Level.INFO, "record2");
}
/**
* Tests threadID setter methods for consistency
* with longThreadID
*/
@Test
public void testSetThreadId() {
record.setThreadID(Integer.MAX_VALUE - 20);
record1.setThreadID(Integer.MAX_VALUE - 1);
assertEquals(record.getLongThreadID(), Integer.MAX_VALUE - 20L);
assertEquals(record.getThreadID(), Integer.MAX_VALUE - 20);
assertEquals(record1.getThreadID(), Integer.MAX_VALUE - 1);
assertEquals(record1.getLongThreadID(), Integer.MAX_VALUE - 1);
}
/**
* Tests longThreadID methods for consistency
* with threadID
*/
@Test
public void testSetLongThreadId() {
record.setLongThreadID(Integer.MAX_VALUE - 20L);
record1.setLongThreadID(Integer.MAX_VALUE + 10L);
record2.setLongThreadID(Integer.MAX_VALUE);
assertEquals(record.getThreadID(), Integer.MAX_VALUE - 20);
assertEquals(record.getLongThreadID(), Integer.MAX_VALUE - 20L);
assertNotEquals(record1.getThreadID(), Integer.MAX_VALUE + 10L);
assertEquals(record1.getLongThreadID(), Integer.MAX_VALUE + 10L);
assertEquals(record2.getThreadID(), Integer.MAX_VALUE);
assertEquals(record2.getLongThreadID(), Integer.MAX_VALUE);
}
}

View File

@ -0,0 +1,305 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Base64;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.XMLFormatter;
import java.util.stream.Stream;
/**
* @test
* @bug 8245302
* @summary tests the deprecation of threadID and a new field longThreadID,
* test should be run on jdk16 and subsequent versions
* @run main/othervm SerializeLogRecordTest
*/
public class SerializeLogRecordTest {
/**
* Serializes a log record, encode the serialized bytes in base 64, and
* prints pseudo java code that can be cut and pasted into this test.
* @param record the log record to serialize, encode in base 64, and for
* which test data will be generated.
* @return A string containing the generated pseudo java code.
* @throws IOException Unexpected.
* @throws ClassNotFoundException Unexpected.
*/
public static String generate(LogRecord record) throws IOException, ClassNotFoundException {
XMLFormatter formatter = new XMLFormatter();
String str = formatter.format(record);
// Serialize the given LogRecord
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(record);
oos.flush();
oos.close();
// Now we're going to perform a number of smoke tests before
// generating the Java pseudo code.
//
// First checks that the log record can be deserialized
final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
final ObjectInputStream ois = new ObjectInputStream(bais);
final LogRecord record2 = (LogRecord)ois.readObject();
String str2 = formatter.format(record2);
if (!str.equals(str2)) throw new RuntimeException("Unexpected values in deserialized object:"
+ "\n\tExpected: " + str
+ "\n\tRetrieved: "+str);
// Now get a Base64 string representation of the serialized bytes.
final String base64 = Base64.getEncoder().encodeToString(baos.toByteArray());
// Check that we can deserialize a log record from the Base64 string
// representation we just computed.
final ByteArrayInputStream bais2 = new ByteArrayInputStream(Base64.getDecoder().decode(base64));
final ObjectInputStream ois2 = new ObjectInputStream(bais2);
final LogRecord record3 = (LogRecord)ois2.readObject();
// Format the new deserialized LogRecord using the SimpleFormatter, and
// check that the string representation obtained matches the string
// representation of the original LogRecord
String str3 = formatter.format(record3);
if (!str.equals(str3)) throw new RuntimeException("Unexpected values in deserialized object:"
+ "\n\tExpected: " + str
+ "\n\tRetrieved: "+str);
// Generates the Java Pseudo code that can be cut & pasted into
// this test (see Jdk8SerializedLog and Jdk9SerializedLog below)
final StringBuilder sb = new StringBuilder();
sb.append(" /**").append('\n');
sb.append(" * Base64 encoded string for LogRecord object.").append('\n');
sb.append(" * Java version: ").append(System.getProperty("java.version")).append('\n');
sb.append(" * threadID: ").append(record.getThreadID()).append('\n');
sb.append(" * longThreadID: ").append(record.getLongThreadID()).append('\n');
sb.append(" **/").append('\n');
sb.append(" final String base64 = ").append("\n ");
final int last = base64.length() - 1;
for (int i=0; i<base64.length();i++) {
if (i%64 == 0) sb.append("\"");
sb.append(base64.charAt(i));
if (i%64 == 63 || i == last) {
sb.append("\"");
if (i == last) sb.append(";\n");
else sb.append("\n + ");
}
}
return sb.toString();
}
/**
* An abstract class to test that a log record previously serialized on a
* different java version can be deserialized in the current java version.
* (see Jdk11SerializedLog and Jdk16SerializedLog below)
*/
public abstract static class SerializedLog {
public abstract String getBase64();
/**
* Deserializes the Base64 encoded string returned by {@link
* #getBase64()}, and checks that the string representation obtained
* matches the original string representation returned by
*/
protected void dotest() {
try {
final String base64 = getBase64();
final ByteArrayInputStream bais =
new ByteArrayInputStream(Base64.getDecoder().decode(base64));
final ObjectInputStream ois = new ObjectInputStream(bais);
final LogRecord record = (LogRecord)ois.readObject();
check(record);
System.out.println("PASSED: "+this.getClass().getName()+"\n");
} catch (IOException | ClassNotFoundException x) {
throw new RuntimeException(x);
}
}
/**
* Check that the values of threadID and longThreadID
* are correct and consistent when de-serialized from
* earlier jdk versions(jdk11)
*/
protected void check(LogRecord r1) {
XMLFormatter formatter = new XMLFormatter();
int check = Integer.MAX_VALUE - 10;
String str = formatter.format(r1);
String loggerName = r1.getLoggerName();
if (loggerName.equals("test2")) {
int id = -2147483639;
if (r1.getLongThreadID() != Integer.MAX_VALUE + 10L || r1.getThreadID() != id) {
throw new RuntimeException(this.getClass().getName());
}
else {
System.out.println("Test Integer Check Passed");
}
}
if (loggerName.equals("test1") || loggerName.equals("test")) {
if (loggerName.equals("test1")) {
check = Integer.MAX_VALUE / 2 - 20;
}
int tid = r1.getThreadID();
long longThreadID = r1.getLongThreadID();
if (tid != check || longThreadID != check || !str.contains("<thread>" + String.valueOf(longThreadID))) {
throw new RuntimeException(this.getClass().getName());
}
else {
System.out.println("Test Integer Check Passed");
}
}
}
}
public static void generate() {
try {
LogRecord record = new LogRecord(Level.INFO, "Java Version: {0}");
record.setLoggerName("test");
record.setThreadID(Integer.MAX_VALUE - 10);
record.setParameters(new Object[] {System.getProperty("java.version")});
System.out.println(generate(record));
LogRecord record1 = new LogRecord(Level.INFO, "Java Version: {0}");
record1.setLoggerName("test1");
record1.setLongThreadID(Integer.MAX_VALUE/2 - 20);
record1.setParameters(new Object[] {System.getProperty("java.version")});
System.out.println(generate(record1));
LogRecord record2 = new LogRecord(Level.INFO, "Java Version: {0}");
record2.setLoggerName("test2");
record2.setLongThreadID(Integer.MAX_VALUE + 10L);
record2.setParameters(new Object[] {System.getProperty("java.version")});
System.out.println(generate(record2));
} catch (IOException | ClassNotFoundException x) {
throw new RuntimeException(x);
}
}
public static class Jdk11SerializedLog extends SerializedLog {
/**
* Base64 encoded string for LogRecord object.
* It is generated using generate method and
* can be copy pasted as base64 value, for generating
* this value, execute this class with an argument value
* generate and the test will print out the base64 value
* that can be copy pasted below
* Java version: 11.0.6
**/
final String base64 =
"rO0ABXNyABtqYXZhLnV0aWwubG9nZ2luZy5Mb2dSZWNvcmRKjVk982lRlgMAC0oA"
+ "Bm1pbGxpc0kADm5hbm9BZGp1c3RtZW50SgAOc2VxdWVuY2VOdW1iZXJJAAh0aHJl"
+ "YWRJREwABWxldmVsdAAZTGphdmEvdXRpbC9sb2dnaW5nL0xldmVsO0wACmxvZ2dl"
+ "ck5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztMAAdtZXNzYWdlcQB+AAJMABJyZXNv"
+ "dXJjZUJ1bmRsZU5hbWVxAH4AAkwAD3NvdXJjZUNsYXNzTmFtZXEAfgACTAAQc291"
+ "cmNlTWV0aG9kTmFtZXEAfgACTAAGdGhyb3dudAAVTGphdmEvbGFuZy9UaHJvd2Fi"
+ "bGU7eHAAAAFycRovVgAFN/AAAAAAAAAAAH////VzcgAXamF2YS51dGlsLmxvZ2dp"
+ "bmcuTGV2ZWyOiHETUXM2kgIAA0kABXZhbHVlTAAEbmFtZXEAfgACTAAScmVzb3Vy"
+ "Y2VCdW5kbGVOYW1lcQB+AAJ4cAAAAyB0AARJTkZPdAAic3VuLnV0aWwubG9nZ2lu"
+ "Zy5yZXNvdXJjZXMubG9nZ2luZ3QABHRlc3R0ABFKYXZhIFZlcnNpb246IHswfXBw"
+ "cHB3BgEAAAAAAXQABjExLjAuNng=";
@Override
public String getBase64() {
return base64;
}
@Override
protected void check(LogRecord r1) {
super.check(r1);
}
public static void test() {
new Jdk11SerializedLog().dotest();
}
}
public static class Jdk16SerializedLog extends SerializedLog {
/**
* Base64 encoded string for LogRecord object.
* It is generated using generate method and
* can be copy pasted as base64 value, for generating
* this value, execute this class with an argument value
* generate and the test will print out the base64 value
* that can be copy pasted below
* Java version: 16-internal
**/
final String base64 =
"rO0ABXNyABtqYXZhLnV0aWwubG9nZ2luZy5Mb2dSZWNvcmRKjVk982lRlgMADEoA"
+ "DGxvbmdUaHJlYWRJREoABm1pbGxpc0kADm5hbm9BZGp1c3RtZW50SgAOc2VxdWVu"
+ "Y2VOdW1iZXJJAAh0aHJlYWRJREwABWxldmVsdAAZTGphdmEvdXRpbC9sb2dnaW5n"
+ "L0xldmVsO0wACmxvZ2dlck5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztMAAdtZXNz"
+ "YWdlcQB+AAJMABJyZXNvdXJjZUJ1bmRsZU5hbWVxAH4AAkwAD3NvdXJjZUNsYXNz"
+ "TmFtZXEAfgACTAAQc291cmNlTWV0aG9kTmFtZXEAfgACTAAGdGhyb3dudAAVTGph"
+ "dmEvbGFuZy9UaHJvd2FibGU7eHAAAAAAgAAACQAAAXLMALDdAAS+2AAAAAAAAAAC"
+ "gAAACXNyABdqYXZhLnV0aWwubG9nZ2luZy5MZXZlbI6IcRNRczaSAgADSQAFdmFs"
+ "dWVMAARuYW1lcQB+AAJMABJyZXNvdXJjZUJ1bmRsZU5hbWVxAH4AAnhwAAADIHQA"
+ "BElORk90ACJzdW4udXRpbC5sb2dnaW5nLnJlc291cmNlcy5sb2dnaW5ndAAFdGVz"
+ "dDJ0ABFKYXZhIFZlcnNpb246IHswfXBwcHB3BgEAAAAAAXQACzE2LWludGVybmFs"
+ "eA==";
@Override
public String getBase64() {
return base64;
}
@Override
protected void check(LogRecord r1) {
super.check(r1);
}
public static void test() {
new Jdk16SerializedLog().dotest();
}
}
static enum TestCase { GENERATE, TESTJDK11, TESTJDK16 };
public static void main(String[] args) {
// If no args, then run everything....
if (args == null || args.length == 0) {
args = new String[] { "GENERATE", "TESTJDK11", "TESTJDK16" };
}
// Run the specified test case(s)
Stream.of(args).map(x -> TestCase.valueOf(x)).forEach((x) -> {
switch(x) {
case GENERATE: generate(); break;
case TESTJDK11: Jdk11SerializedLog.test(); break;
case TESTJDK16: Jdk16SerializedLog.test(); break;
}
});
}
}