use thread name formtting as simple formatter for default, remove png logging
This commit is contained in:
parent
81f3cc723d
commit
b2ec110f85
10 changed files with 138 additions and 478 deletions
|
@ -72,7 +72,7 @@ public final class LogContext implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final HashMap<String, Reference<Level, Void>> map = new HashMap<String, Reference<Level, Void>>();
|
final HashMap<String, Reference<Level, Void>> map = new HashMap<>();
|
||||||
addStrong(map, Level.OFF);
|
addStrong(map, Level.OFF);
|
||||||
addStrong(map, Level.ALL);
|
addStrong(map, Level.ALL);
|
||||||
addStrong(map, Level.SEVERE);
|
addStrong(map, Level.SEVERE);
|
||||||
|
|
|
@ -8,6 +8,7 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ServiceConfigurationError;
|
import java.util.ServiceConfigurationError;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
@ -22,12 +23,17 @@ public final class LogManager extends java.util.logging.LogManager {
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
// Ensure the StandardOutputStreams are initialized early to capture the current System.out and System.err.
|
// Ensure the StandardOutputStreams are initialized early to capture the current System.out and System.err.
|
||||||
Class.forName(StandardOutputStreams.class.getName());
|
ClassLoader.getSystemClassLoader().loadClass(StandardOutputStreams.class.getName());
|
||||||
} catch (ClassNotFoundException ignore) {
|
} catch (ClassNotFoundException ignore) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final AtomicBoolean CONFIGURED = new AtomicBoolean();
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
private final AtomicReference<LogContextConfigurator> configuratorRef = new AtomicReference<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new logmanager instance. Attempts to plug a known memory leak in {@link java.util.logging.Level} as
|
* Construct a new logmanager instance. Attempts to plug a known memory leak in {@link java.util.logging.Level} as
|
||||||
* well.
|
* well.
|
||||||
|
@ -35,25 +41,118 @@ public final class LogManager extends java.util.logging.LogManager {
|
||||||
public LogManager() {
|
public LogManager() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configuration
|
|
||||||
|
|
||||||
private final AtomicReference<LogContextConfigurator> configuratorRef = new AtomicReference<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure the system log context initially.
|
* Configure the system log context initially.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void readConfiguration() {
|
public void readConfiguration() {
|
||||||
|
if (CONFIGURED.compareAndSet(false, true)) {
|
||||||
doConfigure(null);
|
doConfigure(null);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure the system log context initially withe given input stream.
|
* Configure the system log context initially with a given input stream.
|
||||||
*
|
*
|
||||||
* @param inputStream ignored
|
* @param inputStream the input stream
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void readConfiguration(InputStream inputStream) {
|
public void readConfiguration(InputStream inputStream) {
|
||||||
|
if (CONFIGURED.compareAndSet(false, true)) {
|
||||||
doConfigure(inputStream);
|
doConfigure(inputStream);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing.
|
||||||
|
*
|
||||||
|
* @param mapper not used
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateConfiguration(final Function<String, BiFunction<String, String, String>> mapper) throws IOException {
|
||||||
|
// no operation - the configuration API should be used
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing.
|
||||||
|
*
|
||||||
|
* @param ins not used
|
||||||
|
* @param mapper not used
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateConfiguration(final InputStream ins, final Function<String, BiFunction<String, String, String>> mapper)
|
||||||
|
throws IOException {
|
||||||
|
// no operation - the configuration API should be used
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration listeners are not currently supported.
|
||||||
|
*
|
||||||
|
* @param listener not used
|
||||||
|
* @return this log manager
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public java.util.logging.LogManager addConfigurationListener(final Runnable listener) {
|
||||||
|
// no operation
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration listeners are not currently supported.
|
||||||
|
*
|
||||||
|
* @param listener not used
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void removeConfigurationListener(final Runnable listener) {
|
||||||
|
// no operation
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing. Properties are not supported.
|
||||||
|
*
|
||||||
|
* @param name ignored
|
||||||
|
* @return {@code null}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getProperty(String name) {
|
||||||
|
// no properties
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing. This method only causes trouble.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
// no operation!
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enumeration<String> getLoggerNames() {
|
||||||
|
return LogContext.getLogContext().getLoggerNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do nothing. Loggers are only added/acquired via {@link #getLogger(String)}.
|
||||||
|
*
|
||||||
|
* @param logger ignored
|
||||||
|
* @return {@code false}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean addLogger(java.util.logging.Logger logger) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or create a logger with the given name.
|
||||||
|
*
|
||||||
|
* @param name the logger name
|
||||||
|
* @return the corresponding logger
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Logger getLogger(String name) {
|
||||||
|
return LogContext.getLogContext().getLogger(name);
|
||||||
|
}
|
||||||
|
|
||||||
private void doConfigure(InputStream inputStream) {
|
private void doConfigure(InputStream inputStream) {
|
||||||
final AtomicReference<LogContextConfigurator> configuratorRef = this.configuratorRef;
|
final AtomicReference<LogContextConfigurator> configuratorRef = this.configuratorRef;
|
||||||
|
@ -100,87 +199,4 @@ public final class LogManager extends java.util.logging.LogManager {
|
||||||
}
|
}
|
||||||
configurator.configure(LogContext.getSystemLogContext(), inputStream);
|
configurator.configure(LogContext.getSystemLogContext(), inputStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Does nothing.
|
|
||||||
*
|
|
||||||
* @param mapper not used
|
|
||||||
*/
|
|
||||||
public void updateConfiguration(final Function<String, BiFunction<String, String, String>> mapper) throws IOException {
|
|
||||||
// no operation the configuration API should be used
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does nothing.
|
|
||||||
*
|
|
||||||
* @param ins not used
|
|
||||||
* @param mapper not used
|
|
||||||
*/
|
|
||||||
public void updateConfiguration(final InputStream ins, final Function<String, BiFunction<String, String, String>> mapper)
|
|
||||||
throws IOException {
|
|
||||||
// no operation the configuration API should be used
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configuration listeners are not currently supported.
|
|
||||||
*
|
|
||||||
* @param listener not used
|
|
||||||
* @return this log manager
|
|
||||||
*/
|
|
||||||
public java.util.logging.LogManager addConfigurationListener(final Runnable listener) {
|
|
||||||
// no operation
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configuration listeners are not currently supported.
|
|
||||||
*
|
|
||||||
* @param listener not used
|
|
||||||
*/
|
|
||||||
public void removeConfigurationListener(final Runnable listener) {
|
|
||||||
// no operation
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does nothing. Properties are not supported.
|
|
||||||
*
|
|
||||||
* @param name ignored
|
|
||||||
* @return {@code null}
|
|
||||||
*/
|
|
||||||
public String getProperty(String name) {
|
|
||||||
// no properties
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does nothing. This method only causes trouble.
|
|
||||||
*/
|
|
||||||
public void reset() {
|
|
||||||
// no operation!
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Enumeration<String> getLoggerNames() {
|
|
||||||
return LogContext.getLogContext().getLoggerNames();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do nothing. Loggers are only added/acquired via {@link #getLogger(String)}.
|
|
||||||
*
|
|
||||||
* @param logger ignored
|
|
||||||
* @return {@code false}
|
|
||||||
*/
|
|
||||||
public boolean addLogger(java.util.logging.Logger logger) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get or create a logger with the given name.
|
|
||||||
*
|
|
||||||
* @param name the logger name
|
|
||||||
* @return the corresponding logger
|
|
||||||
*/
|
|
||||||
public Logger getLogger(String name) {
|
|
||||||
return LogContext.getLogContext().getLogger(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,8 @@ public class LoggerFinder extends System.LoggerFinder {
|
||||||
final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(name);
|
final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(name);
|
||||||
if (!logger.getClass().getName().equals("org.xbib.logging.Logger")) {
|
if (!logger.getClass().getName().equals("org.xbib.logging.Logger")) {
|
||||||
if (LOGGED.compareAndSet(false, true)) {
|
if (LOGGED.compareAndSet(false, true)) {
|
||||||
logger.log(Level.ERROR,
|
logger.log(Level.WARN,
|
||||||
"The LogManager accessed before the \"java.util.logging.manager\" system property was set to \"org.xbib.loggingr.LogManager\". Results may be unexpected.");
|
"The LogManager accessed before the \"java.util.logging.manager\" system property was set to \"org.xbib.logging.LogManager\". Results may be unexpected.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new SystemLogger(logger);
|
return new SystemLogger(logger);
|
||||||
|
|
|
@ -26,7 +26,6 @@ class ObjectBuilder<T> {
|
||||||
private final Map<String, String> properties;
|
private final Map<String, String> properties;
|
||||||
private final Set<PropertyValue> definedProperties;
|
private final Set<PropertyValue> definedProperties;
|
||||||
private final Set<String> postConstructMethods;
|
private final Set<String> postConstructMethods;
|
||||||
private String moduleName;
|
|
||||||
|
|
||||||
private ObjectBuilder(final ContextConfiguration contextConfiguration,
|
private ObjectBuilder(final ContextConfiguration contextConfiguration,
|
||||||
final Class<? extends T> baseClass, final String className) {
|
final Class<? extends T> baseClass, final String className) {
|
||||||
|
@ -113,7 +112,6 @@ class ObjectBuilder<T> {
|
||||||
* @return this builder
|
* @return this builder
|
||||||
*/
|
*/
|
||||||
ObjectBuilder<T> setModuleName(final String moduleName) {
|
ObjectBuilder<T> setModuleName(final String moduleName) {
|
||||||
this.moduleName = moduleName;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +131,7 @@ class ObjectBuilder<T> {
|
||||||
final ClassLoader classLoader = getClass().getClassLoader();
|
final ClassLoader classLoader = getClass().getClassLoader();
|
||||||
final Class<? extends T> actualClass;
|
final Class<? extends T> actualClass;
|
||||||
try {
|
try {
|
||||||
actualClass = Class.forName(className, true, classLoader).asSubclass(baseClass);
|
actualClass = classLoader.loadClass(className).asSubclass(baseClass);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IllegalArgumentException(String.format("Failed to load class \"%s\"", className), e);
|
throw new IllegalArgumentException(String.format("Failed to load class \"%s\"", className), e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ import java.util.logging.Logger;
|
||||||
import org.xbib.logging.Level;
|
import org.xbib.logging.Level;
|
||||||
import org.xbib.logging.LogContext;
|
import org.xbib.logging.LogContext;
|
||||||
import org.xbib.logging.LogContextConfigurator;
|
import org.xbib.logging.LogContextConfigurator;
|
||||||
import org.xbib.logging.formatters.PatternFormatter;
|
import org.xbib.logging.formatters.SimpleFormatter;
|
||||||
import org.xbib.logging.handlers.ConsoleHandler;
|
import org.xbib.logging.handlers.ConsoleHandler;
|
||||||
import org.xbib.logging.util.StandardOutputStreams;
|
import org.xbib.logging.util.StandardOutputStreams;
|
||||||
|
|
||||||
|
@ -60,11 +60,11 @@ public class PropertyLogContextConfigurator implements LogContextConfigurator {
|
||||||
final Iterator<LogContextConfigurator> serviceLoader =
|
final Iterator<LogContextConfigurator> serviceLoader =
|
||||||
ServiceLoader.load(LogContextConfigurator.class, PropertyLogContextConfigurator.class.getClassLoader()).iterator();
|
ServiceLoader.load(LogContextConfigurator.class, PropertyLogContextConfigurator.class.getClassLoader()).iterator();
|
||||||
if (serviceLoader.hasNext()) {
|
if (serviceLoader.hasNext()) {
|
||||||
serviceLoader.next().configure(context, null);
|
LogContextConfigurator logContextConfigurator = serviceLoader.next();
|
||||||
|
logContextConfigurator.configure(context, null);
|
||||||
} else {
|
} else {
|
||||||
// Configure a default console handler, pattern formatter and associated with the root logger
|
// Configure a default console handler, thread formatter and associated with the root logger
|
||||||
final ConsoleHandler handler =
|
final ConsoleHandler handler = new ConsoleHandler(new SimpleFormatter());
|
||||||
new ConsoleHandler(new PatternFormatter("%d{yyyy-MM-dd'T'HH:mm:ssXXX} %-5p [%c] (%t) %s%e%n"));
|
|
||||||
handler.setLevel(Level.INFO);
|
handler.setLevel(Level.INFO);
|
||||||
handler.setAutoFlush(true);
|
handler.setAutoFlush(true);
|
||||||
final Logger rootLogger = context.getLogger("");
|
final Logger rootLogger = context.getLogger("");
|
||||||
|
@ -75,7 +75,7 @@ public class PropertyLogContextConfigurator implements LogContextConfigurator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InputStream findConfiguration() {
|
private static InputStream findConfiguration() {
|
||||||
final String propLoc = System.getProperty("logging.configuration");
|
final String propLoc = System.getProperty("org.xbib.logging.configuration");
|
||||||
if (propLoc != null) {
|
if (propLoc != null) {
|
||||||
try {
|
try {
|
||||||
return URI.create(propLoc).toURL().openStream();
|
return URI.create(propLoc).toURL().openStream();
|
||||||
|
@ -83,10 +83,9 @@ public class PropertyLogContextConfigurator implements LogContextConfigurator {
|
||||||
StandardOutputStreams.printError("Unable to read the logging configuration from '%s' (%s)%n", propLoc, e);
|
StandardOutputStreams.printError("Unable to read the logging configuration from '%s' (%s)%n", propLoc, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final ClassLoader cl = PropertyLogContextConfigurator.class.getClassLoader();
|
|
||||||
try {
|
try {
|
||||||
return cl.getResourceAsStream("logging.properties");
|
return PropertyLogContextConfigurator.class.getClassLoader().getResourceAsStream("logging.properties");
|
||||||
} catch (Exception ignore) {
|
} catch (Exception e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,16 +10,16 @@ import java.util.logging.LogManager;
|
||||||
import java.util.logging.LogRecord;
|
import java.util.logging.LogRecord;
|
||||||
import org.xbib.logging.util.StackTraceFormatter;
|
import org.xbib.logging.util.StackTraceFormatter;
|
||||||
|
|
||||||
public class ThreadLoggingFormatter extends Formatter {
|
public class SimpleFormatter extends Formatter {
|
||||||
|
|
||||||
private static final String PROPERTY_KEY = "org.xbib.interlibrary.jul.ThreadLoggingFormatter.format";
|
private static final String PROPERTY_KEY = "org.xbib.logging.formatters.SimpleFormatter.format";
|
||||||
|
|
||||||
private static final String DEFAULT_FORMAT =
|
private static final String DEFAULT_FORMAT =
|
||||||
"%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$-7s [%3$s] [%5$s] %6$s %7$s%n";
|
"%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$-7s [%3$s] [%5$s] %6$s %7$s%n";
|
||||||
|
|
||||||
private final ThreadMXBean threadMXBean;
|
private final ThreadMXBean threadMXBean;
|
||||||
|
|
||||||
public ThreadLoggingFormatter() {
|
public SimpleFormatter() {
|
||||||
this.threadMXBean = ManagementFactory.getThreadMXBean();
|
this.threadMXBean = ManagementFactory.getThreadMXBean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ public class ThreadLoggingFormatter extends Formatter {
|
||||||
return LogManager.getLogManager().getProperty(name);
|
return LogManager.getLogManager().getProperty(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String DEFAULT_FORMAT_STRING = getFormat(ThreadLoggingFormatter::getLoggingProperty);
|
private static final String DEFAULT_FORMAT_STRING = getFormat(SimpleFormatter::getLoggingProperty);
|
||||||
|
|
||||||
private static String getFormat(Function<String, String> defaultPropertyGetter) {
|
private static String getFormat(Function<String, String> defaultPropertyGetter) {
|
||||||
String format = System.getProperty(PROPERTY_KEY);
|
String format = System.getProperty(PROPERTY_KEY);
|
|
@ -1,14 +1,9 @@
|
||||||
package org.xbib.logging.handlers;
|
package org.xbib.logging.handlers;
|
||||||
|
|
||||||
import java.io.Console;
|
import java.io.Console;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.logging.ErrorManager;
|
import java.util.logging.ErrorManager;
|
||||||
import java.util.logging.Formatter;
|
import java.util.logging.Formatter;
|
||||||
import org.xbib.logging.errormanager.HandlerErrorManager;
|
import org.xbib.logging.errormanager.HandlerErrorManager;
|
||||||
|
@ -136,83 +131,6 @@ public class ConsoleHandler extends OutputStreamHandler {
|
||||||
|
|
||||||
private static final String ESC = Character.toString(27);
|
private static final String ESC = Character.toString(27);
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a PNG image to the console log, if it is supported.
|
|
||||||
* The image data stream must be closed by the caller.
|
|
||||||
*
|
|
||||||
* @param imageData the PNG image data stream to write (must not be {@code null})
|
|
||||||
* @param columns the number of text columns to occupy (0 for automatic)
|
|
||||||
* @param rows the number of text rows to occupy (0 for automatic)
|
|
||||||
* @return {@code true} if the image was written, or {@code false} if image support isn't found
|
|
||||||
* @throws IOException if the stream failed while writing the image
|
|
||||||
*/
|
|
||||||
public boolean writeImagePng(InputStream imageData, int columns, int rows) throws IOException {
|
|
||||||
Objects.requireNonNull(imageData, "imageData");
|
|
||||||
columns = Math.max(0, columns);
|
|
||||||
rows = Math.max(0, rows);
|
|
||||||
if (!isGraphicsSupportPassivelyDetected()) {
|
|
||||||
// no graphics
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
// clear out any pending stuff
|
|
||||||
final Writer writer = getWriter();
|
|
||||||
if (writer == null)
|
|
||||||
return false;
|
|
||||||
// start with the header
|
|
||||||
try (OutputStream os = Base64.getEncoder().wrap(new OutputStream() {
|
|
||||||
final byte[] buffer = new byte[2048];
|
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
public void write(final int b) throws IOException {
|
|
||||||
if (pos == buffer.length)
|
|
||||||
more();
|
|
||||||
buffer[pos++] = (byte) b;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(final byte[] b, int off, int len) throws IOException {
|
|
||||||
while (len > 0) {
|
|
||||||
if (pos == buffer.length) {
|
|
||||||
more();
|
|
||||||
}
|
|
||||||
final int cnt = Math.min(len, buffer.length - pos);
|
|
||||||
System.arraycopy(b, off, buffer, pos, cnt);
|
|
||||||
pos += cnt;
|
|
||||||
off += cnt;
|
|
||||||
len -= cnt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void more() throws IOException {
|
|
||||||
writer.write("m=1;");
|
|
||||||
writer.write(new String(buffer, 0, pos, StandardCharsets.US_ASCII));
|
|
||||||
writer.write(ESC + "\\");
|
|
||||||
// set up next segment
|
|
||||||
writer.write(ESC + "_G");
|
|
||||||
pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() throws IOException {
|
|
||||||
writer.write("m=0;");
|
|
||||||
writer.write(new String(buffer, 0, pos, StandardCharsets.US_ASCII));
|
|
||||||
writer.write(ESC + "\\\n");
|
|
||||||
writer.flush();
|
|
||||||
pos = 0;
|
|
||||||
}
|
|
||||||
})) {
|
|
||||||
// set the header
|
|
||||||
writer.write(String.format(ESC + "_Gf=100,a=T,c=%d,r=%d,", Integer.valueOf(columns), Integer.valueOf(rows)));
|
|
||||||
// write the data in encoded chunks
|
|
||||||
imageData.transferTo(os);
|
|
||||||
}
|
|
||||||
// OK
|
|
||||||
return true;
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the local error manager. This is an error manager that will publish errors to this console handler.
|
* Get the local error manager. This is an error manager that will publish errors to this console handler.
|
||||||
* The console handler itself should not use this error manager.
|
* The console handler itself should not use this error manager.
|
||||||
|
@ -264,24 +182,4 @@ public class ConsoleHandler extends OutputStreamHandler {
|
||||||
final String colorterm = System.getenv("COLORTERM");
|
final String colorterm = System.getenv("COLORTERM");
|
||||||
return colorterm != null && (colorterm.contains("truecolor") || colorterm.contains("24bit"));
|
return colorterm != null && (colorterm.contains("truecolor") || colorterm.contains("24bit"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the console can be passively detected to support graphical output.
|
|
||||||
* This call may be expensive, so the result should be captured for the lifetime of any formatter making use of
|
|
||||||
* this information.
|
|
||||||
*
|
|
||||||
* @return {@code true} if the console exists and supports graphical output; {@code false} otherwise or if
|
|
||||||
* graphical support cannot be passively detected
|
|
||||||
*/
|
|
||||||
public static boolean isGraphicsSupportPassivelyDetected() {
|
|
||||||
if (!hasConsole()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final String term = System.getenv("TERM");
|
|
||||||
final String termProgram = System.getenv("TERM_PROGRAM");
|
|
||||||
return term != null && (term.equalsIgnoreCase("kitty")
|
|
||||||
|| term.equalsIgnoreCase("xterm-kitty")
|
|
||||||
|| term.equalsIgnoreCase("wezterm")
|
|
||||||
|| term.equalsIgnoreCase("konsole")) || termProgram != null && termProgram.equalsIgnoreCase("wezterm");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
package org.xbib.logging.handlers;
|
|
||||||
|
|
||||||
import java.util.logging.LogRecord;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replacement for java.util.logging.ConsoleHandler.
|
|
||||||
*/
|
|
||||||
public class ThreadLoggingHandler extends ThreadLoggingStreamHandler {
|
|
||||||
|
|
||||||
public ThreadLoggingHandler() {
|
|
||||||
super();
|
|
||||||
this.setOutputStream(System.out);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void publish(LogRecord record) {
|
|
||||||
super.publish(record);
|
|
||||||
this.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
this.flush();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,220 +0,0 @@
|
||||||
package org.xbib.logging.handlers;
|
|
||||||
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
import java.util.logging.Handler;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.LogRecord;
|
|
||||||
import org.xbib.logging.formatters.ThreadLoggingFormatter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replacement for java.util.logging.StreamHandler that is wired to the ThreadLoggingFormatter
|
|
||||||
* and does not use any fall-back formatter
|
|
||||||
*/
|
|
||||||
public class ThreadLoggingStreamHandler extends Handler {
|
|
||||||
|
|
||||||
private static final ThreadLoggingFormatter formatter = new ThreadLoggingFormatter();
|
|
||||||
|
|
||||||
private final ReentrantLock lock;
|
|
||||||
|
|
||||||
private OutputStream output;
|
|
||||||
|
|
||||||
private boolean doneHeader;
|
|
||||||
|
|
||||||
private volatile Writer writer;
|
|
||||||
|
|
||||||
public ThreadLoggingStreamHandler() {
|
|
||||||
super();
|
|
||||||
this.lock = this.initLocking();
|
|
||||||
setLevel(Level.ALL);
|
|
||||||
setFilter(null);
|
|
||||||
setFormatter(formatter);
|
|
||||||
try {
|
|
||||||
setEncoding("UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
// can't happen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setOutputStream(OutputStream out) {
|
|
||||||
if (this.tryUseLock()) {
|
|
||||||
try {
|
|
||||||
this.setOutputStream0(out);
|
|
||||||
} finally {
|
|
||||||
this.unlock();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
synchronized (this) {
|
|
||||||
this.setOutputStream0(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setOutputStream0(OutputStream out) {
|
|
||||||
if (out == null) {
|
|
||||||
throw new NullPointerException();
|
|
||||||
} else {
|
|
||||||
this.flushAndClose();
|
|
||||||
this.output = out;
|
|
||||||
this.doneHeader = false;
|
|
||||||
String encoding = this.getEncoding();
|
|
||||||
if (encoding == null) {
|
|
||||||
this.writer = new OutputStreamWriter(this.output);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
this.writer = new OutputStreamWriter(this.output, encoding);
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
throw new Error("Unexpected exception " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEncoding(String encoding) throws UnsupportedEncodingException {
|
|
||||||
if (this.tryUseLock()) {
|
|
||||||
try {
|
|
||||||
this.setEncoding0(encoding);
|
|
||||||
} finally {
|
|
||||||
this.unlock();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
synchronized (this) {
|
|
||||||
this.setEncoding0(encoding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setEncoding0(String encoding) throws UnsupportedEncodingException {
|
|
||||||
super.setEncoding(encoding);
|
|
||||||
if (this.output != null) {
|
|
||||||
this.flush();
|
|
||||||
if (encoding == null) {
|
|
||||||
this.writer = new OutputStreamWriter(this.output);
|
|
||||||
} else {
|
|
||||||
this.writer = new OutputStreamWriter(this.output, encoding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void publish(LogRecord record) {
|
|
||||||
if (this.tryUseLock()) {
|
|
||||||
try {
|
|
||||||
this.publish0(record);
|
|
||||||
} finally {
|
|
||||||
this.unlock();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
synchronized (this) {
|
|
||||||
this.publish0(record);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void publish0(LogRecord record) {
|
|
||||||
if (this.isLoggable(record)) {
|
|
||||||
String msg;
|
|
||||||
try {
|
|
||||||
msg = this.getFormatter().format(record);
|
|
||||||
} catch (Exception e) {
|
|
||||||
this.reportError(null, e, 5);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (!this.doneHeader) {
|
|
||||||
this.writer.write(this.getFormatter().getHead(this));
|
|
||||||
this.doneHeader = true;
|
|
||||||
}
|
|
||||||
this.writer.write(msg);
|
|
||||||
} catch (Exception e) {
|
|
||||||
this.reportError(null, e, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLoggable(LogRecord record) {
|
|
||||||
return this.writer != null && record != null && super.isLoggable(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void flush() {
|
|
||||||
if (this.tryUseLock()) {
|
|
||||||
try {
|
|
||||||
this.flush0();
|
|
||||||
} finally {
|
|
||||||
this.unlock();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
synchronized (this) {
|
|
||||||
this.flush0();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void flush0() {
|
|
||||||
if (this.writer != null) {
|
|
||||||
try {
|
|
||||||
this.writer.flush();
|
|
||||||
} catch (Exception e) {
|
|
||||||
this.reportError(null, e, 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void flushAndClose() {
|
|
||||||
if (this.writer != null) {
|
|
||||||
try {
|
|
||||||
if (!this.doneHeader) {
|
|
||||||
this.writer.write(this.getFormatter().getHead(this));
|
|
||||||
this.doneHeader = true;
|
|
||||||
}
|
|
||||||
this.writer.write(this.getFormatter().getTail(this));
|
|
||||||
this.writer.flush();
|
|
||||||
this.writer.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
this.reportError(null, e, 3);
|
|
||||||
}
|
|
||||||
this.writer = null;
|
|
||||||
this.output = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
if (this.tryUseLock()) {
|
|
||||||
try {
|
|
||||||
this.flushAndClose();
|
|
||||||
} finally {
|
|
||||||
this.unlock();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
synchronized (this) {
|
|
||||||
this.flushAndClose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ReentrantLock initLocking() {
|
|
||||||
Class<?> clazz = this.getClass();
|
|
||||||
ClassLoader loader = clazz.getClassLoader();
|
|
||||||
return loader != null && loader != ClassLoader.getPlatformClassLoader() ? null : new ReentrantLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean tryUseLock() {
|
|
||||||
if (this.lock == null) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
this.lock.lock();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void unlock() {
|
|
||||||
this.lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,6 +7,7 @@ import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.logging.Formatter;
|
import java.util.logging.Formatter;
|
||||||
import java.util.logging.Handler;
|
import java.util.logging.Handler;
|
||||||
import java.util.logging.LogRecord;
|
import java.util.logging.LogRecord;
|
||||||
|
@ -29,11 +30,11 @@ public final class HandlerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNullHandler() {
|
public void testNullHandler() {
|
||||||
final ExtHandler handler = new ExtHandler() {
|
try (final ExtHandler handler = new ExtHandler() {}) {
|
||||||
};
|
|
||||||
handler.setLevel(Level.ALL);
|
handler.setLevel(Level.ALL);
|
||||||
handler.publish(new ExtLogRecord(Level.INFO, "Test message", null));
|
handler.publish(new ExtLogRecord(Level.INFO, "Test message", null));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void initHandler(ExtHandler handler) throws UnsupportedEncodingException {
|
private void initHandler(ExtHandler handler) throws UnsupportedEncodingException {
|
||||||
handler.setFormatter(testFormatter);
|
handler.setFormatter(testFormatter);
|
||||||
|
@ -67,7 +68,7 @@ public final class HandlerTests {
|
||||||
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
handler.setOutputStream(stream);
|
handler.setOutputStream(stream);
|
||||||
testPublish(handler);
|
testPublish(handler);
|
||||||
assertEquals("Test message", new String(stream.toByteArray(), "utf-8"));
|
assertEquals("Test message", stream.toString(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -85,20 +86,13 @@ public final class HandlerTests {
|
||||||
handler.setFile(tempFile);
|
handler.setFile(tempFile);
|
||||||
testPublish(handler);
|
testPublish(handler);
|
||||||
handler.close();
|
handler.close();
|
||||||
final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
try (ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
try {
|
FileInputStream is = new FileInputStream(tempFile)) {
|
||||||
final FileInputStream is = new FileInputStream(tempFile);
|
|
||||||
try {
|
|
||||||
int r;
|
int r;
|
||||||
while ((r = is.read()) != -1)
|
while ((r = is.read()) != -1)
|
||||||
os.write(r);
|
os.write(r);
|
||||||
assertEquals("Test message", new String(os.toByteArray(), "utf-8"));
|
assertEquals("Test message", os.toString(StandardCharsets.UTF_8));
|
||||||
tempFile.deleteOnExit();
|
tempFile.deleteOnExit();
|
||||||
} finally {
|
|
||||||
is.close();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
os.close();
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
tempFile.delete();
|
tempFile.delete();
|
||||||
|
@ -106,7 +100,7 @@ public final class HandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEnableDisableHandler() throws Throwable {
|
public void testEnableDisableHandler() {
|
||||||
final StringListHandler handler = new StringListHandler();
|
final StringListHandler handler = new StringListHandler();
|
||||||
testPublish(handler);
|
testPublish(handler);
|
||||||
assertEquals(1, handler.size());
|
assertEquals(1, handler.size());
|
||||||
|
|
Loading…
Reference in a new issue