You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2012/08/10 09:02:23 UTC
svn commit: r1371582 - in /logging/log4j/log4j2/trunk:
api/src/main/java/org/apache/logging/log4j/message/
api/src/test/java/org/apache/logging/log4j/
api/src/test/java/org/apache/logging/log4j/message/ src/changes/
Author: rgoers
Date: Fri Aug 10 07:02:22 2012
New Revision: 1371582
URL: http://svn.apache.org/viewvc?rev=1371582&view=rev
Log:
Add support for formatting using String.format()
Added:
logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java
- copied, changed from r1371500, logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessage.java
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/Timer.java
- copied, changed from r1371500, logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/Timer.java
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java
- copied, changed from r1371500, logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java
Modified:
logging/log4j/log4j2/trunk/src/changes/changes.xml
Copied: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java (from r1371500, logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessage.java)
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java?p2=logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java&p1=logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessage.java&r1=1371500&r2=1371582&rev=1371582&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessage.java (original)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java Fri Aug 10 07:02:22 2012
@@ -16,156 +16,43 @@
*/
package org.apache.logging.log4j.message;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.io.Serializable;
-import java.text.SimpleDateFormat;
import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.util.IllegalFormatException;
/**
- * Handles messages that consist of a format string containing '{}' to represent each replaceable token, and
- * the parameters.
- * <p/>
- * This class was originally written for Lillith (http://mac.freshmeat.net/projects/lilith-viewer) by
- * Joern Huxhorn where it is licensed under the LGPL. It has been relicensed here with his permission
- * providing that this attribution remain.
+ * Handles messages that consist of a format string conforming to java.util.Formatter
*/
-public class ParameterizedMessage implements Message, Serializable {
+public class StringFormattedMessage implements Message, Serializable {
- /**
- * Prefix for recursion.
- */
- public static final String RECURSION_PREFIX = "[...";
- /**
- * Suffix for recursion.
- */
- public static final String RECURSION_SUFFIX = "...]";
-
- /**
- * Prefix for errors.
- */
- public static final String ERROR_PREFIX = "[!!!";
- /**
- * Separator for errors.
- */
- public static final String ERROR_SEPARATOR = "=>";
- /**
- * Separator for error messages.
- */
- public static final String ERROR_MSG_SEPARATOR = ":";
- /**
- * Suffix for errors.
- */
- public static final String ERROR_SUFFIX = "!!!]";
+ private static final Logger LOGGER = StatusLogger.getLogger();
private static final long serialVersionUID = -665975803997290697L;
private static final int HASHVAL = 31;
- private static final char DELIM_START = '{';
- private static final char DELIM_STOP = '}';
- private static final char ESCAPE_CHAR = '\\';
-
private String messagePattern;
- private String[] stringArgs;
private transient Object[] argArray;
+ private String[] stringArgs;
private transient String formattedMessage;
- private transient Throwable throwable;
/**
- * Create the ParameterizedMessage.
+ * Create the StringFormattedMessage.
*/
- public ParameterizedMessage() {
+ public StringFormattedMessage() {
this(null, null, null);
}
- /**
- * Create the parameterizedMessage.
- * @param messagePattern The message "format" string. This will be a String containing "{}" placeholders
- * where parameters should be substituted.
- * @param stringArgs The arguments for substitution.
- * @param throwable A Throwable.
- */
- public ParameterizedMessage(String messagePattern, String[] stringArgs, Throwable throwable) {
- this.messagePattern = messagePattern;
- this.stringArgs = stringArgs;
- this.throwable = throwable;
- }
-
- public ParameterizedMessage(String messagePattern, Object[] arguments, Throwable throwable) {
- this.messagePattern = messagePattern;
- this.throwable = throwable;
- if (arguments != null) {
- parseArguments(arguments);
- }
- }
- /**
- * <p>This method returns a ParameterizedMessage which contains the arguments converted to String
- * as well as an optional Throwable.</p>
- * <p/>
- * <p>If the last argument is a Throwable and is NOT used up by a placeholder in the message pattern it is returned
- * in ParameterizedMessage.getThrowable() and won't be contained in the created String[].<br/>
- * If it is used up ParameterizedMessage.getThrowable() will return null even if the last argument was a
- * Throwable!</p>
- *
- * @param messagePattern the message pattern that to be checked for placeholders.
- * @param arguments the argument array to be converted.
- */
- public ParameterizedMessage(String messagePattern, Object[] arguments) {
+ public StringFormattedMessage(String messagePattern, Object... arguments) {
this.messagePattern = messagePattern;
- if (arguments == null) {
- return;
- }
- parseArguments(arguments);
- }
-
- /**
- * Constructor with a pattern and a single parameter.
- * @param messagePattern The message pattern.
- * @param arg The parameter.
- */
- public ParameterizedMessage(String messagePattern, Object arg) {
- this(messagePattern, new Object[]{arg});
- }
-
- /**
- * Constructor with a pattern and two parameters.
- * @param messagePattern The message pattern.
- * @param arg1 The first parameter.
- * @param arg2 The second parameter.
- */
- public ParameterizedMessage(String messagePattern, Object arg1, Object arg2) {
- this(messagePattern, new Object[]{arg1, arg2});
- }
-
- private void parseArguments(Object[] arguments) {
- int argsCount = countArgumentPlaceholders(messagePattern);
- int resultArgCount = arguments.length;
- if (argsCount < arguments.length) {
- if (throwable == null && arguments[arguments.length - 1] instanceof Throwable) {
- throwable = (Throwable) arguments[arguments.length - 1];
- resultArgCount--;
- }
- }
- argArray = new Object[resultArgCount];
- for (int i = 0; i < resultArgCount; ++i) {
- argArray[i] = arguments[i];
- }
-
- if (argsCount == 1 && throwable == null && arguments.length > 1) {
- // special case
- stringArgs = new String[1];
- stringArgs[0] = deepToString(arguments);
- } else {
- stringArgs = new String[resultArgCount];
- for (int i = 0; i < stringArgs.length; i++) {
- stringArgs[i] = deepToString(arguments[i]);
- }
- }
+ this.argArray = arguments;
}
/**
@@ -174,7 +61,7 @@ public class ParameterizedMessage implem
*/
public String getFormattedMessage() {
if (formattedMessage == null) {
- formattedMessage = formatMessage(messagePattern, stringArgs);
+ formattedMessage = formatMessage(messagePattern, argArray);
}
return formattedMessage;
}
@@ -211,43 +98,18 @@ public class ParameterizedMessage implem
* Sets the parameters for the message.
* @param parameters The parameters.
*/
- public void setParameters(String[] parameters) {
- this.stringArgs = parameters;
- this.formattedMessage = null;
- }
-
- /**
- * Sets the parameters for the message.
- * @param parameters The parameters.
- */
public void setParameters(Object[] parameters) {
- parseArguments(parameters);
+ this.argArray = parameters;
this.formattedMessage = null;
}
- /**
- * Set the Throwable for the message.
- * @param throwable The Throwable.
- */
- public void setThrowable(Throwable throwable) {
- this.throwable = throwable;
- }
-
- /**
- * Returns the Throwable that was given as the last argument, if any.
- * It will not survive serialization. The Throwable exists as part of the message
- * primarily so that it can be extracted from the end of the list of parameters
- * and then be added to the LogEvent. As such, the Throwable in the event should
- * not be used once the LogEvent has been constructed.
- *
- * @return the Throwable, if any.
- */
- public Throwable getThrowable() {
- return throwable;
- }
-
- protected String formatMessage(String msgPattern, String[] sArgs) {
- return format(msgPattern, sArgs);
+ protected String formatMessage(String msgPattern, Object... args) {
+ try {
+ return String.format(msgPattern, args);
+ } catch (IllegalFormatException ife) {
+ LOGGER.error("Unable to format msg: " + msgPattern, ife);
+ return msgPattern;
+ }
}
public boolean equals(Object o) {
@@ -258,7 +120,7 @@ public class ParameterizedMessage implem
return false;
}
- ParameterizedMessage that = (ParameterizedMessage) o;
+ StringFormattedMessage that = (StringFormattedMessage) o;
if (messagePattern != null ? !messagePattern.equals(that.messagePattern) : that.messagePattern != null) {
return false;
@@ -266,7 +128,6 @@ public class ParameterizedMessage implem
if (!Arrays.equals(stringArgs, that.stringArgs)) {
return false;
}
- //if (throwable != null ? !throwable.equals(that.throwable) : that.throwable != null) return false;
return true;
}
@@ -277,306 +138,34 @@ public class ParameterizedMessage implem
return result;
}
- /**
- * Replace placeholders in the given messagePattern with arguments.
- *
- * @param messagePattern the message pattern containing placeholders.
- * @param arguments the arguments to be used to replace placeholders.
- * @return the formatted message.
- */
- public static String format(String messagePattern, Object[] arguments) {
- if (messagePattern == null || arguments == null || arguments.length == 0) {
- return messagePattern;
- }
-
- StringBuilder result = new StringBuilder();
- int escapeCounter = 0;
- int currentArgument = 0;
- for (int i = 0; i < messagePattern.length(); i++) {
- char curChar = messagePattern.charAt(i);
- if (curChar == ESCAPE_CHAR) {
- escapeCounter++;
- } else {
- if (curChar == DELIM_START) {
- if (i < messagePattern.length() - 1) {
- if (messagePattern.charAt(i + 1) == DELIM_STOP) {
- // write escaped escape chars
- int escapedEscapes = escapeCounter / 2;
- for (int j = 0; j < escapedEscapes; j++) {
- result.append(ESCAPE_CHAR);
- }
-
- if (escapeCounter % 2 == 1) {
- // i.e. escaped
- // write escaped escape chars
- result.append(DELIM_START);
- result.append(DELIM_STOP);
- } else {
- // unescaped
- if (currentArgument < arguments.length) {
- result.append(arguments[currentArgument]);
- } else {
- result.append(DELIM_START).append(DELIM_STOP);
- }
- currentArgument++;
- }
- i++;
- escapeCounter = 0;
- continue;
- }
- }
- }
- // any other char beside ESCAPE or DELIM_START/STOP-combo
- // write unescaped escape chars
- if (escapeCounter > 0) {
- for (int j = 0; j < escapeCounter; j++) {
- result.append(ESCAPE_CHAR);
- }
- escapeCounter = 0;
- }
- result.append(curChar);
- }
- }
- return result.toString();
- }
-
- /**
- * Counts the number of unescaped placeholders in the given messagePattern.
- *
- * @param messagePattern the message pattern to be analyzed.
- * @return the number of unescaped placeholders.
- */
- public static int countArgumentPlaceholders(String messagePattern) {
- if (messagePattern == null) {
- return 0;
- }
-
- int delim = messagePattern.indexOf(DELIM_START);
-
- if (delim == -1) {
- // special case, no placeholders at all.
- return 0;
- }
- int result = 0;
- boolean isEscaped = false;
- for (int i = 0; i < messagePattern.length(); i++) {
- char curChar = messagePattern.charAt(i);
- if (curChar == ESCAPE_CHAR) {
- isEscaped = !isEscaped;
- } else if (curChar == DELIM_START) {
- if (!isEscaped) {
- if (i < messagePattern.length() - 1) {
- if (messagePattern.charAt(i + 1) == DELIM_STOP) {
- result++;
- i++;
- }
- }
- }
- isEscaped = false;
- } else {
- isEscaped = false;
- }
- }
- return result;
- }
- /**
- * This method performs a deep toString of the given Object.
- * Primitive arrays are converted using their respective Arrays.toString methods while
- * special handling is implemented for "container types", i.e. Object[], Map and Collection because those could
- * contain themselves.
- * <p/>
- * It should be noted that neither AbstractMap.toString() nor AbstractCollection.toString() implement such a
- * behavior. They only check if the container is directly contained in itself, but not if a contained container
- * contains the original one. Because of that, Arrays.toString(Object[]) isn't safe either.
- * Confusing? Just read the last paragraph again and check the respective toString() implementation.
- * <p/>
- * This means, in effect, that logging would produce a usable output even if an ordinary System.out.println(o)
- * would produce a relatively hard-to-debug StackOverflowError.
- * @param o The object.
- * @return The String representation.
- */
- public static String deepToString(Object o) {
- if (o == null) {
- return null;
- }
- if (o instanceof String) {
- return (String) o;
- }
- StringBuilder str = new StringBuilder();
- Set<String> dejaVu = new HashSet<String>(); // that's actually a neat name ;)
- recursiveDeepToString(o, str, dejaVu);
- return str.toString();
+ public String toString() {
+ return "StringFormatMessage[messagePattern=" + messagePattern + ", args=" +
+ Arrays.toString(argArray) + "]";
}
- /**
- * This method performs a deep toString of the given Object.
- * Primitive arrays are converted using their respective Arrays.toString methods while
- * special handling is implemented for "container types", i.e. Object[], Map and Collection because those could
- * contain themselves.
- * <p/>
- * dejaVu is used in case of those container types to prevent an endless recursion.
- * <p/>
- * It should be noted that neither AbstractMap.toString() nor AbstractCollection.toString() implement such a
- * behavior.
- * They only check if the container is directly contained in itself, but not if a contained container contains the
- * original one. Because of that, Arrays.toString(Object[]) isn't safe either.
- * Confusing? Just read the last paragraph again and check the respective toString() implementation.
- * <p/>
- * This means, in effect, that logging would produce a usable output even if an ordinary System.out.println(o)
- * would produce a relatively hard-to-debug StackOverflowError.
- *
- * @param o the Object to convert into a String
- * @param str the StringBuilder that o will be appended to
- * @param dejaVu a list of container identities that were already used.
- */
- private static void recursiveDeepToString(Object o, StringBuilder str, Set<String> dejaVu) {
- if (o == null) {
- str.append("null");
- return;
- }
- if (o instanceof String) {
- str.append(o);
- return;
- }
-
- Class oClass = o.getClass();
- if (oClass.isArray()) {
- if (oClass == byte[].class) {
- str.append(Arrays.toString((byte[]) o));
- } else if (oClass == short[].class) {
- str.append(Arrays.toString((short[]) o));
- } else if (oClass == int[].class) {
- str.append(Arrays.toString((int[]) o));
- } else if (oClass == long[].class) {
- str.append(Arrays.toString((long[]) o));
- } else if (oClass == float[].class) {
- str.append(Arrays.toString((float[]) o));
- } else if (oClass == double[].class) {
- str.append(Arrays.toString((double[]) o));
- } else if (oClass == boolean[].class) {
- str.append(Arrays.toString((boolean[]) o));
- } else if (oClass == char[].class) {
- str.append(Arrays.toString((char[]) o));
- } else {
- // special handling of container Object[]
- String id = identityToString(o);
- if (dejaVu.contains(id)) {
- str.append(RECURSION_PREFIX).append(id).append(RECURSION_SUFFIX);
- } else {
- dejaVu.add(id);
- Object[] oArray = (Object[]) o;
- str.append("[");
- boolean first = true;
- for (Object current : oArray) {
- if (first) {
- first = false;
- } else {
- str.append(", ");
- }
- recursiveDeepToString(current, str, new HashSet<String>(dejaVu));
- }
- str.append("]");
- }
- //str.append(Arrays.deepToString((Object[]) o));
- }
- } else if (o instanceof Map) {
- // special handling of container Map
- String id = identityToString(o);
- if (dejaVu.contains(id)) {
- str.append(RECURSION_PREFIX).append(id).append(RECURSION_SUFFIX);
- } else {
- dejaVu.add(id);
- Map oMap = (Map) o;
- str.append("{");
- boolean isFirst = true;
- for (Object o1 : oMap.entrySet()) {
- Map.Entry current = (Map.Entry) o1;
- if (isFirst) {
- isFirst = false;
- } else {
- str.append(", ");
- }
- Object key = current.getKey();
- Object value = current.getValue();
- recursiveDeepToString(key, str, new HashSet<String>(dejaVu));
- str.append("=");
- recursiveDeepToString(value, str, new HashSet<String>(dejaVu));
- }
- str.append("}");
- }
- } else if (o instanceof Collection) {
- // special handling of container Collection
- String id = identityToString(o);
- if (dejaVu.contains(id)) {
- str.append(RECURSION_PREFIX).append(id).append(RECURSION_SUFFIX);
- } else {
- dejaVu.add(id);
- Collection oCol = (Collection) o;
- str.append("[");
- boolean isFirst = true;
- for (Object anOCol : oCol) {
- if (isFirst) {
- isFirst = false;
- } else {
- str.append(", ");
- }
- recursiveDeepToString(anOCol, str, new HashSet<String>(dejaVu));
- }
- str.append("]");
- }
- } else if (o instanceof Date) {
- Date date = (Date) o;
- SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
- // I'll leave it like this for the moment... this could probably be optimized using ThreadLocal...
- str.append(format.format(date));
- } else {
- // it's just some other Object, we can only use toString().
- try {
- str.append(o.toString());
- } catch (Throwable t) {
- str.append(ERROR_PREFIX);
- str.append(identityToString(o));
- str.append(ERROR_SEPARATOR);
- String msg = t.getMessage();
- String className = t.getClass().getName();
- str.append(className);
- if (!className.equals(msg)) {
- str.append(ERROR_MSG_SEPARATOR);
- str.append(msg);
- }
- str.append(ERROR_SUFFIX);
- }
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ getFormattedMessage();
+ out.writeUTF(formattedMessage);
+ out.writeUTF(messagePattern);
+ out.writeInt(argArray.length);
+ stringArgs = new String[argArray.length];
+ int i = 0;
+ for (Object obj: argArray) {
+ stringArgs[i] = obj.toString();
+ ++i;
}
}
- /**
- * This method returns the same as if Object.toString() would not have been
- * overridden in obj.
- * <p/>
- * Note that this isn't 100% secure as collisions can always happen with hash codes.
- * <p/>
- * Copied from Object.hashCode():
- * As much as is reasonably practical, the hashCode method defined by
- * class <tt>Object</tt> does return distinct integers for distinct
- * objects. (This is typically implemented by converting the internal
- * address of the object into an integer, but this implementation
- * technique is not required by the
- * Java<font size="-2"><sup>TM</sup></font>
- * programming language.)
- *
- * @param obj the Object that is to be converted into an identity string.
- * @return the identity string as also defined in Object.toString()
- */
- public static String identityToString(Object obj) {
- if (obj == null) {
- return null;
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ formattedMessage = in.readUTF();
+ messagePattern = in.readUTF();
+ int length = in.readInt();
+ stringArgs = new String[length];
+ for (int i=0; i < length; ++i) {
+ stringArgs[i] = in.readUTF();
}
- return obj.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(obj));
- }
-
- public String toString() {
- return "ParameterizedMessage[messagePattern=" + messagePattern + ", stringArgs=" +
- Arrays.toString(stringArgs) + ", throwable=" + throwable + "]";
}
}
Copied: logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/Timer.java (from r1371500, logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/Timer.java)
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/Timer.java?p2=logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/Timer.java&p1=logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/Timer.java&r1=1371500&r2=1371582&rev=1371582&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/Timer.java (original)
+++ logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/Timer.java Fri Aug 10 07:02:22 2012
@@ -14,7 +14,7 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
-package org.apache.logging.log4j.core;
+package org.apache.logging.log4j;
import java.io.Serializable;
import java.text.DecimalFormat;
Copied: logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java (from r1371500, logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java)
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java?p2=logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java&p1=logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java&r1=1371500&r2=1371582&rev=1371582&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java (original)
+++ logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java Fri Aug 10 07:02:22 2012
@@ -16,27 +16,82 @@
*/
package org.apache.logging.log4j.message;
+import org.apache.logging.log4j.Timer;
+import org.junit.AfterClass;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
/**
*
*/
-public class ParameterizedMessageTest {
+public class StringFormattedMessageTest {
+
+ private static final int LOOP_CNT = 500;
+ String[] array = new String[LOOP_CNT];
+ private static long stringTime = 0;
+ private static long paramTime = 0;
+
+ @AfterClass
+ public static void after() {
+ if (stringTime > paramTime) {
+ System.out.println(String.format("Parameterized is %1$.2f times faster than StringFormat.",
+ ((float) stringTime / paramTime)));
+ } else if (stringTime > paramTime) {
+ System.out.println(String.format("Parameterized is %1$.2f times slower than StringFormat.",
+ ((float) paramTime / stringTime)));
+ } else {
+ System.out.println("The speed of Parameterized and StringFormat are the same");
+ }
+ }
@Test
public void testNoArgs() {
- String testMsg = "Test message {}";
- ParameterizedMessage msg = new ParameterizedMessage(testMsg, null);
+ String testMsg = "Test message %1s";
+ StringFormattedMessage msg = new StringFormattedMessage(testMsg, null);
String result = msg.getFormattedMessage();
- assertEquals(testMsg, result);
+ String expected = "Test message null";
+ assertEquals(expected, result);
Object[] array = null;
- msg = new ParameterizedMessage(testMsg, array, null);
+ msg = new StringFormattedMessage(testMsg, array, null);
result = msg.getFormattedMessage();
- assertEquals(testMsg, result);
+ assertEquals(expected, result);
+ }
+
+ @Test
+ public void testOneArg() {
+ String testMsg = "Test message %1s";
+ StringFormattedMessage msg = new StringFormattedMessage(testMsg, "Apache");
+ String result = msg.getFormattedMessage();
+ String expected = "Test message Apache";
+ assertEquals(expected, result);
+ }
+
+ @Test
+ public void testStringPerf() {
+ String testMsg = "Test message %1s %2s";
+ Timer timer = new Timer("StringFormat", LOOP_CNT);
+ timer.start();
+ for (int i = 0; i < LOOP_CNT; ++i) {
+ StringFormattedMessage msg = new StringFormattedMessage(testMsg, "Apache", "Log4j");
+ array[i] = msg.getFormattedMessage();
+ }
+ timer.stop();
+ stringTime = timer.getElapsedNanoTime();
+ System.out.println(timer.toString());
+ }
+
+ @Test
+ public void testParameterizedPerf() {
+ String testMsg = "Test message {} {}";
+ Timer timer = new Timer("Parameterized", LOOP_CNT);
+ timer.start();
+ for (int i = 0; i < LOOP_CNT; ++i) {
+ ParameterizedMessage msg = new ParameterizedMessage(testMsg, "Apache", "Log4j");
+ array[i] = msg.getFormattedMessage();
+ }
+ timer.stop();
+ paramTime = timer.getElapsedNanoTime();
+ System.out.println(timer.toString());
}
}
Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1371582&r1=1371581&r2=1371582&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Fri Aug 10 07:02:22 2012
@@ -23,6 +23,9 @@
<body>
<release version="2.0-alpha2" date="TBD" description="Bug fixes and minor enhancements">
+ <action dev="rgoers" type="add">
+ Add support for formatting using String.format().
+ </action>
<action issue="LOG4J2-67" dev="rgoers" type="add">
Allow components besides core to create a PluginMap for faster plugin loading and not
having to specify the plugin package in the configuration.