From 05a568dcce9260c302af1ac19dea4023c3099557 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Sun, 23 Feb 2014 01:52:50 -0600 Subject: [PATCH] PrintStream API update. - Add getLoggerStream to LogManager. - Add getLoggerStream to LoggerContext. - Extract interface for LoggerStream. - Remove getStream from Logger. --- .../java/org/apache/logging/log4j/LogManager.java | 56 ++++ .../main/java/org/apache/logging/log4j/Logger.java | 18 -- .../org/apache/logging/log4j/LoggerStream.java | 83 ++++++ .../logging/log4j/simple/SimpleLoggerContext.java | 15 +- .../logging/log4j/simple/SimpleLoggerStream.java | 297 +++++++++++++++++++++ .../apache/logging/log4j/spi/AbstractLogger.java | 27 +- .../logging/log4j/spi/AbstractLoggerContext.java | 37 +++ .../apache/logging/log4j/spi/LoggerContext.java | 19 ++ .../org/apache/logging/log4j/spi/LoggerStream.java | 290 -------------------- .../org/apache/logging/log4j/LogManagerTest.java | 39 ++- .../java/org/apache/logging/log4j/LoggerTest.java | 35 ++- .../apache/logging/log4j/TestLoggerContext.java | 17 +- .../apache/logging/log4j/spi/LoggerStreamTest.java | 21 +- .../apache/logging/log4j/core/LoggerContext.java | 3 +- .../log4j/taglib/Log4jTaglibLoggerContext.java | 3 +- .../apache/logging/slf4j/SLF4JLoggerContext.java | 3 +- 16 files changed, 587 insertions(+), 376 deletions(-) create mode 100644 log4j-api/src/main/java/org/apache/logging/log4j/LoggerStream.java create mode 100644 log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerStream.java create mode 100644 log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLoggerContext.java delete mode 100644 log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerStream.java diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java b/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java index bc75df5..565d231 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java @@ -478,6 +478,62 @@ public class LogManager { } /** + * Returns a LoggerStream with the name of the calling class. Uses a default level of ALL. + * @return A new LoggerStream. + */ + public static LoggerStream getLoggerStream() { + return getLoggerStream(getClassName(2)); + } + + /** + * Returns a LoggerStream with the specified name. Uses a default level of ALL. + * + * @param name The logger name. If null it will default to the name of the calling class. + * @return A new LoggerStream. + */ + public static LoggerStream getLoggerStream(final String name) { + final String actualName = name != null ? name : getClassName(2); + return getContext().getLoggerStream(actualName); + } + + /** + * Returns a named LoggerStream using a specific MessageFactory. Uses a default level of ALL. + * + * @param name The logger name. If null it will default to the name of the calling class. + * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change + * the logger but will log a warning if mismatched. + * @return A new LoggerStream. + */ + public static LoggerStream getLoggerStream(final String name, final MessageFactory messageFactory) { + final String actualName = name != null ? name : getClassName(2); + return getContext().getLoggerStream(actualName, messageFactory); + } + + /** + * Returns a LoggerStream named after the specified class. Uses a default level of ALL. + * + * @param clazz The Class whose name should be used as the Logger name. If null it will default to the calling + * class. + * @return A new LoggerStream. + */ + public static LoggerStream getLoggerStream(final Class clazz) { + return getLoggerStream(clazz != null ? clazz.getName() : getClassName(2)); + } + + /** + * Returns a class-named LoggerStream using a specific MessageFactory. Uses a default level of ALL. + * + * @param clazz The Class whose name should be used as the Logger name. If null it will default to the + * calling class. + * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change + * the logger but will log a warning if mismatched. + * @return A new LoggerStream. + */ + public static LoggerStream getLoggerStream(final Class clazz, final MessageFactory messageFactory) { + return getLoggerStream(clazz != null ? clazz.getName() : getClassName(2), messageFactory); + } + + /** * Prevents instantiation */ protected LogManager() { diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java b/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java index fb339d6..c5327c7 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java @@ -18,7 +18,6 @@ package org.apache.logging.log4j; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.MessageFactory; -import org.apache.logging.log4j.spi.LoggerStream; /** * This is the central interface in the log4j package. Most logging operations, except configuration, are done through @@ -464,23 +463,6 @@ public interface Logger { String getName(); /** - * Gets a print stream that logs lines to this logger. - * - * @param level the logging level - * @return print stream that logs printed lines to this logger. - */ - LoggerStream getStream(Level level); - - /** - * Gets a marked print stream that logs lines to this logger. - * - * @param marker the marker data specific to this log statement - * @param level the logging level - * @return print stream that logs printed lines to this logger. - */ - LoggerStream getStream(Marker marker, Level level); - - /** * Logs a message with the specific Marker at the {@link Level#INFO INFO} level. * * @param marker the marker data specific to this log statement diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/LoggerStream.java b/log4j-api/src/main/java/org/apache/logging/log4j/LoggerStream.java new file mode 100644 index 0000000..ebb5b10 --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/LoggerStream.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.logging.log4j; + +import java.io.Closeable; +import java.io.Flushable; +import java.io.IOException; + +/** + * LoggerStream is a PrintStream-like interface to logging messages. Each line printed to a LoggerStream is considered + * to be a single log message. + */ +public interface LoggerStream extends Closeable, Flushable, Appendable { + + LoggerStream withLevel(Level level); + + LoggerStream withMarker(Marker marker); + + String getName(); + + void println(); + + void print(boolean b); + + void println(boolean b); + + void print(char c); + + void println(char c); + + void print(char[] a); + + void println(char[] a); + + void print(double d); + + void println(double d); + + void print(float f); + + void println(float f); + + void print(int i); + + void println(int i); + + void print(long l); + + void println(long l); + + void print(Object o); + + void println(Object o); + + void print(String s); + + void println(String s); + + void write(byte[] buf, int off, int len) throws IOException; + + void write(byte[] buf) throws IOException; + + void write(int b) throws IOException; + + void printf(String format, Object... args); + + void format(String format, Object... args); +} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java index e1d22f0..512aa86 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java @@ -19,12 +19,12 @@ package org.apache.logging.log4j.simple; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; -import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LoggerStream; import org.apache.logging.log4j.message.MessageFactory; import org.apache.logging.log4j.spi.AbstractLogger; import org.apache.logging.log4j.spi.LoggerContext; @@ -41,9 +41,6 @@ public class SimpleLoggerContext implements LoggerContext { /** All system properties used by SimpleLog start with this */ protected static final String SYSTEM_PREFIX = "org.apache.logging.log4j.simplelog."; - /** Properties loaded from simplelog.properties */ - private final Properties simpleLogProps = new Properties(); - private final PropertiesUtil props; /** Include the instance name in the log message? */ @@ -115,6 +112,16 @@ public class SimpleLoggerContext implements LoggerContext { } @Override + public LoggerStream getLoggerStream(final String name) { + return new SimpleLoggerStream((AbstractLogger) getLogger(name)); + } + + @Override + public LoggerStream getLoggerStream(final String name, final MessageFactory messageFactory) { + return new SimpleLoggerStream((AbstractLogger) getLogger(name, messageFactory)); + } + + @Override public boolean hasLogger(final String name) { return false; } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerStream.java b/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerStream.java new file mode 100644 index 0000000..df2b48d --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerStream.java @@ -0,0 +1,297 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.simple; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LoggerStream; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.spi.AbstractLogger; + +/** + * Output stream that logs each line written to a pre-defined level. Can also + * be configured with a Marker. This class provides an interface that follows + * the {@link java.io.PrintStream} methods in spirit, but doesn't output to + * any external stream. This class should not be used as a stream for an + * underlying logger unless it's being used as a bridge. Otherwise, infinite + * loops may occur! + */ +public class SimpleLoggerStream implements LoggerStream { + + private final PrintStream stream; + private final HelperStream helperStream; + private final String name; + + public SimpleLoggerStream(final AbstractLogger parent) { + helperStream = new HelperStream(parent); + stream = new PrintStream(helperStream, true); + name = parent.getName(); + } + + @Override + public LoggerStream withLevel(final Level level) { + helperStream.setLevel(level); + return this; + } + + @Override + public LoggerStream withMarker(final Marker marker) { + helperStream.setMarker(marker); + return this; + } + + @Override + public void write(int b) { + stream.write(b); + } + + @Override + public void write(byte[] b) throws IOException { + stream.write(b); + } + + @Override + public void write(byte[] b, int off, int len) { + stream.write(b, off, len); + } + + @Override + public void flush() { + stream.flush(); + } + + @Override + public void close() { + stream.close(); + } + + @Override + public void print(boolean b) { + stream.print(b); + } + + @Override + public void print(char c) { + stream.print(c); + } + + @Override + public void print(int i) { + stream.print(i); + } + + @Override + public void print(long l) { + stream.print(l); + } + + @Override + public void print(float f) { + stream.print(f); + } + + @Override + public void print(double d) { + stream.print(d); + } + + @Override + public void print(char[] s) { + stream.print(s); + } + + @Override + public void print(String s) { + stream.print(s); + } + + @Override + public void print(Object obj) { + stream.print(obj); + } + + @Override + public String getName() { + return name; + } + + @Override + public void println() { + stream.println(); + } + + @Override + public void println(boolean x) { + stream.println(x); + } + + @Override + public void println(char x) { + stream.println(x); + } + + @Override + public void println(int x) { + stream.println(x); + } + + @Override + public void println(long x) { + stream.println(x); + } + + @Override + public void println(float x) { + stream.println(x); + } + + @Override + public void println(double x) { + stream.println(x); + } + + @Override + public void println(char[] x) { + stream.println(x); + } + + @Override + public void println(String x) { + stream.println(x); + } + + @Override + public void println(Object x) { + stream.println(x); + } + + @Override + public void printf(String format, Object... args) { + helperStream.printf(format, args); + } + + @Override + public void format(final String format, final Object... args) { + helperStream.printf(format, args); + } + + @Override + public LoggerStream append(char c) { + stream.append(c); + return this; + } + + @Override + public LoggerStream append(CharSequence csq) { + stream.append(csq); + return this; + } + + @Override + public LoggerStream append(CharSequence csq, int start, int end) { + stream.append(csq, start, end); + return this; + } + + @Override + public String toString() { + return "SimpleLoggerStream{" + + "stream=" + stream + + '}'; + } + + @Override + public boolean equals(Object other) { + return this == other + || !(other == null || getClass() != other.getClass()) + && stream.equals(((SimpleLoggerStream) other).stream); + } + + @Override + public int hashCode() { + return stream.hashCode(); + } + + private static class HelperStream extends ByteArrayOutputStream { + private static final String FQCN = SimpleLoggerStream.class.getName(); + private final AbstractLogger logger; + private volatile Level level = Level.ALL; + private volatile Marker marker; + + private HelperStream(final AbstractLogger logger) { + this.logger = logger; + } + + private void setLevel(final Level level) { + this.level = level; + } + + private void setMarker(final Marker marker) { + this.marker = marker; + } + + private void log(int upTo) { + if (upTo < 0 || upTo >= count) { + throw new IndexOutOfBoundsException("Upper bounds: " + count + ". Actual: " + upTo + '.'); + } + final Message message = logger.getMessageFactory().newMessage(extractLine(upTo)); + logger.log(marker, FQCN, level, message, null); + } + + private String extractLine(int upTo) { + final String line = new String(buf, 0, upTo); + leftShiftBuffer(upTo + 1); + return line; + } + + private void leftShiftBuffer(int numBytes) { + int remaining = count - numBytes; + if (remaining > 0) { + System.arraycopy(buf, numBytes, buf, 0, remaining); + count = remaining + 1; + } else { + reset(); + } + } + + @Override + public synchronized void write(int b) { + if (b == '\r') { + return; + } + super.write(b); + if (b == '\n') { + log(count - 1); + } + } + + @Override + public synchronized void write(byte[] b, int off, int len) { + for (int i = 0; i < len; ++i) { + write(b[off + i]); + } + } + + public synchronized void printf(final String format, final Object... args) { + logger.printf(level, marker, format, args); + } + } +} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java index f51887a..519f245 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.spi; +import java.io.Serializable; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Marker; @@ -26,8 +28,6 @@ import org.apache.logging.log4j.message.ParameterizedMessageFactory; import org.apache.logging.log4j.message.StringFormattedMessage; import org.apache.logging.log4j.status.StatusLogger; -import java.io.Serializable; - /** * Base implementation of a Logger. It is highly recommended that any Logger implementation extend this class. */ @@ -850,29 +850,6 @@ public abstract class AbstractLogger implements Logger, Serializable { } /** - * Gets a print stream that logs lines to this logger. - * - * @param level the logging level - * @return print stream that logs printed lines to this logger. - */ - @Override - public LoggerStream getStream(final Level level) { - return new LoggerStream(this, level); - } - - /** - * Gets a marked print stream that logs lines to this logger. - * - * @param marker the marker data specific to this log statement - * @param level the logging level - * @return print stream that logs printed lines to this logger. - */ - @Override - public LoggerStream getStream(Marker marker, Level level) { - return new LoggerStream(this, marker, level); - } - - /** * Logs a message with the specific Marker at the INFO level. * * @param marker the marker data specific to this log statement diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLoggerContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLoggerContext.java new file mode 100644 index 0000000..9a35df6 --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLoggerContext.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.logging.log4j.spi; + +import org.apache.logging.log4j.LoggerStream; +import org.apache.logging.log4j.message.MessageFactory; +import org.apache.logging.log4j.simple.SimpleLoggerStream; + +/** + * Base implementation of a LoggerContext. This provides LoggerStream instances. + */ +public abstract class AbstractLoggerContext implements LoggerContext { + @Override + public LoggerStream getLoggerStream(final String name) { + return new SimpleLoggerStream((AbstractLogger) getLogger(name)); + } + + @Override + public LoggerStream getLoggerStream(final String name, final MessageFactory messageFactory) { + return new SimpleLoggerStream((AbstractLogger) getLogger(name, messageFactory)); + } +} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java index 040ae6a..3565e90 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java @@ -17,6 +17,7 @@ package org.apache.logging.log4j.spi; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LoggerStream; import org.apache.logging.log4j.message.MessageFactory; /** @@ -47,6 +48,24 @@ public interface LoggerContext { Logger getLogger(String name, MessageFactory messageFactory); /** + * Returns a named LoggerStream using the default logging level {@link org.apache.logging.log4j.Level#ALL ALL}. + * @param name The name of the Logger to return. + * @return The newly created LoggerStream with the specified name. + */ + LoggerStream getLoggerStream(String name); + + /** + * Returns a customized LoggerStream using a specified MessageFactory at the default logging level + * {@link org.apache.logging.log4j.Level#ALL ALL}. + * + * @param name The name of the Logger to return. + * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change + * the logger but will log a warning if mismatched. + * @return The newly created LoggerStream logging at {@code ALL}. + */ + LoggerStream getLoggerStream(String name, MessageFactory messageFactory); + + /** * Detects if a Logger with the specified name exists. * @param name The Logger name to search for. * @return true if the Logger exists, false otherwise. diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerStream.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerStream.java deleted file mode 100644 index 4e4e72e..0000000 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerStream.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.spi; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.message.Message; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.util.Locale; - -/** - * Output stream that logs each line written to a pre-defined level. Can also - * be configured with a Marker. This class provides an interface that follows - * the {@link java.io.PrintStream} methods in spirit, but doesn't output to - * any external stream. This class should not be used as a stream for an - * underlying logger unless it's being used as a bridge. Otherwise, infinite - * loops may occur! - */ -public class LoggerStream extends PrintStream { - - final PrintStream stream; - - public LoggerStream(final AbstractLogger logger, final Level level) { - super(System.out); - stream = new PrintStream(new HelperStream(logger, null, level), true); - } - - public LoggerStream(final AbstractLogger logger, final Marker marker, final Level level) { - super(System.out); - stream = new PrintStream(new HelperStream(logger, marker, level), true); - } - - @Override - public void write(int b) { - stream.write(b); - } - - @Override - public void write(byte[] b) throws IOException { - stream.write(b); - } - - @Override - public void write(byte[] b, int off, int len) { - stream.write(b, off, len); - } - - @Override - public void flush() { - stream.flush(); - } - - @Override - public void close() { - stream.close(); - } - - @Override - public void print(boolean b) { - stream.print(b); - } - - @Override - public void print(char c) { - stream.print(c); - } - - @Override - public void print(int i) { - stream.print(i); - } - - @Override - public void print(long l) { - stream.print(l); - } - - @Override - public void print(float f) { - stream.print(f); - } - - @Override - public void print(double d) { - stream.print(d); - } - - @Override - public void print(char[] s) { - stream.print(s); - } - - @Override - public void print(String s) { - stream.print(s); - } - - @Override - public void print(Object obj) { - stream.print(obj); - } - - @Override - public void println() { - stream.println(); - } - - @Override - public void println(boolean x) { - stream.println(x); - } - - @Override - public void println(char x) { - stream.println(x); - } - - @Override - public void println(int x) { - stream.println(x); - } - - @Override - public void println(long x) { - stream.println(x); - } - - @Override - public void println(float x) { - stream.println(x); - } - - @Override - public void println(double x) { - stream.println(x); - } - - @Override - public void println(char[] x) { - stream.println(x); - } - - @Override - public void println(String x) { - stream.println(x); - } - - @Override - public void println(Object x) { - stream.println(x); - } - - @Override - public LoggerStream printf(String format, Object... args) { - stream.printf(format, args); - return this; - } - - @Override - public LoggerStream printf(Locale l, String format, Object... args) { - stream.printf(l, format, args); - return this; - } - - @Override - public LoggerStream append(char c) { - stream.append(c); - return this; - } - - @Override - public LoggerStream append(CharSequence csq) { - stream.append(csq); - return this; - } - - @Override - public LoggerStream append(CharSequence csq, int start, int end) { - stream.append(csq, start, end); - return this; - } - - @Override - public LoggerStream format(String format, Object... args) { - stream.format(format, args); - return this; - } - - @Override - public LoggerStream format(Locale l, String format, Object... args) { - stream.format(l, format, args); - return this; - } - - @Override - public boolean checkError() { - return stream.checkError(); - } - - @Override - public String toString() { - return "LoggerStream{" + - "stream=" + stream + - '}'; - } - - @Override - public boolean equals(Object other) { - return this == other - || !(other == null || getClass() != other.getClass()) - && stream.equals(((LoggerStream) other).stream); - } - - @Override - public int hashCode() { - return stream.hashCode(); - } - - private static class HelperStream extends ByteArrayOutputStream { - private static final String FQCN = LoggerStream.class.getName(); - private final AbstractLogger logger; - private final Level level; - private final Marker marker; - - private HelperStream(AbstractLogger logger, Marker marker, Level level) { - this.logger = logger; - this.marker = marker; - this.level = level; - } - - private void log(int upTo) { - if (upTo < 0 || upTo >= count) { - throw new IndexOutOfBoundsException(); - } - final Message message = logger.getMessageFactory().newMessage(extractLine(upTo)); - logger.log(marker, FQCN, level, message, null); - } - - private String extractLine(int upTo) { - final String line = new String(buf, 0, upTo); - leftShiftBuffer(upTo + 1); - return line; - } - - private void leftShiftBuffer(int numBytes) { - int remaining = count - numBytes; - if (remaining > 0) { - System.arraycopy(buf, numBytes, buf, 0, remaining); - count = remaining + 1; - } else { - reset(); - } - } - - @Override - public synchronized void write(int b) { - if (b == '\r') { - return; - } - super.write(b); - if (b == '\n') { - log(count - 1); - } - } - - @Override - public synchronized void write(byte[] b, int off, int len) { - for (int i = 0; i < len; ++i) { - write(b[off + i]); - } - } - } -} diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/LogManagerTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/LogManagerTest.java index 8728175..acab867 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/LogManagerTest.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/LogManagerTest.java @@ -19,7 +19,7 @@ package org.apache.logging.log4j; import org.apache.logging.log4j.message.ParameterizedMessageFactory; import org.junit.Test; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; /** @@ -31,27 +31,48 @@ public class LogManagerTest { public void testGetLogger() { Logger logger = LogManager.getLogger(); assertNotNull("No Logger returned", logger); - assertTrue("Incorrect Logger name: " + logger.getName(),LogManagerTest.class.getName().equals(logger.getName())); + assertEquals("Incorrect Logger name: " + logger.getName(), LogManagerTest.class.getName(), logger.getName()); logger = LogManager.getLogger(ParameterizedMessageFactory.INSTANCE); assertNotNull("No Logger returned", logger); - assertTrue("Incorrect Logger name: " + logger.getName(),LogManagerTest.class.getName().equals(logger.getName())); + assertEquals("Incorrect Logger name: " + logger.getName(), LogManagerTest.class.getName(), logger.getName()); logger = LogManager.getLogger((Class) null); assertNotNull("No Logger returned", logger); - assertTrue("Incorrect Logger name: " + logger.getName(),LogManagerTest.class.getName().equals(logger.getName())); + assertEquals("Incorrect Logger name: " + logger.getName(), LogManagerTest.class.getName(), logger.getName()); logger = LogManager.getLogger((Class) null, ParameterizedMessageFactory.INSTANCE); assertNotNull("No Logger returned", logger); - assertTrue("Incorrect Logger name: " + logger.getName(),LogManagerTest.class.getName().equals(logger.getName())); + assertEquals("Incorrect Logger name: " + logger.getName(), LogManagerTest.class.getName(), logger.getName()); logger = LogManager.getLogger((String) null); assertNotNull("No Logger returned", logger); - assertTrue("Incorrect Logger name: " + logger.getName(),LogManagerTest.class.getName().equals(logger.getName())); + assertEquals("Incorrect Logger name: " + logger.getName(), LogManagerTest.class.getName(), logger.getName()); logger = LogManager.getLogger((String) null, ParameterizedMessageFactory.INSTANCE); assertNotNull("No Logger returned", logger); - assertTrue("Incorrect Logger name: " + logger.getName(),LogManagerTest.class.getName().equals(logger.getName())); + assertEquals("Incorrect Logger name: " + logger.getName(), LogManagerTest.class.getName(), logger.getName()); logger = LogManager.getLogger((Object) null); assertNotNull("No Logger returned", logger); - assertTrue("Incorrect Logger name: " + logger.getName(),LogManagerTest.class.getName().equals(logger.getName())); + assertEquals("Incorrect Logger name: " + logger.getName(), LogManagerTest.class.getName(), logger.getName()); logger = LogManager.getLogger((Object) null, ParameterizedMessageFactory.INSTANCE); assertNotNull("No Logger returned", logger); - assertTrue("Incorrect Logger name: " + logger.getName(),LogManagerTest.class.getName().equals(logger.getName())); + assertEquals("Incorrect Logger name: " + logger.getName(), LogManagerTest.class.getName(), logger.getName()); + } + + @Test + public void testGetLoggerStream() throws Exception { + LoggerStream stream = LogManager.getLoggerStream(); + assertNotNull("No LoggerStream returned", stream); + assertEquals("Incorrect stream name: " + stream.getName(), stream.getName(), LogManagerTest.class.getName()); + stream = LogManager.getLoggerStream((String) null); + assertNotNull("No LoggerStream returned", stream); + assertEquals("Incorrect stream name: " + stream.getName(), stream.getName(), LogManagerTest.class.getName()); + stream = LogManager.getLoggerStream((Class) null); + assertNotNull("No LoggerStream returned", stream); + assertEquals("Incorrect stream name: " + stream.getName(), stream.getName(), LogManagerTest.class.getName()); + stream = LogManager.getLoggerStream((String) null, ParameterizedMessageFactory.INSTANCE); + assertNotNull("No LoggerStream returned", stream); + assertEquals("Incorrect stream name: " + stream.getName(), stream.getName(), LogManagerTest.class.getName()); + stream = LogManager.getLoggerStream((Class) null, ParameterizedMessageFactory.INSTANCE); + assertNotNull("No LoggerStream returned", stream); + assertEquals("Incorrect stream name: " + stream.getName(), stream.getName(), LogManagerTest.class.getName()); + stream = LogManager.getLoggerStream(LoggerStream.class); + assertEquals("Incorrect stream name: " + stream.getName(), stream.getName(), LoggerStream.class.getName()); } } diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java index 621a98b..f9d8b73 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java @@ -16,9 +16,6 @@ */ package org.apache.logging.log4j; -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; - import java.util.Date; import java.util.List; import java.util.Locale; @@ -26,10 +23,13 @@ import java.util.Locale; import org.apache.logging.log4j.message.ParameterizedMessageFactory; import org.apache.logging.log4j.message.StringFormatterMessageFactory; import org.apache.logging.log4j.message.StructuredDataMessage; -import org.apache.logging.log4j.spi.LoggerStream; +import org.junit.After; import org.junit.Before; import org.junit.Test; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.junit.Assert.*; + /** * */ @@ -43,8 +43,9 @@ public class LoggerTest { // empty } - TestLogger logger = (TestLogger) LogManager.getLogger("LoggerTest"); - List results = logger.getEntries(); + TestLoggerContext context = (TestLoggerContext) LogManager.getContext(); + TestLogger logger; + List results; @Test public void basicFlow() { @@ -273,31 +274,39 @@ public class LoggerTest { @Test public void getStream() { - final LoggerStream stream = logger.getStream(Level.DEBUG); + final LoggerStream stream = context.getLoggerStream("LoggerTest").withLevel(Level.DEBUG); stream.println("Debug message 1"); stream.print("Debug message 2"); stream.println(); stream.println(); // verify blank log message stream.print("Debug message 3\n"); stream.print("\r\n"); // verify windows EOL works - assertEquals(5, results.size()); + stream.withLevel(Level.INFO).println("Info message"); + stream.println("Still an info message"); + assertEquals(7, results.size()); assertThat("Incorrect message", results.get(0), startsWith(" DEBUG Debug message 1")); assertThat("Incorrect message", results.get(1), startsWith(" DEBUG Debug message 2")); assertEquals("Message should be blank-ish", " DEBUG ", results.get(2)); assertThat("Incorrect message", results.get(3), startsWith(" DEBUG Debug message 3")); assertEquals("Message should be blank-ish", " DEBUG ", results.get(4)); + assertThat("Incorrect message", results.get(5), startsWith(" INFO Info message")); + assertThat("Incorrect message", results.get(6), startsWith(" INFO Still an info message")); } @Test public void getStream_Marker() { - final LoggerStream stream = logger.getStream(MarkerManager.getMarker("HI"), Level.INFO); + final LoggerStream stream = context.getLoggerStream("LoggerTest") + .withLevel(Level.INFO) + .withMarker(MarkerManager.getMarker("HI")); stream.println("Hello, world!"); stream.print("How about this?\n"); stream.println("Is this thing on?"); - assertEquals(3, results.size()); + stream.withMarker(MarkerManager.getMarker("BYE")).printf("Have a %s night", "good"); + assertEquals(4, results.size()); assertThat("Incorrect message.", results.get(0), startsWith("HI INFO Hello")); assertThat("Incorrect message.", results.get(1), startsWith("HI INFO How about")); assertThat("Incorrect message.", results.get(2), startsWith("HI INFO Is this")); + assertThat("Incorrect formatted message", results.get(3), startsWith("BYE INFO Have a good night")); } @Test @@ -371,6 +380,12 @@ public class LoggerTest { @Before public void setup() { + logger = context.getLogger("LoggerTest"); + results = logger.getEntries(); + } + + @After + public void tearDown() throws Exception { results.clear(); } diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/TestLoggerContext.java b/log4j-api/src/test/java/org/apache/logging/log4j/TestLoggerContext.java index c153209..709a2df 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/TestLoggerContext.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/TestLoggerContext.java @@ -16,30 +16,31 @@ */ package org.apache.logging.log4j; -import org.apache.logging.log4j.message.MessageFactory; -import org.apache.logging.log4j.spi.LoggerContext; - import java.util.HashMap; import java.util.Map; +import org.apache.logging.log4j.message.MessageFactory; +import org.apache.logging.log4j.spi.AbstractLoggerContext; +import org.apache.logging.log4j.spi.LoggerContext; + /** * */ -public class TestLoggerContext implements LoggerContext { - private final Map map = new HashMap(); +public class TestLoggerContext extends AbstractLoggerContext implements LoggerContext { + private final Map map = new HashMap(); @Override - public Logger getLogger(final String name) { + public TestLogger getLogger(final String name) { if (map.containsKey(name)) { return map.get(name); } - final Logger logger = new TestLogger(name); + final TestLogger logger = new TestLogger(name); map.put(name, logger); return logger; } @Override - public Logger getLogger(final String name, final MessageFactory messageFactory) { + public TestLogger getLogger(final String name, final MessageFactory messageFactory) { return new TestLogger(name, messageFactory); } diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/spi/LoggerStreamTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/spi/LoggerStreamTest.java index b3a4933..8d2fd90 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/spi/LoggerStreamTest.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/spi/LoggerStreamTest.java @@ -16,19 +16,22 @@ */ package org.apache.logging.log4j.spi; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.LoggerStream; import org.apache.logging.log4j.TestLogger; +import org.apache.logging.log4j.TestLoggerContext; +import org.apache.logging.log4j.simple.SimpleLoggerStream; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - import static org.hamcrest.core.StringStartsWith.startsWith; import static org.junit.Assert.*; @@ -59,16 +62,18 @@ public class LoggerStreamTest { @Before public void setUp() throws Exception { - TestLogger logger = (TestLogger) LogManager.getLogger(); + TestLoggerContext context = (TestLoggerContext) LogManager.getContext(); + TestLogger logger = context.getLogger(LoggerStreamTest.class.getName()); results = logger.getEntries(); assertEmpty(); - stream = new LoggerStream(logger, level); + stream = new SimpleLoggerStream(logger).withLevel(level); assertEmpty(); } @After public void tearDown() throws Exception { results.clear(); + stream.close(); } private void assertEmpty() { @@ -171,14 +176,12 @@ public class LoggerStreamTest { @Test public void testPrintf() throws Exception { stream.printf("<<<%s>>>", logMessage); - assertEmpty(); - stream.println(); assertMessageStartsWith("<<<" + logMessage); } @Test public void testFormat() throws Exception { - stream.format("[%s]", logMessage).println(); + stream.format("[%s]", logMessage); assertMessageStartsWith("[" + logMessage); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java index d0debec..83e2582 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java @@ -38,6 +38,7 @@ import org.apache.logging.log4j.core.helpers.NetUtils; import org.apache.logging.log4j.core.jmx.Server; import org.apache.logging.log4j.message.MessageFactory; import org.apache.logging.log4j.spi.AbstractLogger; +import org.apache.logging.log4j.spi.AbstractLoggerContext; import org.apache.logging.log4j.status.StatusLogger; /** @@ -47,7 +48,7 @@ import org.apache.logging.log4j.status.StatusLogger; * appenders, filters, etc and will be atomically updated whenever a reconfigure * occurs. */ -public class LoggerContext implements org.apache.logging.log4j.spi.LoggerContext, ConfigurationListener, LifeCycle { +public class LoggerContext extends AbstractLoggerContext implements org.apache.logging.log4j.spi.LoggerContext, ConfigurationListener, LifeCycle { public static final String PROPERTY_CONFIG = "config"; private static final StatusLogger LOGGER = StatusLogger.getLogger(); diff --git a/log4j-taglib/src/main/java/org/apache/logging/log4j/taglib/Log4jTaglibLoggerContext.java b/log4j-taglib/src/main/java/org/apache/logging/log4j/taglib/Log4jTaglibLoggerContext.java index 1579a32..54cffd9 100644 --- a/log4j-taglib/src/main/java/org/apache/logging/log4j/taglib/Log4jTaglibLoggerContext.java +++ b/log4j-taglib/src/main/java/org/apache/logging/log4j/taglib/Log4jTaglibLoggerContext.java @@ -24,6 +24,7 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LoggingException; import org.apache.logging.log4j.message.MessageFactory; import org.apache.logging.log4j.spi.AbstractLogger; +import org.apache.logging.log4j.spi.AbstractLoggerContext; import org.apache.logging.log4j.spi.LoggerContext; /** @@ -32,7 +33,7 @@ import org.apache.logging.log4j.spi.LoggerContext; * * @since 2.0 */ -final class Log4jTaglibLoggerContext implements LoggerContext { +final class Log4jTaglibLoggerContext extends AbstractLoggerContext implements LoggerContext { // These were change to WeakHashMaps to avoid ClassLoader (memory) leak, something that's particularly // important in Servlet containers. private static final WeakHashMap CONTEXTS = diff --git a/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContext.java b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContext.java index 6d76081..97db6d6 100644 --- a/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContext.java +++ b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContext.java @@ -21,13 +21,14 @@ import java.util.concurrent.ConcurrentMap; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.MessageFactory; +import org.apache.logging.log4j.spi.AbstractLoggerContext; import org.apache.logging.log4j.spi.LoggerContext; import org.slf4j.LoggerFactory; /** * */ -public class SLF4JLoggerContext implements LoggerContext { +public class SLF4JLoggerContext extends AbstractLoggerContext implements LoggerContext { private final ConcurrentMap loggers = new ConcurrentHashMap(); @Override -- 1.9.0