You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by Remko Popma <re...@gmail.com> on 2014/08/10 15:12:10 UTC

Re: Fwd: svn commit: r1617051 - in /logging/log4j/log4j2/trunk: log4j-api/src/main/java/org/apache/logging/log4j/message/ log4j-api/src/test/java/org/apache/logging/log4j/message/ src/changes/ src/site/xdoc/manual/

I'll take a look at fixing it the way Ralph suggested later this week.

On Sunday, August 10, 2014, Remko Popma <re...@gmail.com> wrote:

> Well darn, you're right!
>
> I completely missed that.
>
> I wish you'd told me a few days ago though. That kind of feedback was
> exactly was I was hoping for when I attached the patch to the Jira ticket.
>
> Sent from my iPhone
>
> > On 2014/08/10, at 21:49, Ralph Goers <rgoers@apache.org <javascript:;>>
> wrote:
> >
> > One of the points of getFormattedMessage was to defer the expense of
> formatting until it is actually required. This change eliminates that
> savings.  I would have preferred having the async component call
> getFormattedMessage when it needed to, thus not impacting synchronous
> configurations.
> >
> > Sent from my iPad
> >
> >> On Aug 10, 2014, at 5:12 AM, Gary Gregory <garydgregory@gmail.com
> <javascript:;>> wrote:
> >>
> >> Instead of calling getFormattedMessage(), how about refactoring it and
> call an initSomething method. This will make the call sites less smelly of
> programming by side effect.
> >>
> >> Gary
> >>
> >>
> >> -------- Original message --------
> >> From: rpopma@apache.org <javascript:;>
> >> Date:08/10/2014 02:40 (GMT-05:00)
> >> To: commits@logging.apache.org <javascript:;>
> >> Subject: svn commit: r1617051 - in /logging/log4j/log4j2/trunk:
> log4j-api/src/main/java/org/apache/logging/log4j/message/
> log4j-api/src/test/java/org/apache/logging/log4j/message/ src/changes/
> src/site/xdoc/manual/
> >>
> >> Author: rpopma
> >> Date: Sun Aug 10 06:40:14 2014
> >> New Revision: 1617051
> >>
> >> URL: http://svn.apache.org/r1617051
> >> Log:
> >> LOG4J2-763: Improved FormattedMessage, StringFormattedMessage,
> LocalizedMessage, MessageFormatMessage and ObjectMessage for asynchronous
> logging to ensure the formatted message does not change even if parameters
> are modified by the application. Improved docs for MapMessage and
> StructuredDataMessage. Improved site docs.
> >>
> >> Added:
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/Mutable.java
>   (with props)
> >> Modified:
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessage.java
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessage.java
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/MapMessage.java
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessage.java
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/FormattedMessageTest.java
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/LocalizedMessageTest.java
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/MapMessageTest.java
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/MessageFormatMessageTest.java
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ObjectMessageTest.java
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java
> >>
>  logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ThreadDumpMessageTest.java
> >>    logging/log4j/log4j2/trunk/src/changes/changes.xml
> >>    logging/log4j/log4j2/trunk/src/site/xdoc/manual/async.xml
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessage.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessage.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessage.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessage.java
> Sun Aug 10 06:40:14 2014
> >> @@ -46,12 +46,11 @@ public class FormattedMessage implements
> >>         this.messagePattern = messagePattern;
> >>         this.argArray = arguments;
> >>         this.throwable = throwable;
> >> +        getFormattedMessage(); // LOG4J2-763 take snapshot of
> parameters at message construction time
> >>     }
> >>
> >>     public FormattedMessage(final String messagePattern, final Object[]
> arguments) {
> >> -        this.messagePattern = messagePattern;
> >> -        this.argArray = arguments;
> >> -        this.throwable = null;
> >> +        this(messagePattern, arguments, null);
> >>     }
> >>
> >>     /**
> >> @@ -60,9 +59,7 @@ public class FormattedMessage implements
> >>      * @param arg The parameter.
> >>      */
> >>     public FormattedMessage(final String messagePattern, final Object
> arg) {
> >> -        this.messagePattern = messagePattern;
> >> -        this.argArray = new Object[] {arg};
> >> -        this.throwable = null;
> >> +        this(messagePattern, new Object[] {arg}, null);
> >>     }
> >>
> >>     /**
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessage.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessage.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessage.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessage.java
> Sun Aug 10 06:40:14 2014
> >> @@ -78,6 +78,7 @@ public class LocalizedMessage implements
> >>         this.baseName = baseName;
> >>         this.resourceBundle = null;
> >>         this.locale = locale;
> >> +        getFormattedMessage(); // LOG4J2-763 take snapshot of
> parameters at message construction time
> >>     }
> >>
> >>     public LocalizedMessage(final ResourceBundle bundle, final Locale
> locale, final String key,
> >> @@ -88,6 +89,7 @@ public class LocalizedMessage implements
> >>         this.baseName = null;
> >>         this.resourceBundle = bundle;
> >>         this.locale = locale;
> >> +        getFormattedMessage(); // LOG4J2-763 take snapshot of
> parameters at message construction time
> >>     }
> >>
> >>     public LocalizedMessage(final Locale locale, final String key,
> final Object[] arguments) {
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/MapMessage.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/MapMessage.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/MapMessage.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/MapMessage.java
> Sun Aug 10 06:40:14 2014
> >> @@ -26,6 +26,11 @@ import org.apache.logging.log4j.util.Str
> >>
> >> /**
> >>  * Represents a Message that consists of a Map.
> >> + * <p>
> >> + * Thread-safety note: the contents of this message can be modified
> after construction.
> >> + * When using asynchronous loggers and appenders it is not recommended
> to modify this message after the message is
> >> + * logged, because it is undefined whether the logged message string
> will contain the old values or the modified
> >> + * values.
> >>  */
> >> public class MapMessage implements MultiformatMessage {
> >>     /**
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessage.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessage.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessage.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessage.java
> Sun Aug 10 06:40:14 2014
> >> @@ -49,6 +49,7 @@ public class MessageFormatMessage implem
> >>         if (arguments != null && arguments.length > 0 &&
> arguments[arguments.length - 1] instanceof Throwable) {
> >>             this.throwable = (Throwable) arguments[arguments.length -
> 1];
> >>         }
> >> +        getFormattedMessage(); // LOG4J2-763 take snapshot of
> parameters at message construction time
> >>     }
> >>
> >>     /**
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java
> Sun Aug 10 06:40:14 2014
> >> @@ -29,6 +29,7 @@ public class ObjectMessage implements Me
> >>     private static final long serialVersionUID = -5903272448334166185L;
> >>
> >>     private transient Object obj;
> >> +    private final String objectString;
> >>
> >>     /**
> >>      * Create the ObjectMessage.
> >> @@ -39,6 +40,9 @@ public class ObjectMessage implements Me
> >>             obj = "null";
> >>         }
> >>         this.obj = obj;
> >> +
> >> +        // LOG4J2-763: take snapshot of parameters at message
> construction time
> >> +        objectString = String.valueOf(obj);
> >>     }
> >>
> >>     /**
> >> @@ -47,7 +51,7 @@ public class ObjectMessage implements Me
> >>      */
> >>     @Override
> >>     public String getFormattedMessage() {
> >> -        return obj.toString();
> >> +        return objectString;
> >>     }
> >>
> >>     /**
> >> @@ -56,7 +60,7 @@ public class ObjectMessage implements Me
> >>      */
> >>     @Override
> >>     public String getFormat() {
> >> -        return obj.toString();
> >> +        return objectString;
> >>     }
> >>
> >>     /**
> >> @@ -89,7 +93,7 @@ public class ObjectMessage implements Me
> >>
> >>     @Override
> >>     public String toString() {
> >> -        return "ObjectMessage[obj=" + obj.toString() + ']';
> >> +        return "ObjectMessage[obj=" + objectString + ']';
> >>     }
> >>
> >>     private void writeObject(final ObjectOutputStream out) throws
> IOException {
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java
> Sun Aug 10 06:40:14 2014
> >> @@ -48,6 +48,7 @@ public class StringFormattedMessage impl
> >>         if (arguments != null && arguments.length > 0 &&
> arguments[arguments.length - 1] instanceof Throwable) {
> >>             this.throwable = (Throwable) arguments[arguments.length -
> 1];
> >>         }
> >> +        getFormattedMessage(); // LOG4J2-763 take snapshot of
> parameters at message construction time
> >>     }
> >>
> >>     /**
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java
> Sun Aug 10 06:40:14 2014
> >> @@ -22,6 +22,11 @@ import org.apache.logging.log4j.util.Eng
> >>
> >> /**
> >>  * Represents a Message that conforms to an RFC 5424 StructuredData
> element along with the syslog message.
> >> + * <p>
> >> + * Thread-safety note: the contents of this message can be modified
> after construction.
> >> + * When using asynchronous loggers and appenders it is not recommended
> to modify this message after the message is
> >> + * logged, because it is undefined whether the logged message string
> will contain the old values or the modified
> >> + * values.
> >>  *
> >>  * @see <a href="https://tools.ietf.org/html/rfc5424">RFC 5424</a>
> >>  */
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/FormattedMessageTest.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/FormattedMessageTest.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/FormattedMessageTest.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/FormattedMessageTest.java
> Sun Aug 10 06:40:14 2014
> >> @@ -83,4 +83,16 @@ public class FormattedMessageTest {
> >>         result = msg.getFormattedMessage();
> >>         assertEquals(testMsg, result);
> >>     }
> >> +
> >> +    @Test
> >> +    public void testSafeWithMutableParams() { // LOG4J2-763
> >> +        final String testMsg = "Test message %s";
> >> +        final Mutable param = new Mutable().set("abc");
> >> +        FormattedMessage msg = new FormattedMessage(testMsg, param);
> >> +
> >> +        // modify parameter before calling msg.getFormattedMessage
> >> +        param.set("XYZ");
> >> +        String actual = msg.getFormattedMessage();
> >> +        assertEquals("Should use initial param value", "Test message
> abc", actual);
> >> +    }
> >> }
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/LocalizedMessageTest.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/LocalizedMessageTest.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/LocalizedMessageTest.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/LocalizedMessageTest.java
> Sun Aug 10 06:40:14 2014
> >> @@ -64,4 +64,16 @@ public class LocalizedMessageTest {
> >>         assertEquals("This is test number 1 with string argument
> Test.", msg.getFormattedMessage());
> >>     }
> >>
> >> +    @Test
> >> +    public void testSafeWithMutableParams() { // LOG4J2-763
> >> +        final String testMsg = "Test message %s";
> >> +        final Mutable param = new Mutable().set("abc");
> >> +        LocalizedMessage msg = new LocalizedMessage(testMsg, param);
> >> +
> >> +        // modify parameter before calling msg.getFormattedMessage
> >> +        param.set("XYZ");
> >> +        String actual = msg.getFormattedMessage();
> >> +        assertEquals("Should use initial param value", "Test message
> abc", actual);
> >> +    }
> >> +
> >> }
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/MapMessageTest.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/MapMessageTest.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/MapMessageTest.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/MapMessageTest.java
> Sun Aug 10 06:40:14 2014
> >> @@ -70,4 +70,22 @@ public class MapMessageTest {
> >>         final String expected = "{message=\"Test message {}\",
> project=\"Log4j\"}";
> >>         assertEquals(expected, result);
> >>     }
> >> +
> >> +    @Test
> >> +    public void testMutableByDesign() { // LOG4J2-763
> >> +        MapMessage msg = new MapMessage();
> >> +
> >> +        // modify parameter before calling msg.getFormattedMessage
> >> +        msg.put("key1", "value1");
> >> +        msg.put("key2", "value2");
> >> +        final String result = msg.getFormattedMessage(new
> String[]{"Java"});
> >> +        final String expected = "{key1=\"value1\", key2=\"value2\"}";
> >> +        assertEquals(expected, result);
> >> +
> >> +        // modify parameter after calling msg.getFormattedMessage
> >> +        msg.put("key3", "value3");
> >> +        final String result2 = msg.getFormattedMessage(new
> String[]{"Java"});
> >> +        final String expected2 = "{key1=\"value1\", key2=\"value2\",
> key3=\"value3\"}";
> >> +        assertEquals(expected2, result2);
> >> +    }
> >> }
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/MessageFormatMessageTest.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/MessageFormatMessageTest.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/MessageFormatMessageTest.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/MessageFormatMessageTest.java
> Sun Aug 10 06:40:14 2014
> >> @@ -61,4 +61,16 @@ public class MessageFormatMessageTest {
> >>         final Throwable t = msg.getThrowable();
> >>         assertNotNull("No Throwable", t);
> >>     }
> >> +
> >> +    @Test
> >> +    public void testSafeWithMutableParams() { // LOG4J2-763
> >> +        final String testMsg = "Test message {0}";
> >> +        final Mutable param = new Mutable().set("abc");
> >> +        MessageFormatMessage msg = new MessageFormatMessage(testMsg,
> param);
> >> +
> >> +        // modify parameter before calling msg.getFormattedMessage
> >> +        param.set("XYZ");
> >> +        String actual = msg.getFormattedMessage();
> >> +        assertEquals("Should use initial param value", "Test message
> abc", actual);
> >> +    }
> >> }
> >>
> >> Added:
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/Mutable.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/Mutable.java?rev=1617051&view=auto
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/Mutable.java
> (added)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/Mutable.java
> Sun Aug 10 06:40:14 2014
> >> @@ -0,0 +1,34 @@
> >> +/*
> >> + * 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.message;
> >> +
> >> +/**
> >> + * Helper class for JUnit tests.
> >> + */
> >> +class Mutable {
> >> +    private String value;
> >> +
> >> +    public Mutable set(String value) {
> >> +        this.value = value;
> >> +        return this;
> >> +    }
> >> +
> >> +    @Override
> >> +    public String toString() {
> >> +        return this.value;
> >> +    }
> >> +}
> >> \ No newline at end of file
> >>
> >> Propchange:
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/Mutable.java
> >>
> ------------------------------------------------------------------------------
> >>    svn:eol-style = native
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ObjectMessageTest.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ObjectMessageTest.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ObjectMessageTest.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ObjectMessageTest.java
> Sun Aug 10 06:40:14 2014
> >> @@ -39,4 +39,15 @@ public class ObjectMessageTest {
> >>         final String result = msg.getFormattedMessage();
> >>         assertEquals(testMsg, result);
> >>     }
> >> +
> >> +    @Test
> >> +    public void testSafeWithMutableParams() { // LOG4J2-763
> >> +        final Mutable param = new Mutable().set("abc");
> >> +        ObjectMessage msg = new ObjectMessage(param);
> >> +
> >> +        // modify parameter before calling msg.getFormattedMessage
> >> +        param.set("XYZ");
> >> +        String actual = msg.getFormattedMessage();
> >> +        assertEquals("Should use initial param value", "abc", actual);
> >> +    }
> >> }
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java
> Sun Aug 10 06:40:14 2014
> >> @@ -36,4 +36,16 @@ public class ParameterizedMessageTest {
> >>         result = msg.getFormattedMessage();
> >>         assertEquals(testMsg, result);
> >>     }
> >> +
> >> +    @Test
> >> +    public void testSafeWithMutableParams() { // LOG4J2-763
> >> +        final String testMsg = "Test message {}";
> >> +        final Mutable param = new Mutable().set("abc");
> >> +        ParameterizedMessage msg = new ParameterizedMessage(testMsg,
> param);
> >> +
> >> +        // modify parameter before calling msg.getFormattedMessage
> >> +        param.set("XYZ");
> >> +        String actual = msg.getFormattedMessage();
> >> +        assertEquals("Should use initial param value", "Test message
> abc", actual);
> >> +    }
> >> }
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java
> Sun Aug 10 06:40:14 2014
> >> @@ -60,4 +60,16 @@ public class StringFormattedMessageTest
> >>         final Throwable t = msg.getThrowable();
> >>         assertNotNull("No Throwable", t);
> >>     }
> >> +
> >> +    @Test
> >> +    public void testSafeWithMutableParams() { // LOG4J2-763
> >> +        final String testMsg = "Test message %s";
> >> +        final Mutable param = new Mutable().set("abc");
> >> +        StringFormattedMessage msg = new
> StringFormattedMessage(testMsg, param);
> >> +
> >> +        // modify parameter before calling msg.getFormattedMessage
> >> +        param.set("XYZ");
> >> +        String actual = msg.getFormattedMessage();
> >> +        assertEquals("Should use initial param value", "Test message
> abc", actual);
> >> +    }
> >> }
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java
> Sun Aug 10 06:40:14 2014
> >> @@ -43,4 +43,23 @@ public class StructuredDataMessageTest {
> >>         final StructuredDataMessage msg = new
> StructuredDataMessage("MsgId@12345", testMsg, "Alert");
> >>         msg.put("This is a very long key that will violate the key
> length validation", "Testing");
> >>     }
> >> +
> >> +    @Test
> >> +    public void testMutableByDesign() { // LOG4J2-763
> >> +        final String testMsg = "Test message {}";
> >> +        StructuredDataMessage msg = new StructuredDataMessage("MsgId@1",
> testMsg, "Alert");
> >> +
> >> +        // modify parameter before calling msg.getFormattedMessage
> >> +        msg.put("message", testMsg);
> >> +        msg.put("project", "Log4j");
> >> +        final String result = msg.getFormattedMessage();
> >> +        final String expected = "Alert [MsgId@1 message=\"Test
> message {}\" project=\"Log4j\"] Test message {}";
> >> +        assertEquals(expected, result);
> >> +
> >> +        // modify parameter after calling msg.getFormattedMessage
> >> +        msg.put("memo", "Added later");
> >> +        final String result2 = msg.getFormattedMessage();
> >> +        final String expected2 = "Alert [MsgId@1 memo=\"Added later\"
> message=\"Test message {}\" project=\"Log4j\"] Test message {}";
> >> +        assertEquals(expected2, result2);
> >> +    }
> >> }
> >>
> >> Modified:
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ThreadDumpMessageTest.java
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ThreadDumpMessageTest.java?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> ---
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ThreadDumpMessageTest.java
> (original)
> >> +++
> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ThreadDumpMessageTest.java
> Sun Aug 10 06:40:14 2014
> >> @@ -73,6 +73,22 @@ public class ThreadDumpMessageTest {
> >>         assertEquals(expected, msg.toString());
> >>     }
> >>
> >> +    @Test
> >> +    public void testUseConstructorThread() throws InterruptedException
> { // LOG4J2-763
> >> +        final ThreadDumpMessage msg = new ThreadDumpMessage("Test");
> >> +
> >> +        final String[] actual = new String[1];
> >> +        Thread other = new Thread("OtherThread") {
> >> +            public void run() {
> >> +                actual[0] = msg.getFormattedMessage();
> >> +            }
> >> +        };
> >> +        other.start();
> >> +        other.join();
> >> +
> >> +        assertTrue("No mention of other thread in msg",
> !actual[0].contains("OtherThread"));
> >> +    }
> >> +
> >>     private class Thread1 extends Thread {
> >>         private final ReentrantLock lock;
> >>
> >>
> >> Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> --- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
> >> +++ logging/log4j/log4j2/trunk/src/changes/changes.xml Sun Aug 10
> 06:40:14 2014
> >> @@ -22,6 +22,12 @@
> >>   </properties>
> >>   <body>
> >>     <release version="2.0.2" date="2014-0?-??" description="Bug fixes
> and enhancements">
> >> +      <action issue="LOG4J2-763" dev="rpopma" type="fix">
> >> +        Improved FormattedMessage, StringFormattedMessage,
> LocalizedMessage, MessageFormatMessage and
> >> +        ObjectMessage for asynchronous logging to ensure the formatted
> message does not change even if
> >> +        parameters are modified by the application.
> (ParameterizedMessage was already safe.)
> >> +        Improved documentation.
> >> +      </action>
> >>       <action issue="LOG4J2-729" dev="rpopma" type="fix">
> >>         Emit warning message to console if no configuration file found.
> >>       </action>
> >>
> >> Modified: logging/log4j/log4j2/trunk/src/site/xdoc/manual/async.xml
> >> URL:
> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/site/xdoc/manual/async.xml?rev=1617051&r1=1617050&r2=1617051&view=diff
> >>
> ==============================================================================
> >> --- logging/log4j/log4j2/trunk/src/site/xdoc/manual/async.xml (original)
> >> +++ logging/log4j/log4j2/trunk/src/site/xdoc/manual/async.xml Sun Aug
> 10 06:40:14 2014
> >> @@ -124,6 +124,26 @@
> >> logging in addition to synchronous
> >> logging for the audit trail.)
> >> </li>
> >> +     <li>In some rare cases, care must be taken with mutable messages.
> >> +       Most of the time you don't need to worry about this. Log4 will
> ensure that log messages like
> >> +       <code>logger.debug("My object is {}", myObject)</code> will use
> the state of the
> >> +       <code>myObject</code> parameter at the time of the call to
> <code>logger.debug()</code>.
> >> +       The log message will not change even if <code>myObject</code>
> is modified later.
> >> +       It is safe to asynchronously log mutable objects because most
> >> +       <a
> href="../log4j-api/apidocs/org/apache/logging/log4j/message/Message.html">Message</a>
> >> +       implementations built-in to Log4j take a snapshot of the
> parameters.
> >> +       There are some exceptions however:
> >> +       <a
> href="../log4j-api/apidocs/org/apache/logging/log4j/message/MapMessage.html">MapMessage</a>
> >> +       and
> >> +       <a
> href="../log4j-api/apidocs/org/apache/logging/log4j/message/StructuredDataMessage.html">StructuredDataMessage</a>
> >> +       are mutable by design: fields can be added to these messages
> after the message object was created.
> >> +       These messages should not be modified after they are logged
> with asynchronous loggers or
> >> +       asynchronous appenders; you may or may not see the
> modifications in the resulting log output.
> >> +       Similarly, custom
> >> +       <a
> href="../log4j-api/apidocs/org/apache/logging/log4j/message/Message.html">Message</a>
> >> +       implementations should be designed with asynchronous use in
> mind, and either take a snapshot
> >> +       of their parameters at construction time, or document their
> thread-safety characteristics.
> >> +     </li>
> >> </ul>
> >> </subsection>
> >> <a name="AllAsync" />
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org
> <javascript:;>
> > For additional commands, e-mail: log4j-dev-help@logging.apache.org
> <javascript:;>
> >
>