[
https://issues.apache.org/jira/browse/LOG4J2-763?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14084247#comment-14084247
]
Remko Popma edited comment on LOG4J2-763 at 8/4/14 3:05 AM:
------------------------------------------------------------
Strange: I thought ParameterizedMessage was okay because it already takes a
snapshot of the parameters when the LogEvent is created, but looking again at
Stephen's blog post, he is using... parameterized messages.
Looking at the resulting log output, I can't actually see what is wrong with it.
Stephen, what did you expect to see in the log output?
The suggested solution:
{code}
if (logger.isWarnEnabled()) {
logger.warn("{} == {}", instance.next(), instance.toString());
}
{code}
I don't think this will produce different results, does it? The only difference
I can see is that the window of opportunity for another thread to increment the
counter is narrower now than in the original code. But it will still not
*guarantee* that you see the same number...
The problem is that the {{value}} field is static, so shared by all App
instances. Giving each Thread its own App instance does not help since they all
still share the same AtomicLong {{value}} field.
was (Author: [email protected]):
Strange: I thought ParameterizedMessage was okay because it already takes a
snapshot of the parameters when the LogEvent is created, but looking again at
Stephen's blog post, he is using... parameterized messages.
Looking at the resulting log output, I can't actually see what is wrong with it.
Stephen, what did you expect to see in the log output?
The suggested solution:
{code}
if (logger.isWarnEnabled()) {
logger.warn("{} == {}", instance.next(), instance.toString());
}
{code}
I don't think this will produce different results, does it? The only difference
I can see is that the window of opportunity for another thread to increment the
counter is narrower in the code below. But it will still not *guarantee* that
you see the same number...
The problem is that the {{value}} field is static, so shared by all App
instances. Giving each Thread its own App instance does not help since they all
still share the same AtomicLong {{value}} field.
> Async loggers convert message parameters toString at log record writing not
> at log statement execution
> ------------------------------------------------------------------------------------------------------
>
> Key: LOG4J2-763
> URL: https://issues.apache.org/jira/browse/LOG4J2-763
> Project: Log4j 2
> Issue Type: Bug
> Affects Versions: 2.0
> Reporter: Stephen Connolly
>
> http://javaadventure.blogspot.com/2014/07/log4j-20-async-loggers-and-immutability.html
> When using parameterized messages, the toString() method of the log messages
> is not called when the log message is enqueued, rather after the log message
> has been dequeued for writing. If any of the message parameters are mutable,
> they can thus have changed state before the log message is written, thus
> resulting in the logged message content being incorrect.
> From the blog post, code that demonstrates the problem:
> {code}
> import org.apache.logging.log4j.LogManager;
> import org.apache.logging.log4j.Logger;
> import java.util.concurrent.atomic.AtomicLong;
> public class App {
> private static final AtomicLong value = new AtomicLong();
> public String toString() {
> return Long.toString(value.get());
> }
> public long next() {
> return value.incrementAndGet();
> }
> public static void main(String[] args) {
> for (int i = 0; i < 32; i++) {
> new Thread() {
> final Logger logger = LogManager.getLogger(App.class);
> final App instance = new App();
> @Override
> public void run() {
> for (int i = 0; i < 100000; i++) {
> logger.warn("{} == {}", instance.next(), instance);
> }
> }
> }.start();
> }
> }
> }
> {code}
> Here is the first few lines of logging output
> {code}
> 2014-07-28 15:59:45,729 WARN t.App [Thread-13] 13 == 13
> 2014-07-28 15:59:45,730 WARN t.App [Thread-29] 29 == 29
> 2014-07-28 15:59:45,729 WARN t.App [Thread-15] 15 == 15
> 2014-07-28 15:59:45,729 WARN t.App [Thread-6] 6 == 6
> 2014-07-28 15:59:45,730 WARN t.App [Thread-30] 30 == 30
> 2014-07-28 15:59:45,729 WARN t.App [Thread-20] 20 == 20
> 2014-07-28 15:59:45,729 WARN t.App [Thread-8] 8 == 8
> 2014-07-28 15:59:45,730 WARN t.App [Thread-28] 28 == 28
> 2014-07-28 15:59:45,729 WARN t.App [Thread-19] 19 == 19
> 2014-07-28 15:59:45,729 WARN t.App [Thread-18] 18 == 18
> 2014-07-28 15:59:45,729 WARN t.App [Thread-5] 5 == 6
> 2014-07-28 15:59:45,731 WARN t.App [Thread-13] 33 == 37
> 2014-07-28 15:59:45,731 WARN t.App [Thread-8] 39 == 39
> 2014-07-28 15:59:45,731 WARN t.App [Thread-28] 40 == 41
> 2014-07-28 15:59:45,731 WARN t.App [Thread-18] 42 == 43
> 2014-07-28 15:59:45,731 WARN t.App [Thread-5] 43 == 43
> {code}
> To make my previous code work with Asynchronous loggers (other than by fixing
> the mutable state) I would need to log like this:
> {code}
> if (logger.isWarnEnabled()) {
> logger.warn("{} == {}", instance.next(), instance.toString());
> }
> {code}
--
This message was sent by Atlassian JIRA
(v6.2#6252)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]