mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-17 11:23:19 +00:00
8144460: Improve the code coverage for BootstrapLogger and SimpleConsoleLogger APIs and verify bug fix JDK-8144214
Cover the logXX and LogEvent.valueOf APIs of BootstrapLogger and logXX APIs of SimpleConsoleLogger Reviewed-by: dfuchs
This commit is contained in:
parent
d3f047f9cf
commit
b3fa048050
@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.PrintStream;
|
||||
import java.lang.System.Logger;
|
||||
import java.lang.System.Logger.Level;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.internal.logger.BootstrapLogger;
|
||||
import jdk.internal.logger.LazyLoggers;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8144460 8144214
|
||||
* @summary Cover the logXX and LogEvent.valueOf APIs of BootstrapLogger
|
||||
* and logXX APIs of SimpleConsoleLogger.
|
||||
* @modules java.base/jdk.internal.logger
|
||||
* @build BootstrapLoggerUtils LogStream
|
||||
* @run main/othervm BootstrapLoggerAPIsTest
|
||||
*/
|
||||
|
||||
public class BootstrapLoggerAPIsTest {
|
||||
|
||||
private static final LogStream ERR = new LogStream();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
final ContentManager MGR = new ContentManager();
|
||||
|
||||
// private reflection hook that allows us to simulate a non booted VM
|
||||
final AtomicBoolean VM_BOOTED = new AtomicBoolean(false);
|
||||
|
||||
BootstrapLoggerUtils.setBootedHook(() -> VM_BOOTED.get());
|
||||
|
||||
// We replace System.err to check the messages that have been logged
|
||||
// by the JUL ConsoleHandler and default SimpleConsoleLogger
|
||||
// implementaion
|
||||
System.setErr(new PrintStream(ERR));
|
||||
|
||||
VM_BOOTED.getAndSet(false);
|
||||
if (BootstrapLogger.isBooted()) {
|
||||
throw new RuntimeException("VM should not be booted!");
|
||||
}
|
||||
|
||||
final Logger LOGGER =
|
||||
LazyLoggers.getLogger("foo.bar", Thread.class);
|
||||
final sun.util.logging.PlatformLogger.Level PLATFORM_LEVEL =
|
||||
sun.util.logging.PlatformLogger.Level.SEVERE;
|
||||
final MyResources BUNDLE = new MyResources();
|
||||
|
||||
/*
|
||||
* Test logXX APIs for interface java.lang.System.Logger. Log content
|
||||
* before VM is booted should be retained. Log content after VM was
|
||||
* booted should be flushed instantly. VM is not booted in first round
|
||||
* of loop, VM is booted in second round of loop.
|
||||
*/
|
||||
for (int i = 0; i < 2; i++) {
|
||||
boolean booted = BootstrapLogger.isBooted();
|
||||
|
||||
// make sure there is no [remaining] content in the LogStream.
|
||||
MGR.failLog("xyz", "throwable #", "MyClass_#", "MyMethod_#");
|
||||
|
||||
/*
|
||||
* test logXX APIs for interface java.lang.System.Logger.
|
||||
*/
|
||||
// void log(java.lang.System$Logger$Level,java.util.ResourceBundle,
|
||||
// java.lang.String,java.lang.Throwable)
|
||||
LOGGER.log(Level.ERROR, BUNDLE, "abc #0", new RuntimeException("throwable #0"));
|
||||
MGR.checkLog(booted, "xyz #0", "throwable #0");
|
||||
|
||||
// void log(java.lang.System$Logger$Level,java.util.ResourceBundle,
|
||||
// java.lang.String,java.lang.Object[])
|
||||
LOGGER.log(Level.ERROR, BUNDLE, "abc #1");
|
||||
MGR.checkLog(booted, "xyz #1");
|
||||
|
||||
// void log(java.lang.System$Logger$Level,java.lang.String,java.lang.Object[])
|
||||
LOGGER.log(Level.ERROR, BUNDLE, "abc {0}", "#2");
|
||||
MGR.checkLog(booted, "xyz #2");
|
||||
|
||||
// void log(java.lang.System$Logger$Level,java.lang.String,java.lang.Throwable)
|
||||
LOGGER.log(Level.ERROR, "xyz #3", new RuntimeException("throwable #3"));
|
||||
MGR.checkLog(booted, "xyz #3", "throwable #3");
|
||||
|
||||
// void log(java.lang.System$Logger$Level,java.util.function.Supplier)
|
||||
LOGGER.log(Level.ERROR, () -> "xyz #4");
|
||||
MGR.checkLog(booted, "xyz #4");
|
||||
|
||||
// void log(java.lang.System$Logger$Level,java.lang.Object)
|
||||
LOGGER.log(Level.ERROR, new MyObject("xyz #5"));
|
||||
MGR.checkLog(booted, "xyz #5");
|
||||
|
||||
// void log(java.lang.System$Logger$Level,java.util.function.Supplier,
|
||||
// java.lang.Throwable)
|
||||
LOGGER.log(Level.ERROR, () -> "xyz #6", new RuntimeException("throwable #6"));
|
||||
MGR.checkLog(booted, "xyz #6", "throwable #6");
|
||||
|
||||
|
||||
/*
|
||||
* test logXX APIs for interface
|
||||
* sun.util.logging.PlatformLogger.Bridge.
|
||||
*/
|
||||
sun.util.logging.PlatformLogger.Bridge bridge =
|
||||
(sun.util.logging.PlatformLogger.Bridge) LOGGER;
|
||||
|
||||
// void log(sun.util.logging.PlatformLogger$Level,java.lang.String)
|
||||
bridge.log(PLATFORM_LEVEL, "xyz #7");
|
||||
MGR.checkLog(booted, "xyz #7");
|
||||
|
||||
// void log(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.Throwable)
|
||||
bridge.log(PLATFORM_LEVEL, "xyz #8", new RuntimeException("throwable #8"));
|
||||
MGR.checkLog(booted, "xyz #8", "throwable #8");
|
||||
|
||||
// void log(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.Object[])
|
||||
bridge.log(PLATFORM_LEVEL, "xyz {0}", "#9");
|
||||
MGR.checkLog(booted, "xyz #9");
|
||||
|
||||
// void log(sun.util.logging.PlatformLogger$Level,java.util.function.Supplier)
|
||||
bridge.log(PLATFORM_LEVEL, () -> "xyz #10");
|
||||
MGR.checkLog(booted, "xyz #10");
|
||||
|
||||
// void log(sun.util.logging.PlatformLogger$Level,
|
||||
// java.lang.Throwable,java.util.function.Supplier)
|
||||
bridge.log(PLATFORM_LEVEL, new RuntimeException("throwable #11"), () -> "xyz #11");
|
||||
MGR.checkLog(booted, "xyz #11", "throwable #11");
|
||||
|
||||
// void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
|
||||
// java.lang.String,java.lang.String)
|
||||
bridge.logp(PLATFORM_LEVEL, "MyClass_#12", "MyMethod_#12", "xyz #12");
|
||||
MGR.checkLog(booted, "xyz #12", "MyClass_#12", "MyMethod_#12");
|
||||
|
||||
// void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
|
||||
// java.lang.String,java.util.function.Supplier)
|
||||
bridge.logp(PLATFORM_LEVEL, "MyClass_#13", "MyMethod_#13", () -> "xyz #13");
|
||||
MGR.checkLog(booted, "xyz #13", "MyClass_#13", "MyMethod_#13");
|
||||
|
||||
// void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
|
||||
// java.lang.String,java.lang.String,java.lang.Object[])
|
||||
bridge.logp(PLATFORM_LEVEL, "MyClass_#14", "MyMethod_#14", "xyz {0}", "#14");
|
||||
MGR.checkLog(booted, "xyz #14", "MyClass_#14", "MyMethod_#14");
|
||||
|
||||
// void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
|
||||
// java.lang.String,java.lang.String,java.lang.Throwable)
|
||||
bridge.logp(PLATFORM_LEVEL, "MyClass_#15", "MyMethod_#15",
|
||||
"xyz #15", new RuntimeException("throwable #15"));
|
||||
MGR.checkLog(booted, "xyz #15", "throwable #15", "MyClass_#15", "MyMethod_#15");
|
||||
|
||||
// void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
|
||||
// java.lang.String,java.lang.Throwable,java.util.function.Supplier)
|
||||
bridge.logp(PLATFORM_LEVEL, "MyClass_#16", "MyMethod_#16",
|
||||
new RuntimeException("throwable #16"), () -> "xyz #16");
|
||||
MGR.checkLog(booted, "xyz #16", "throwable #16", "MyClass_#16", "MyMethod_#16");
|
||||
|
||||
// void logrb(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.String,
|
||||
// java.util.ResourceBundle,java.lang.String,java.lang.Object[])
|
||||
bridge.logrb(PLATFORM_LEVEL, "MyClass_#17", "MyMethod_#17",
|
||||
BUNDLE, "abc {0}", "#17");
|
||||
MGR.checkLog(booted, "xyz #17", "MyClass_#17", "MyMethod_#17");
|
||||
|
||||
// void logrb(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.String,
|
||||
// java.util.ResourceBundle,java.lang.String,java.lang.Throwable)
|
||||
bridge.logrb(PLATFORM_LEVEL, "MyClass_#18", "MyMethod_#18",
|
||||
BUNDLE, "abc #18", new RuntimeException("throwable #18"));
|
||||
MGR.checkLog(booted, "xyz #18", "throwable #18", "MyClass_#18", "MyMethod_#18");
|
||||
|
||||
// void logrb(sun.util.logging.PlatformLogger$Level,java.util.ResourceBundle,
|
||||
// java.lang.String,java.lang.Object[])
|
||||
bridge.logrb(PLATFORM_LEVEL, BUNDLE, "abc {0}", "#19");
|
||||
MGR.checkLog(booted, "xyz #19");
|
||||
|
||||
// void logrb(sun.util.logging.PlatformLogger$Level,java.util.ResourceBundle,
|
||||
// java.lang.String,java.lang.Throwable)
|
||||
bridge.logrb(PLATFORM_LEVEL, BUNDLE, "abc #20",
|
||||
new RuntimeException("throwable #20"));
|
||||
MGR.checkLog(booted, "xyz #20", "throwable #20");
|
||||
|
||||
/*
|
||||
* retained log content should be flushed after VM is booted.
|
||||
*/
|
||||
if (!booted) {
|
||||
VM_BOOTED.getAndSet(true);
|
||||
// trigger the flush, make sure to call LOGGER.log(...)
|
||||
// after VM_BOOTED.getAndSet(true) and before MGR.assertCachedLog()
|
||||
LOGGER.log(Level.ERROR, "VM was just booted! This log should flush the cached logs.");
|
||||
MGR.assertCachedLog();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ContentManager {
|
||||
final List<String[]> cached = new ArrayList<String[]>();
|
||||
String[] last;
|
||||
|
||||
public void cache() {
|
||||
cached.add(last);
|
||||
}
|
||||
|
||||
public ContentManager failLog(String... nonexistent) {
|
||||
last = nonexistent;
|
||||
for (String c : nonexistent) {
|
||||
if (ERR.drain().contains(c)) {
|
||||
throw new RuntimeException("Content \"" + nonexistent
|
||||
+ "\" should not exist in the log!");
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void assertLog(String... logs) {
|
||||
String log = ERR.drain();
|
||||
for (String str : logs) {
|
||||
if (!log.contains(str)) {
|
||||
throw new RuntimeException("Content \"" + str + "\" does not exist in the log!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void checkLog(boolean booted, String... logs) {
|
||||
if (!booted) {
|
||||
failLog(logs).cache();
|
||||
} else {
|
||||
assertLog(logs);
|
||||
}
|
||||
}
|
||||
|
||||
public void assertCachedLog() {
|
||||
String log = ERR.drain();
|
||||
for (String[] arr : cached) {
|
||||
for (String c : arr) {
|
||||
if (!log.contains(c)) {
|
||||
throw new RuntimeException("Content \"" + c + "\" does not exist in the log!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyObject {
|
||||
String str;
|
||||
|
||||
public MyObject(String str) {
|
||||
this.str = str;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyResources extends ResourceBundle {
|
||||
public Object handleGetObject(String key) {
|
||||
if (key.contains("abc #") || key.contains("abc {")) {
|
||||
return key.replaceAll("abc ", "xyz ");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Enumeration<String> getKeys() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21,19 +21,14 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.lang.System.Logger;
|
||||
import java.lang.System.Logger.Level;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.System.Logger;
|
||||
import java.lang.System.Logger.Level;
|
||||
import java.security.AllPermission;
|
||||
import java.security.CodeSource;
|
||||
import java.security.Permission;
|
||||
@ -41,6 +36,7 @@ import java.security.PermissionCollection;
|
||||
import java.security.Permissions;
|
||||
import java.security.Policy;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
@ -56,25 +52,17 @@ import jdk.internal.logger.LazyLoggers;
|
||||
Tests the behavior of bootstrap loggers (and SimpleConsoleLoggers
|
||||
* too).
|
||||
* @modules java.base/jdk.internal.logger
|
||||
* @build BootstrapLoggerUtils LogStream
|
||||
* @run main/othervm BootstrapLoggerTest NO_SECURITY
|
||||
* @run main/othervm BootstrapLoggerTest SECURE
|
||||
* @run main/othervm/timeout=120 BootstrapLoggerTest SECURE_AND_WAIT
|
||||
*/
|
||||
public class BootstrapLoggerTest {
|
||||
|
||||
static final Method awaitPending;
|
||||
static final Method isAlive;
|
||||
static final Field isBooted;
|
||||
static final Field logManagerInitialized;
|
||||
static {
|
||||
try {
|
||||
isBooted = BootstrapLogger.class.getDeclaredField("isBooted");
|
||||
isBooted.setAccessible(true);
|
||||
// private reflection hook that allows us to test wait until all
|
||||
// the tasks pending in the BootstrapExecutor are finished.
|
||||
awaitPending = BootstrapLogger.class
|
||||
.getDeclaredMethod("awaitPendingTasks");
|
||||
awaitPending.setAccessible(true);
|
||||
// private reflection hook that allows us to test whether
|
||||
// the BootstrapExecutor is alive.
|
||||
isAlive = BootstrapLogger.class
|
||||
@ -90,43 +78,6 @@ public class BootstrapLoggerTest {
|
||||
}
|
||||
}
|
||||
|
||||
static void awaitPending() {
|
||||
try {
|
||||
awaitPending.invoke(null);
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
|
||||
ex.printStackTrace(LogStream.err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We use an instance of this class to check what the logging system has
|
||||
* printed on System.err.
|
||||
*/
|
||||
public static class LogStream extends OutputStream {
|
||||
|
||||
final static PrintStream err = System.err;
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
public LogStream() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(int b) {
|
||||
baos.write(b);
|
||||
err.write(b);
|
||||
}
|
||||
|
||||
public String drain() {
|
||||
awaitPending();
|
||||
synchronized(this) {
|
||||
String txt = baos.toString();
|
||||
baos.reset();
|
||||
return txt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static enum TestCase {
|
||||
NO_SECURITY, SECURE, SECURE_AND_WAIT
|
||||
}
|
||||
@ -142,7 +93,7 @@ public class BootstrapLoggerTest {
|
||||
|
||||
// private reflection hook that allows us to simulate a non booted VM
|
||||
final AtomicBoolean vmBooted = new AtomicBoolean(false);
|
||||
isBooted.set(null,(BooleanSupplier) () -> vmBooted.get());
|
||||
BootstrapLoggerUtils.setBootedHook(() -> vmBooted.get());
|
||||
|
||||
// We replace System.err to check the messages that have been logged
|
||||
// by the JUL ConsoleHandler and default SimpleConsoleLogger
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import jdk.internal.logger.BootstrapLogger;
|
||||
|
||||
class BootstrapLoggerUtils {
|
||||
|
||||
private static final Field IS_BOOTED;
|
||||
private static final Method AWAIT_PENDING;
|
||||
|
||||
static {
|
||||
try {
|
||||
IS_BOOTED = BootstrapLogger.class.getDeclaredField("isBooted");
|
||||
IS_BOOTED.setAccessible(true);
|
||||
// private reflection hook that allows us to test wait until all
|
||||
// the tasks pending in the BootstrapExecutor are finished.
|
||||
AWAIT_PENDING = BootstrapLogger.class.getDeclaredMethod("awaitPendingTasks");
|
||||
AWAIT_PENDING.setAccessible(true);
|
||||
} catch (Exception ex) {
|
||||
throw new ExceptionInInitializerError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void setBootedHook(BooleanSupplier supplier) throws IllegalAccessException {
|
||||
IS_BOOTED.set(null, supplier);
|
||||
}
|
||||
|
||||
static void awaitPending() {
|
||||
try {
|
||||
AWAIT_PENDING.invoke(null);
|
||||
} catch (IllegalAccessException | IllegalArgumentException
|
||||
| InvocationTargetException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.ByteArrayOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import jdk.internal.logger.BootstrapLogger;
|
||||
|
||||
/**
|
||||
* We use an instance of this class to check what the logging system has printed
|
||||
* on System.err.
|
||||
*/
|
||||
class LogStream extends OutputStream {
|
||||
|
||||
static final PrintStream err = System.err;
|
||||
|
||||
private final ByteArrayOutputStream BAOS = new ByteArrayOutputStream();
|
||||
|
||||
LogStream() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(int b) {
|
||||
BAOS.write(b);
|
||||
err.write(b);
|
||||
}
|
||||
|
||||
String drain() {
|
||||
BootstrapLoggerUtils.awaitPending();
|
||||
synchronized (this) {
|
||||
String txt = BAOS.toString();
|
||||
BAOS.reset();
|
||||
return txt;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user