You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rp...@apache.org on 2014/07/12 13:22:51 UTC
svn commit: r1609903 - in /logging/log4j/log4j2/trunk:
log4j-api/src/main/java/org/apache/logging/log4j/
log4j-api/src/main/java/org/apache/logging/log4j/spi/
log4j-api/src/test/java/org/apache/logging/log4j/spi/
log4j-core/src/test/java/org/apache/log...
Author: rpopma
Date: Sat Jul 12 11:22:51 2014
New Revision: 1609903
URL: http://svn.apache.org/r1609903
Log:
LOG4J2-705 Fixed issue where Async Logger does not log thread context stack data. API change: added method getImmutableStackOrNull() to ThreadContext.ContextStack interface.
Added:
logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadContextTest.java (with props)
logging/log4j/log4j2/trunk/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml (with props)
Modified:
logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextStack.java
logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableThreadContextStack.java
logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextStackTest.java
logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/spi/MutableThreadContextStackTest.java
logging/log4j/log4j2/trunk/src/changes/changes.xml
Modified: logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java?rev=1609903&r1=1609902&r2=1609903&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java (original)
+++ logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java Sat Jul 12 11:22:51 2014
@@ -142,6 +142,10 @@ public final class ThreadContext {
return 0;
}
+ @Override
+ public ContextStack getImmutableStackOrNull() {
+ return this;
+ }
}
/**
@@ -169,12 +173,14 @@ public final class ThreadContext {
/**
* Empty, immutable Map.
*/
- @SuppressWarnings("PublicStaticCollectionField")
+ // ironically, this annotation gives an "unsupported @SuppressWarnings" warning in Eclipse
+ @SuppressWarnings("PublicStaticCollectionField") // I like irony, so I won't delete it...
public static final Map<String, String> EMPTY_MAP = Collections.emptyMap();
/**
* Empty, immutable ContextStack.
*/
+ // ironically, this annotation gives an "unsupported @SuppressWarnings" warning in Eclipse
@SuppressWarnings("PublicStaticCollectionField")
public static final ThreadContextStack EMPTY_STACK = new EmptyThreadContextStack();
@@ -352,7 +358,8 @@ public final class ThreadContext {
* @return an immutable copy of the ThreadContext stack.
*/
public static ContextStack getImmutableStack() {
- return contextStack;
+ ContextStack result = contextStack.getImmutableStackOrNull();
+ return result == null ? EMPTY_STACK : result;
}
/**
@@ -527,8 +534,16 @@ public final class ThreadContext {
/**
* Returns a copy of the ContextStack.
- * @return a copy of the ContextStack.s
+ * @return a copy of the ContextStack.
*/
ContextStack copy();
+
+ /**
+ * Returns a ContextStack with the same contents as this ContextStack or {@code null}.
+ * Attempts to modify the returned stack may or may not throw an exception, but will not affect the contents
+ * of this ContextStack.
+ * @return a ContextStack with the same contents as this ContextStack or {@code null}.
+ */
+ ContextStack getImmutableStackOrNull();
}
}
Modified: logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextStack.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextStack.java?rev=1609903&r1=1609902&r2=1609903&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextStack.java (original)
+++ logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextStack.java Sat Jul 12 11:22:51 2014
@@ -16,13 +16,13 @@
*/
package org.apache.logging.log4j.spi;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
+import org.apache.logging.log4j.ThreadContext.ContextStack;
import org.apache.logging.log4j.util.Strings;
/**
@@ -33,23 +33,28 @@ public class DefaultThreadContextStack i
private static final long serialVersionUID = 5050501L;
- private static final ThreadLocal<List<String>> stack = new ThreadLocal<List<String>>();
+ private static final ThreadLocal<MutableThreadContextStack> stack = new ThreadLocal<MutableThreadContextStack>();
private final boolean useStack;
public DefaultThreadContextStack(final boolean useStack) {
this.useStack = useStack;
}
+
+ private MutableThreadContextStack getNonNullStackCopy() {
+ final MutableThreadContextStack values = stack.get();
+ return (MutableThreadContextStack) (values == null ? new MutableThreadContextStack() : values.copy());
+ }
@Override
public boolean add(final String s) {
if (!useStack) {
return false;
}
- final List<String> list = stack.get();
- final List<String> copy = list == null ? new ArrayList<String>() : new ArrayList<String>(list);
+ final MutableThreadContextStack copy = getNonNullStackCopy();
copy.add(s);
- stack.set(Collections.unmodifiableList(copy));
+ copy.freeze();
+ stack.set(copy);
return true;
}
@@ -58,20 +63,20 @@ public class DefaultThreadContextStack i
if (!useStack || strings.isEmpty()) {
return false;
}
- final List<String> list = stack.get();
- final List<String> copy = list == null ? new ArrayList<String>() : new ArrayList<String>(list);
+ final MutableThreadContextStack copy = getNonNullStackCopy();
copy.addAll(strings);
- stack.set(Collections.unmodifiableList(copy));
+ copy.freeze();
+ stack.set(copy);
return true;
}
@Override
public List<String> asList() {
- final List<String> list = stack.get();
- if (list == null) {
+ final MutableThreadContextStack values = stack.get();
+ if (values == null) {
return Collections.emptyList();
}
- return list;
+ return values.asList();
}
@Override
@@ -81,8 +86,8 @@ public class DefaultThreadContextStack i
@Override
public boolean contains(final Object o) {
- final List<String> result = stack.get();
- return result != null && result.contains(o);
+ final MutableThreadContextStack values = stack.get();
+ return values != null && values.contains(o);
}
@Override
@@ -91,17 +96,17 @@ public class DefaultThreadContextStack i
return true; // looks counter-intuitive, but see
// j.u.AbstractCollection
}
- final List<String> list = stack.get();
- return list != null && list.containsAll(objects);
+ final MutableThreadContextStack values = stack.get();
+ return values != null && values.containsAll(objects);
}
@Override
public ThreadContextStack copy() {
- List<String> result = null;
- if (!useStack || (result = stack.get()) == null) {
- return new MutableThreadContextStack(new ArrayList<String>());
+ MutableThreadContextStack values = null;
+ if (!useStack || (values = stack.get()) == null) {
+ return new MutableThreadContextStack();
}
- return new MutableThreadContextStack(result);
+ return values.copy();
}
@Override
@@ -122,58 +127,52 @@ public class DefaultThreadContextStack i
return false;
}
final ThreadContextStack other = (ThreadContextStack) obj;
- final List<String> otherAsList = other.asList();
- final List<String> list = stack.get();
- if (list == null) {
- if (otherAsList != null) {
- return false;
- }
- } else if (!list.equals(otherAsList)) {
- return false;
+ final MutableThreadContextStack values = stack.get();
+ if (values == null) {
+ return other == null;
}
- return true;
+ return values.equals(other);
}
@Override
public int getDepth() {
- final List<String> list = stack.get();
- return list == null ? 0 : list.size();
+ final MutableThreadContextStack values = stack.get();
+ return values == null ? 0 : values.getDepth();
}
@Override
public int hashCode() {
- final List<String> list = stack.get();
+ final MutableThreadContextStack values = stack.get();
final int prime = 31;
int result = 1;
// Factor in the stack itself to compare vs. other implementors.
- result = prime * result + ((list == null) ? 0 : list.hashCode());
+ result = prime * result + ((values == null) ? 0 : values.hashCode());
return result;
}
@Override
public boolean isEmpty() {
- final List<String> result = stack.get();
- return result == null || result.isEmpty();
+ final MutableThreadContextStack values = stack.get();
+ return values == null || values.isEmpty();
}
@Override
public Iterator<String> iterator() {
- final List<String> immutable = stack.get();
- if (immutable == null) {
+ final MutableThreadContextStack values = stack.get();
+ if (values == null) {
final List<String> empty = Collections.emptyList();
return empty.iterator();
}
- return immutable.iterator();
+ return values.iterator();
}
@Override
public String peek() {
- final List<String> list = stack.get();
- if (list == null || list.size() == 0) {
+ final MutableThreadContextStack values = stack.get();
+ if (values == null || values.size() == 0) {
return null;
}
- final int last = list.size() - 1;
- return list.get(last);
+ return values.peek();
}
@Override
@@ -181,14 +180,14 @@ public class DefaultThreadContextStack i
if (!useStack) {
return Strings.EMPTY;
}
- final List<String> list = stack.get();
- if (list == null || list.size() == 0) {
+ final MutableThreadContextStack values = stack.get();
+ if (values == null || values.size() == 0) {
throw new NoSuchElementException("The ThreadContext stack is empty");
}
- final List<String> copy = new ArrayList<String>(list);
- final int last = copy.size() - 1;
- final String result = copy.remove(last);
- stack.set(Collections.unmodifiableList(copy));
+ final MutableThreadContextStack copy = (MutableThreadContextStack) values.copy();
+ final String result = copy.pop();
+ copy.freeze();
+ stack.set(copy);
return result;
}
@@ -205,13 +204,14 @@ public class DefaultThreadContextStack i
if (!useStack) {
return false;
}
- final List<String> list = stack.get();
- if (list == null || list.size() == 0) {
+ final MutableThreadContextStack values = stack.get();
+ if (values == null || values.size() == 0) {
return false;
}
- final List<String> copy = new ArrayList<String>(list);
+ final MutableThreadContextStack copy = (MutableThreadContextStack) values.copy();
final boolean result = copy.remove(o);
- stack.set(Collections.unmodifiableList(copy));
+ copy.freeze();
+ stack.set(copy);
return result;
}
@@ -220,13 +220,14 @@ public class DefaultThreadContextStack i
if (!useStack || objects.isEmpty()) {
return false;
}
- final List<String> list = stack.get();
- if (list == null || list.isEmpty()) {
+ final MutableThreadContextStack values = stack.get();
+ if (values == null || values.isEmpty()) {
return false;
}
- final List<String> copy = new ArrayList<String>(list);
+ final MutableThreadContextStack copy = (MutableThreadContextStack) values.copy();
final boolean result = copy.removeAll(objects);
- stack.set(Collections.unmodifiableList(copy));
+ copy.freeze();
+ stack.set(copy);
return result;
}
@@ -235,25 +236,26 @@ public class DefaultThreadContextStack i
if (!useStack || objects.isEmpty()) {
return false;
}
- final List<String> list = stack.get();
- if (list == null || list.isEmpty()) {
+ final MutableThreadContextStack values = stack.get();
+ if (values == null || values.isEmpty()) {
return false;
}
- final List<String> copy = new ArrayList<String>(list);
+ final MutableThreadContextStack copy = (MutableThreadContextStack) values.copy();
final boolean result = copy.retainAll(objects);
- stack.set(Collections.unmodifiableList(copy));
+ copy.freeze();
+ stack.set(copy);
return result;
}
@Override
public int size() {
- final List<String> result = stack.get();
- return result == null ? 0 : result.size();
+ final MutableThreadContextStack values = stack.get();
+ return values == null ? 0 : values.size();
}
@Override
public Object[] toArray() {
- final List<String> result = stack.get();
+ final MutableThreadContextStack result = stack.get();
if (result == null) {
return new String[0];
}
@@ -262,7 +264,7 @@ public class DefaultThreadContextStack i
@Override
public <T> T[] toArray(final T[] ts) {
- final List<String> result = stack.get();
+ final MutableThreadContextStack result = stack.get();
if (result == null) {
if (ts.length > 0) { // as per the contract of j.u.List#toArray(T[])
ts[0] = null;
@@ -274,8 +276,8 @@ public class DefaultThreadContextStack i
@Override
public String toString() {
- final List<String> list = stack.get();
- return list == null ? "[]" : list.toString();
+ final MutableThreadContextStack values = stack.get();
+ return values == null ? "[]" : values.toString();
}
@Override
@@ -283,15 +285,21 @@ public class DefaultThreadContextStack i
if (depth < 0) {
throw new IllegalArgumentException("Maximum stack depth cannot be negative");
}
- final List<String> list = stack.get();
- if (list == null) {
+ final MutableThreadContextStack values = stack.get();
+ if (values == null) {
return;
}
- final List<String> copy = new ArrayList<String>();
- final int count = Math.min(depth, list.size());
- for (int i = 0; i < count; i++) {
- copy.add(list.get(i));
- }
+ final MutableThreadContextStack copy = (MutableThreadContextStack) values.copy();
+ copy.trim(depth);
+ copy.freeze();
stack.set(copy);
}
+
+ /* (non-Javadoc)
+ * @see org.apache.logging.log4j.ThreadContext.ContextStack#getImmutableStackOrNull()
+ */
+ @Override
+ public ContextStack getImmutableStackOrNull() {
+ return stack.get();
+ }
}
Modified: logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableThreadContextStack.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableThreadContextStack.java?rev=1609903&r1=1609902&r2=1609903&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableThreadContextStack.java (original)
+++ logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableThreadContextStack.java Sat Jul 12 11:22:51 2014
@@ -21,6 +21,8 @@ import java.util.Collection;
import java.util.Iterator;
import java.util.List;
+import org.apache.logging.log4j.ThreadContext.ContextStack;
+
/**
*
*/
@@ -32,6 +34,14 @@ public class MutableThreadContextStack i
* The underlying list (never null).
*/
private final List<String> list;
+ private boolean frozen;
+
+ /**
+ * Constructs an empty MutableThreadContextStack.
+ */
+ public MutableThreadContextStack() {
+ this(new ArrayList<String>());
+ }
public MutableThreadContextStack(final List<String> list) {
this.list = new ArrayList<String>(list);
@@ -41,8 +51,15 @@ public class MutableThreadContextStack i
this.list = new ArrayList<String>(stack.list);
}
+ private void checkInvariants() {
+ if (frozen) {
+ throw new UnsupportedOperationException("context stack has been frozen");
+ }
+ }
+
@Override
public String pop() {
+ checkInvariants();
if (list.isEmpty()) {
return null;
}
@@ -62,6 +79,7 @@ public class MutableThreadContextStack i
@Override
public void push(final String message) {
+ checkInvariants();
list.add(message);
}
@@ -77,6 +95,7 @@ public class MutableThreadContextStack i
@Override
public void trim(final int depth) {
+ checkInvariants();
if (depth < 0) {
throw new IllegalArgumentException("Maximum stack depth cannot be negative");
}
@@ -99,6 +118,7 @@ public class MutableThreadContextStack i
@Override
public void clear() {
+ checkInvariants();
list.clear();
}
@@ -134,11 +154,13 @@ public class MutableThreadContextStack i
@Override
public boolean add(final String s) {
+ checkInvariants();
return list.add(s);
}
@Override
public boolean remove(final Object o) {
+ checkInvariants();
return list.remove(o);
}
@@ -149,16 +171,19 @@ public class MutableThreadContextStack i
@Override
public boolean addAll(final Collection<? extends String> strings) {
+ checkInvariants();
return list.addAll(strings);
}
@Override
public boolean removeAll(final Collection<?> objects) {
+ checkInvariants();
return list.removeAll(objects);
}
@Override
public boolean retainAll(final Collection<?> objects) {
+ checkInvariants();
return list.retainAll(objects);
}
@@ -197,4 +222,20 @@ public class MutableThreadContextStack i
}
return true;
}
+
+ @Override
+ public ContextStack getImmutableStackOrNull() {
+ return copy();
+ }
+
+ /**
+ * "Freezes" this context stack so it becomes immutable: all mutator methods will throw an exception from now on.
+ */
+ public void freeze() {
+ frozen = true;
+ }
+
+ public boolean isFrozen() {
+ return frozen;
+ }
}
Modified: logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextStackTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextStackTest.java?rev=1609903&r1=1609902&r2=1609903&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextStackTest.java (original)
+++ logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextStackTest.java Sat Jul 12 11:22:51 2014
@@ -19,12 +19,20 @@ package org.apache.logging.log4j.spi;
import java.util.Arrays;
import java.util.Iterator;
+import org.apache.logging.log4j.ThreadContext.ContextStack;
+import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class DefaultThreadContextStackTest {
+ @Before
+ public void before() {
+ // clear the thread-local map
+ new DefaultThreadContextMap(true).clear();
+ }
+
@Test
public void testEqualsVsSameKind() {
final DefaultThreadContextStack stack1 = createStack();
@@ -53,10 +61,38 @@ public class DefaultThreadContextStackTe
}
@Test
- public void testHashCodeVsMutable() {
- final DefaultThreadContextStack stack1 = createStack();
- final MutableThreadContextStack stack2 = MutableThreadContextStackTest.createStack();
- assertEquals(stack1.hashCode(), stack2.hashCode());
+ public void testImmutableOrNullReturnsNullIfUseStackIsFalse() {
+ final DefaultThreadContextStack stack = new DefaultThreadContextStack(false);
+ stack.clear();
+ assertEquals(null, stack.getImmutableStackOrNull());
+ }
+
+ @Test
+ public void testImmutableOrNullReturnsNullIfStackIsEmpty() {
+ final DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ assertEquals(null, stack.getImmutableStackOrNull());
+ }
+
+ @Test
+ public void testImmutableOrNullReturnsCopyOfContents() {
+ final DefaultThreadContextStack stack = createStack();
+ assertTrue(!stack.isEmpty());
+ final ContextStack actual = stack.getImmutableStackOrNull();
+ assertNotNull(actual);
+ assertEquals(stack, actual);
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testModifyingImmutableOrNullThrowsException() {
+ final DefaultThreadContextStack stack = createStack();
+ final int originalSize = stack.size();
+ assertTrue(originalSize > 0);
+ final ContextStack actual = stack.getImmutableStackOrNull();
+ assertEquals(originalSize, actual.size());
+
+ actual.pop();
}
@Test
@@ -215,7 +251,7 @@ public class DefaultThreadContextStackTe
public void testToArray() {
final DefaultThreadContextStack stack = createStack();
- final String[] expecteds = {"msg1", "msg2", "msg3"};
+ final String[] expecteds = { "msg1", "msg2", "msg3" };
assertArrayEquals(expecteds, stack.toArray());
}
@@ -223,8 +259,8 @@ public class DefaultThreadContextStackTe
public void testToArrayTArray() {
final DefaultThreadContextStack stack = createStack();
- final String[] expecteds = {"msg1", "msg2", "msg3"};
- final String[] result = new String[3] ;
+ final String[] expecteds = { "msg1", "msg2", "msg3" };
+ final String[] result = new String[3];
assertArrayEquals(expecteds, stack.toArray(result));
assertSame(result, stack.toArray(result));
}
Modified: logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/spi/MutableThreadContextStackTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/spi/MutableThreadContextStackTest.java?rev=1609903&r1=1609902&r2=1609903&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/spi/MutableThreadContextStackTest.java (original)
+++ logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/spi/MutableThreadContextStackTest.java Sat Jul 12 11:22:51 2014
@@ -202,7 +202,7 @@ public class MutableThreadContextStackTe
public void testToArray() {
final MutableThreadContextStack stack = createStack();
- final String[] expecteds = {"msg1", "msg2", "msg3"};
+ final String[] expecteds = { "msg1", "msg2", "msg3" };
assertArrayEquals(expecteds, stack.toArray());
}
@@ -210,8 +210,8 @@ public class MutableThreadContextStackTe
public void testToArrayTArray() {
final MutableThreadContextStack stack = createStack();
- final String[] expecteds = {"msg1", "msg2", "msg3"};
- final String[] result = new String[3] ;
+ final String[] expecteds = { "msg1", "msg2", "msg3" };
+ final String[] result = new String[3];
assertArrayEquals(expecteds, stack.toArray(result));
assertSame(result, stack.toArray(result));
}
@@ -287,4 +287,81 @@ public class MutableThreadContextStackTe
stack.retainAll(Arrays.asList("msg1", "msg3"));
assertEquals("[msg1, msg3]", stack.toString());
}
+
+ @Test
+ public void testIsFrozenIsFalseByDefault() {
+ assertFalse(new MutableThreadContextStack().isFrozen());
+ assertFalse(createStack().isFrozen());
+ }
+
+ @Test
+ public void testIsFrozenIsTrueAfterCallToFreeze() {
+ final MutableThreadContextStack stack = new MutableThreadContextStack();
+ assertFalse(stack.isFrozen());
+ stack.freeze();
+ assertTrue(stack.isFrozen());
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testAddAllOnFrozenStackThrowsException() {
+ final MutableThreadContextStack stack = new MutableThreadContextStack();
+ stack.freeze();
+ stack.addAll(Arrays.asList("a", "b", "c"));
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testAddOnFrozenStackThrowsException() {
+ final MutableThreadContextStack stack = new MutableThreadContextStack();
+ stack.freeze();
+ stack.add("a");
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testClearOnFrozenStackThrowsException() {
+ final MutableThreadContextStack stack = new MutableThreadContextStack();
+ stack.freeze();
+ stack.clear();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testPopOnFrozenStackThrowsException() {
+ final MutableThreadContextStack stack = new MutableThreadContextStack();
+ stack.freeze();
+ stack.pop();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testPushOnFrozenStackThrowsException() {
+ final MutableThreadContextStack stack = new MutableThreadContextStack();
+ stack.freeze();
+ stack.push("a");
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testRemoveOnFrozenStackThrowsException() {
+ final MutableThreadContextStack stack = new MutableThreadContextStack();
+ stack.freeze();
+ stack.remove("a");
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testRemoveAllOnFrozenStackThrowsException() {
+ final MutableThreadContextStack stack = new MutableThreadContextStack();
+ stack.freeze();
+ stack.removeAll(Arrays.asList("a", "b"));
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testRetainAllOnFrozenStackThrowsException() {
+ final MutableThreadContextStack stack = new MutableThreadContextStack();
+ stack.freeze();
+ stack.retainAll(Arrays.asList("a", "b"));
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testTrimOnFrozenStackThrowsException() {
+ final MutableThreadContextStack stack = new MutableThreadContextStack();
+ stack.freeze();
+ stack.trim(3);
+ }
}
Added: logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadContextTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadContextTest.java?rev=1609903&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadContextTest.java (added)
+++ logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadContextTest.java Sat Jul 12 11:22:51 2014
@@ -0,0 +1,76 @@
+/*
+ * 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.core.async;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.LifeCycle;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.util.Strings;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class AsyncLoggerThreadContextTest {
+
+ @BeforeClass
+ public static void beforeClass() {
+ System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR,
+ AsyncLoggerContextSelector.class.getName());
+ System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY,
+ "AsyncLoggerThreadContextTest.xml");
+ }
+
+ @AfterClass
+ public static void afterClass() {
+ System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, Strings.EMPTY);
+ }
+
+ @Test
+ public void testAsyncLogWritesToLog() throws Exception {
+ final File f = new File("target", "AsyncLoggerTest.log");
+ // System.out.println(f.getAbsolutePath());
+ f.delete();
+
+ ThreadContext.push("stackvalue");
+ ThreadContext.put("KEY", "mapvalue");
+
+ final Logger log = LogManager.getLogger("com.foo.Bar");
+ final String msg = "Async logger msg";
+ log.info(msg, new InternalError("this is not a real error"));
+ ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
+
+ final BufferedReader reader = new BufferedReader(new FileReader(f));
+ final String line1 = reader.readLine();
+ reader.close();
+ f.delete();
+ assertNotNull("line1", line1);
+ assertTrue("line1 correct", line1.contains(msg));
+
+ assertTrue("ThreadContext.map", line1.contains("mapvalue"));
+ assertTrue("ThreadContext.stack", line1.contains("stackvalue"));
+ }
+
+}
Propchange: logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadContextTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: logging/log4j/log4j2/trunk/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml?rev=1609903&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml (added)
+++ logging/log4j/log4j2/trunk/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml Sat Jul 12 11:22:51 2014
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="ERROR">
+ <Appenders>
+ <RandomAccessFile name="RandomAccessFile" fileName="target/AsyncLoggerTest.log"
+ immediateFlush="false" append="false">
+ <PatternLayout>
+ <Pattern>%d %p %c{1.} [%t] %X{KEY} %x %location %m %ex%n</Pattern>
+ </PatternLayout>
+ </RandomAccessFile>
+ </Appenders>
+
+ <Loggers>
+ <Root level="info" includeLocation="false">
+ <AppenderRef ref="RandomAccessFile"/>
+ </Root>
+ </Loggers>
+</Configuration>
\ No newline at end of file
Propchange: logging/log4j/log4j2/trunk/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml
------------------------------------------------------------------------------
svn:eol-style = native
Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1609903&r1=1609902&r2=1609903&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Sat Jul 12 11:22:51 2014
@@ -22,6 +22,10 @@
</properties>
<body>
<release version="2.0-???" date="2014-0M-DD" description="Bug fixes and enhancements">
+ <action issue="LOG4J2-705" dev="rpopma" type="fix">
+ Fixed issue where Async Logger does not log thread context stack data.
+ API change: added method getImmutableStackOrNull() to ThreadContext.ContextStack interface.
+ </action>
<action issue="LOG4J2-631" dev="rpopma" type="fix">
Update docs to clarify how to use formatter logger and standard logger together.
</action>