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 2013/05/27 00:11:29 UTC
svn commit: r1486482 - in /logging/log4j/log4j2/trunk:
api/src/main/java/org/apache/logging/log4j/
api/src/main/java/org/apache/logging/log4j/spi/
api/src/test/java/org/apache/logging/log4j/
api/src/test/java/org/apache/logging/log4j/spi/ core/src/main...
Author: rpopma
Date: Sun May 26 22:11:29 2013
New Revision: 1486482
URL: http://svn.apache.org/r1486482
Log:
LOG4J2-154 improve ThreadContext performance with copy-on-write map and stack
Added:
logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextStack.java (with props)
logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/MutableThreadContextStack.java (with props)
logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextStack.java (with props)
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextMapTest.java (with props)
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextStackTest.java (with props)
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/MutableThreadContextStackTest.java (with props)
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/LocationPerfCheck.java (with props)
Modified:
logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/ThreadContext.java
logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java
logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap.java
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/ThreadContextTest.java
logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverter.java
logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverterTest.java
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverterTest.java
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicyTest.java
logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java
Modified: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/ThreadContext.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/ThreadContext.java?rev=1486482&r1=1486481&r2=1486482&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/ThreadContext.java (original)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/ThreadContext.java Sun May 26 22:11:29 2013
@@ -17,26 +17,28 @@
package org.apache.logging.log4j;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.spi.DefaultThreadContextMap;
+import org.apache.logging.log4j.spi.DefaultThreadContextStack;
import org.apache.logging.log4j.spi.LoggerContextFactory;
+import org.apache.logging.log4j.spi.MutableThreadContextStack;
import org.apache.logging.log4j.spi.Provider;
import org.apache.logging.log4j.spi.ThreadContextMap;
+import org.apache.logging.log4j.spi.ThreadContextStack;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.PropertiesUtil;
import org.apache.logging.log4j.util.ProviderUtil;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-
/**
- * The ThreadContext allows applications to store information either in a Map.
+ * The ThreadContext allows applications to store information either in a Map or a Stack.
* <p>
* <b><em>The MDC is managed on a per thread basis</em></b>. A child thread automatically inherits a <em>copy</em> of
* the mapped diagnostic context of its parent.
@@ -47,36 +49,32 @@ public final class ThreadContext {
/**
* Empty, immutable Map.
*/
- public static final Map<String, String> EMPTY_MAP = new ImmutableMap();
+ public static final Map<String, String> EMPTY_MAP = Collections.emptyMap();
/**
* Empty, immutable ContextStack.
*/
- public static final ContextStack EMPTY_STACK = new ImmutableStack();
+ public static final ThreadContextStack EMPTY_STACK = new MutableThreadContextStack(new ArrayList<String>());
private static final String DISABLE_MAP = "disableThreadContextMap";
-
private static final String DISABLE_STACK = "disableThreadContextStack";
-
private static final String DISABLE_ALL = "disableThreadContext";
-
private static final String THREAD_CONTEXT_KEY = "log4j2.threadContextMap";
private static boolean all;
-
private static boolean useMap;
-
private static boolean useStack;
-
private static ThreadContextMap contextMap;
-
+ private static ThreadContextStack contextStack;
private static final Logger LOGGER = StatusLogger.getLogger();
static {
final PropertiesUtil managerProps = PropertiesUtil.getProperties();
all = managerProps.getBooleanProperty(DISABLE_ALL);
- useMap = !(managerProps.getBooleanProperty(DISABLE_MAP) || all);
useStack = !(managerProps.getBooleanProperty(DISABLE_STACK) || all);
+ contextStack = new DefaultThreadContextStack(useStack);
+
+ useMap = !(managerProps.getBooleanProperty(DISABLE_MAP) || all);
String threadContextMapName = managerProps.getStringProperty(THREAD_CONTEXT_KEY);
final ClassLoader cl = ProviderUtil.findClassLoader();
if (threadContextMapName != null) {
@@ -114,23 +112,18 @@ public final class ThreadContext {
}
}
}
- if (contextMap == null) {
- contextMap = new DefaultThreadContextMap(useMap);
- }
-
- } else {
+ }
+ if (contextMap == null) {
contextMap = new DefaultThreadContextMap(useMap);
}
}
- private static ThreadLocal<ContextStack> localStack = new ThreadLocal<ContextStack>();
-
private ThreadContext() {
}
/**
- * Put a context value (the <code>o</code> parameter) as identified
+ * Put a context value (the <code>value</code> parameter) as identified
* with the <code>key</code> parameter into the current thread's
* context map.
* <p/>
@@ -144,7 +137,7 @@ public final class ThreadContext {
}
/**
- * Get the context identified by the <code>key</code> parameter.
+ * Get the context value identified by the <code>key</code> parameter.
* <p/>
* <p>This method has no side effects.
* @param key The key to locate.
@@ -155,8 +148,7 @@ public final class ThreadContext {
}
/**
- * Remove the the context identified by the <code>key</code>
- * parameter.
+ * Remove the context value identified by the <code>key</code> parameter.
* @param key The key to remove.
*/
public static void remove(final String key) {
@@ -180,20 +172,20 @@ public final class ThreadContext {
}
/**
- * Get a copy of current thread's context Map.
- * @return a copy of the context.
+ * Returns a mutable copy of current thread's context Map.
+ * @return a mutable copy of the context.
*/
public static Map<String, String> getContext() {
- return contextMap.getContext();
+ return contextMap.getCopy();
}
/**
- * Get an immutable copy of the current thread's context Map.
- * @return An immutable copy of the ThreadContext Map.
+ * Returns an immutable view of the current thread's context Map.
+ * @return An immutable view of the ThreadContext Map.
*/
public static Map<String, String> getImmutableContext() {
- final Map<String, String> map = contextMap.get();
- return map == null ? new ImmutableMap() : new ImmutableMap(map);
+ final Map<String, String> map = contextMap.getImmutableMapOrNull();
+ return map == null ? EMPTY_MAP : map;
}
/**
@@ -208,7 +200,7 @@ public final class ThreadContext {
* Clear the stack for this thread.
*/
public static void clearStack() {
- localStack.remove();
+ contextStack.clear();
}
/**
@@ -216,8 +208,7 @@ public final class ThreadContext {
* @return A copy of this thread's stack.
*/
public static ContextStack cloneStack() {
- final ContextStack stack = localStack.get();
- return stack == null ? new ThreadContextStack() : new ThreadContextStack(stack.asList());
+ return contextStack.copy();
}
/**
@@ -225,8 +216,7 @@ public final class ThreadContext {
* @return an immutable copy of the ThreadContext stack.
*/
public static ContextStack getImmutableStack() {
- final ContextStack stack = localStack.get();
- return stack == null ? EMPTY_STACK : new ImmutableStack(stack.asList());
+ return contextStack;
}
/**
@@ -237,7 +227,8 @@ public final class ThreadContext {
if (stack.size() == 0 || !useStack) {
return;
}
- localStack.set(new ThreadContextStack(stack));
+ contextStack.clear();
+ contextStack.addAll(stack);
}
/**
@@ -247,8 +238,7 @@ public final class ThreadContext {
* @see #trim
*/
public static int getDepth() {
- final ContextStack stack = localStack.get();
- return stack == null ? 0 : stack.getDepth();
+ return contextStack.getDepth();
}
/**
@@ -260,11 +250,7 @@ public final class ThreadContext {
* @return String The innermost diagnostic context.
*/
public static String pop() {
- final ContextStack s = localStack.get();
- if (s == null || s.getDepth() == 0) {
- return "";
- }
- return s.pop();
+ return contextStack.pop();
}
/**
@@ -277,11 +263,7 @@ public final class ThreadContext {
* @return String The innermost diagnostic context.
*/
public static String peek() {
- final ContextStack s = localStack.get();
- if (s == null || s.getDepth() == 0) {
- return "";
- }
- return s.peek();
+ return contextStack.peek();
}
/**
@@ -293,15 +275,7 @@ public final class ThreadContext {
* @param message The new diagnostic context information.
*/
public static void push(final String message) {
- if (!useStack) {
- return;
- }
- ContextStack stack = localStack.get();
- if (stack == null) {
- stack = new ThreadContextStack();
- localStack.set(stack);
- }
- stack.push(message);
+ contextStack.push(message);
}
/**
* Push new diagnostic context information for the current thread.
@@ -315,15 +289,7 @@ public final class ThreadContext {
* @param args Parameters for the message.
*/
public static void push(final String message, final Object... args) {
- if (!useStack) {
- return;
- }
- ContextStack stack = localStack.get();
- if (stack == null) {
- stack = new ThreadContextStack();
- localStack.set(stack);
- }
- stack.push(ParameterizedMessage.format(message, args));
+ contextStack.push(ParameterizedMessage.format(message, args));
}
/**
@@ -345,7 +311,7 @@ public final class ThreadContext {
* memory.
*/
public static void removeStack() {
- localStack.remove();
+ contextStack.clear();
}
/**
@@ -378,10 +344,7 @@ public final class ThreadContext {
* @param depth The number of elements to keep.
*/
public static void trim(final int depth) {
- final ContextStack stack = localStack.get();
- if (stack != null) {
- stack.trim(depth);
- }
+ contextStack.trim(depth);
}
/**
@@ -433,139 +396,8 @@ public final class ThreadContext {
/**
* Returns a copy of the ContextStack.
- * @return a copy of the ContextStack.
+ * @return a copy of the ContextStack.s
*/
ContextStack copy();
}
-
- /**
- * The ContextStack implementation.
- */
- private static class ThreadContextStack extends ArrayList<String> implements ContextStack {
-
- private static final long serialVersionUID = 5050501L;
-
- public ThreadContextStack() {
- super();
- }
-
- public ThreadContextStack(final Collection<String> collection) {
- super(collection);
- }
-
- @Override
- public String pop() {
- final int index = size() - 1;
- if (index >= 0) {
- final String result = get(index);
- remove(index);
- return result;
- }
- throw new NoSuchElementException("The ThreadContext stack is empty");
- }
-
- @Override
- public String peek() {
- final int index = size() - 1;
- if (index >= 0) {
- return get(index);
- }
- return null;
- }
-
- @Override
- public void push(final String message) {
- add(message);
- }
-
- @Override
- public int getDepth() {
- return size();
- }
-
- @Override
- public List<String> asList() {
- return this;
- }
-
- @Override
- public void trim(final int depth) {
- if (depth < 0) {
- throw new IllegalArgumentException("Maximum stack depth cannot be negative");
- }
- while (size() > depth) {
- remove(size() - 1);
- }
-
- }
-
- @Override
- public ContextStack copy() {
- return new ThreadContextStack(this);
- }
- }
-
- /**
- * An immutable ContextStack.
- */
- public static class ImmutableStack extends ThreadContextStack {
-
- private static final long serialVersionUID = 5050502L;
-
- public ImmutableStack() {
- }
-
- public ImmutableStack(final Collection<String> collection) {
- super(collection);
- }
-
- public ImmutableStack(final ThreadContextStack stack) {
- super(stack);
- }
-
- @Override
- public void push(final String message) {
- throw new UnsupportedOperationException("Stack cannot be modified");
- }
-
- @Override
- public void trim(final int depth) {
- throw new UnsupportedOperationException("Stack cannot be modified");
- }
- }
-
- /**
- * An immutable Context Map.
- */
- public static class ImmutableMap extends HashMap<String, String> {
- private static final long serialVersionUID = 5050503L;
-
- public ImmutableMap() {
- super();
- }
-
- public ImmutableMap(final Map<String, String> map) {
- super(map);
- }
-
- @Override
- public String put(final String s, final String s1) {
- throw new UnsupportedOperationException("Map cannot be modified");
- }
-
- @Override
- public void putAll(final Map<? extends String, ? extends String> map) {
- throw new UnsupportedOperationException("Map cannot be modified");
- }
-
- @Override
- public String remove(final Object o) {
- throw new UnsupportedOperationException("Map cannot be modified");
- }
-
- @Override
- public void clear() {
- throw new UnsupportedOperationException("Map cannot be modified");
- }
- }
}
Modified: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java?rev=1486482&r1=1486481&r2=1486482&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java (original)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java Sun May 26 22:11:29 2013
@@ -16,11 +16,15 @@
*/
package org.apache.logging.log4j.spi;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
- *
+ * The actual ThreadContext Map. A new ThreadContext Map is created each time it is updated and the Map stored
+ * is always immutable. This means the Map can be passed to other threads without concern that it will be updated.
+ * Since it is expected that the Map will be passed to many more log events than the number of keys it contains
+ * the performance should be much better than if the Map was copied for each event.
*/
public class DefaultThreadContextMap implements ThreadContextMap {
@@ -30,7 +34,8 @@ public class DefaultThreadContextMap imp
new InheritableThreadLocal<Map<String, String>>() {
@Override
protected Map<String, String> childValue(final Map<String, String> parentValue) {
- return parentValue == null || !useMap ? null : new HashMap<String, String>(parentValue);
+ return parentValue == null || !useMap ? null :
+ Collections.unmodifiableMap(new HashMap<String, String>(parentValue));
}
};
@@ -54,11 +59,9 @@ public class DefaultThreadContextMap imp
return;
}
Map<String, String> map = localMap.get();
- if (map == null) {
- map = new HashMap<String, String>();
- localMap.set(map);
- }
+ map = map == null ? new HashMap<String, String>() : new HashMap<String, String>(map);
map.put(key, value);
+ localMap.set(Collections.unmodifiableMap(map));
}
/**
@@ -83,7 +86,9 @@ public class DefaultThreadContextMap imp
public void remove(final String key) {
final Map<String, String> map = localMap.get();
if (map != null) {
- map.remove(key);
+ final Map<String, String> copy = new HashMap<String, String>(map);
+ copy.remove(key);
+ localMap.set(Collections.unmodifiableMap(copy));
}
}
@@ -103,25 +108,25 @@ public class DefaultThreadContextMap imp
@Override
public boolean containsKey(final String key) {
final Map<String, String> map = localMap.get();
- return map == null ? false : map.containsKey(key);
+ return map != null && map.containsKey(key);
}
/**
- * Get a copy of current thread's context Map.
- * @return a copy of the context.
+ * Returns a non-{@code null} mutable copy of the ThreadContext Map.
+ * @return a non-{@code null} mutable copy of the context.
*/
@Override
- public Map<String, String> getContext() {
+ public Map<String, String> getCopy() {
final Map<String, String> map = localMap.get();
return map == null ? new HashMap<String, String>() : new HashMap<String, String>(map);
}
/**
- * Return the context Map.
+ * Returns either {@code null} or an immutable view of the context Map.
* @return the Context Map.
*/
@Override
- public Map<String, String> get() {
+ public Map<String, String> getImmutableMapOrNull() {
return localMap.get();
}
Added: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextStack.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextStack.java?rev=1486482&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextStack.java (added)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextStack.java Sun May 26 22:11:29 2013
@@ -0,0 +1,233 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.spi;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * A copy-on-write thread-safe variant of
+ * {@code org.apache.logging.log4j.spi.ThreadContextStack} in which all mutative
+ * operations (add, pop, and so on) are implemented by making a fresh copy of
+ * the underlying list.
+ */
+public class DefaultThreadContextStack implements ThreadContextStack {
+
+ private static final long serialVersionUID = 5050501L;
+
+ private final boolean useStack;
+ private static ThreadLocal<List<String>> stack = new ThreadLocal<List<String>>();
+
+ public DefaultThreadContextStack(boolean useStack) {
+ this.useStack = useStack;
+ }
+
+ public String pop() {
+ if (!useStack) {
+ return "";
+ }
+ final List<String> list = stack.get();
+ if (list == null || list.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));
+ return result;
+ }
+
+ public String peek() {
+ final List<String> list = stack.get();
+ if (list == null || list.size() == 0) {
+ return null;
+ }
+ final int last = list.size() - 1;
+ return list.get(last);
+ }
+
+ public void push(final String message) {
+ if (!useStack) {
+ return;
+ }
+ add(message);
+ }
+
+ public int getDepth() {
+ final List<String> list = stack.get();
+ return list == null ? 0 : list.size();
+ }
+
+ public List<String> asList() {
+ final List<String> list = stack.get();
+ if (list == null) {
+ return Collections.emptyList();
+ }
+ return list;
+ }
+
+ public void trim(final int depth) {
+ if (depth < 0) {
+ throw new IllegalArgumentException(
+ "Maximum stack depth cannot be negative");
+ }
+ final List<String> list = stack.get();
+ if (list == null) {
+ return;
+ }
+ final List<String> copy = new ArrayList<String>();
+ int count = Math.min(depth, list.size());
+ for(int i = 0; i < count; i++) {
+ copy.add(list.get(i));
+ }
+ stack.set(copy);
+ }
+
+ public ThreadContextStack copy() {
+ List<String> result = null;
+ if (!useStack || (result = stack.get()) == null) {
+ return new MutableThreadContextStack(new ArrayList<String>());
+ }
+ return new MutableThreadContextStack(result);
+ }
+
+ public void clear() {
+ stack.remove();
+ }
+
+ public int size() {
+ final List<String> result = stack.get();
+ return result == null ? 0 : result.size();
+ }
+
+ public boolean isEmpty() {
+ final List<String> result = stack.get();
+ return result == null || result.isEmpty();
+ }
+
+ public boolean contains(Object o) {
+ final List<String> result = stack.get();
+ return result != null && result.contains(o);
+ }
+
+ public Iterator<String> iterator() {
+ final List<String> immutable = stack.get();
+ if (immutable == null) {
+ final List<String> empty = Collections.emptyList();
+ return empty.iterator();
+ }
+ return immutable.iterator();
+ }
+
+ public Object[] toArray() {
+ final List<String> result = stack.get();
+ if (result == null) {
+ return new String[0];
+ }
+ return result.toArray(new Object[result.size()]);
+ }
+
+ public <T> T[] toArray(T[] ts) {
+ List<String> result = stack.get();
+ if (result == null) {
+ if (ts.length > 0) { // as per the contract of j.u.List#toArray(T[])
+ ts[0] = null;
+ }
+ return ts;
+ }
+ return result.toArray(ts);
+ }
+
+ public boolean add(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);
+ copy.add(s);
+ stack.set(Collections.unmodifiableList(copy));
+ return true;
+ }
+
+ public boolean remove(Object o) {
+ if (!useStack) {
+ return false;
+ }
+ final List<String> list = stack.get();
+ if (list == null || list.size() == 0) {
+ return false;
+ }
+ final List<String> copy = new ArrayList<String>(list);
+ final boolean result = copy.remove(o);
+ stack.set(Collections.unmodifiableList(copy));
+ return result;
+ }
+
+ public boolean containsAll(Collection<?> objects) {
+ if (objects.isEmpty()) { // quick check before accessing the ThreadLocal
+ return true; // looks counter-intuitive, but see
+ // j.u.AbstractCollection
+ }
+ final List<String> list = stack.get();
+ return list != null && list.containsAll(objects);
+ }
+
+ public boolean addAll(Collection<? extends String> strings) {
+ 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);
+ copy.addAll(strings);
+ stack.set(Collections.unmodifiableList(copy));
+ return true;
+ }
+
+ public boolean removeAll(Collection<?> objects) {
+ if (!useStack || objects.isEmpty()) {
+ return false;
+ }
+ final List<String> list = stack.get();
+ if (list == null || list.isEmpty()) {
+ return false;
+ }
+ final List<String> copy = new ArrayList<String>(list);
+ boolean result = copy.removeAll(objects);
+ stack.set(Collections.unmodifiableList(copy));
+ return result;
+ }
+
+ public boolean retainAll(Collection<?> objects) {
+ if (!useStack || objects.isEmpty()) {
+ return false;
+ }
+ final List<String> list = stack.get();
+ if (list == null || list.isEmpty()) {
+ return false;
+ }
+ final List<String> copy = new ArrayList<String>(list);
+ final boolean result = copy.retainAll(objects);
+ stack.set(Collections.unmodifiableList(copy));
+ return result;
+ }
+}
Propchange: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextStack.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/MutableThreadContextStack.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/MutableThreadContextStack.java?rev=1486482&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/MutableThreadContextStack.java (added)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/MutableThreadContextStack.java Sun May 26 22:11:29 2013
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.spi;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ *
+ */
+public class MutableThreadContextStack implements ThreadContextStack {
+
+ private static final long serialVersionUID = 50505011L;
+
+ /**
+ * The underlying list (never null).
+ */
+ private final List<String> list;
+
+ public MutableThreadContextStack(List<String> list) {
+ this.list = new ArrayList<String>(list);
+ }
+
+ private MutableThreadContextStack(MutableThreadContextStack stack) {
+ this.list = new ArrayList<String>(stack.list);
+ }
+
+ public String pop() {
+ if (list.isEmpty()) {
+ return null;
+ }
+ final int last = list.size() - 1;
+ final String result = list.remove(last);
+ return result;
+ }
+
+ public String peek() {
+ if (list.isEmpty()) {
+ return null;
+ }
+ final int last = list.size() - 1;
+ return list.get(last);
+ }
+
+ public void push(final String message) {
+ list.add(message);
+ }
+
+ public int getDepth() {
+ return list.size();
+ }
+
+ public List<String> asList() {
+ return list;
+ }
+
+ public void trim(final int depth) {
+ if (depth < 0) {
+ throw new IllegalArgumentException("Maximum stack depth cannot be negative");
+ }
+ if (list == null) {
+ return;
+ }
+ final List<String> copy = new ArrayList<String>(list.size());
+ int count = Math.min(depth, list.size());
+ for(int i = 0; i < count; i++) {
+ copy.add(list.get(i));
+ }
+ list.clear();
+ list.addAll(copy);
+ }
+
+ public ThreadContextStack copy() {
+ return new MutableThreadContextStack(this);
+ }
+
+ public void clear() {
+ list.clear();
+ }
+
+ public int size() {
+ return list.size();
+ }
+
+ public boolean isEmpty() {
+ return list.isEmpty();
+ }
+
+ public boolean contains(Object o) {
+ return list.contains(o);
+ }
+
+ public Iterator<String> iterator() {
+ return list.iterator();
+ }
+
+ public Object[] toArray() {
+ return list.toArray();
+ }
+
+ public <T> T[] toArray(T[] ts) {
+ return list.toArray(ts);
+ }
+
+ public boolean add(String s) {
+ return list.add(s);
+ }
+
+ public boolean remove(Object o) {
+ return list.remove(o);
+ }
+
+ public boolean containsAll(Collection<?> objects) {
+ return list.containsAll(objects);
+ }
+
+ public boolean addAll(Collection<? extends String> strings) {
+ return list.addAll(strings);
+ }
+
+ public boolean removeAll(Collection<?> objects) {
+ return list.removeAll(objects);
+ }
+
+ public boolean retainAll(Collection<?> objects) {
+ return list.retainAll(objects);
+ }
+}
Propchange: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/MutableThreadContextStack.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap.java?rev=1486482&r1=1486481&r2=1486482&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap.java (original)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap.java Sun May 26 22:11:29 2013
@@ -63,16 +63,16 @@ public interface ThreadContextMap {
boolean containsKey(final String key);
/**
- * Get a copy of current thread's context Map.
- * @return a copy of the context.
+ * Get a non-{@code null} mutable copy of current thread's context Map.
+ * @return a mutable copy of the context.
*/
- Map<String, String> getContext();
+ Map<String, String> getCopy();
/**
- * Return the actual context Map.
- * @return the actual context Map.
+ * Return an immutable view on the context Map or {@code null} if the context map is empty.
+ * @return an immutable context Map or {@code null}.
*/
- Map<String, String> get();
+ Map<String, String> getImmutableMapOrNull();
/**
* Returns true if the Map is empty.
Added: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextStack.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextStack.java?rev=1486482&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextStack.java (added)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextStack.java Sun May 26 22:11:29 2013
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.spi;
+
+import org.apache.logging.log4j.ThreadContext;
+
+import java.io.Serializable;
+import java.util.Collection;
+
+/**
+ *
+ */
+public interface ThreadContextStack extends ThreadContext.ContextStack,
+ Collection<String>, Serializable {
+}
Propchange: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextStack.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/ThreadContextTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/ThreadContextTest.java?rev=1486482&r1=1486481&r2=1486482&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/ThreadContextTest.java (original)
+++ logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/ThreadContextTest.java Sun May 26 22:11:29 2013
@@ -18,8 +18,9 @@ package org.apache.logging.log4j;
import org.junit.Test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import java.util.Map;
+
+import static org.junit.Assert.*;
/**
*
@@ -29,9 +30,12 @@ public class ThreadContextTest {
@Test
public void testPush() {
ThreadContext.push("Hello");
- ThreadContext.push("{} is {}", ThreadContextTest.class.getSimpleName(), "running");
- assertEquals("Incorrect parameterized stack value", ThreadContext.pop(), "ThreadContextTest is running");
- assertEquals("Incorrect simple stack value", ThreadContext.pop(), "Hello");
+ ThreadContext.push("{} is {}", ThreadContextTest.class.getSimpleName(),
+ "running");
+ assertEquals("Incorrect parameterized stack value",
+ ThreadContext.pop(), "ThreadContextTest is running");
+ assertEquals("Incorrect simple stack value", ThreadContext.pop(),
+ "Hello");
}
@Test
@@ -43,15 +47,131 @@ public class ThreadContextTest {
thread.start();
thread.join();
String str = sb.toString();
- assertTrue("Unexpected ThreadContext value. Expected Hello. Actual " + str, "Hello".equals(str));
+ assertTrue("Unexpected ThreadContext value. Expected Hello. Actual "
+ + str, "Hello".equals(str));
sb = new StringBuilder();
thread = new TestThread(sb);
thread.start();
thread.join();
str = sb.toString();
- assertTrue("Unexpected ThreadContext value. Expected Hello. Actual " + str, "Hello".equals(str));
+ assertTrue("Unexpected ThreadContext value. Expected Hello. Actual "
+ + str, "Hello".equals(str));
+ }
+
+ @Test
+ public void perfTest() throws Exception {
+ ThreadContext.clear();
+ Timer complete = new Timer("ThreadContextTest");
+ complete.start();
+ ThreadContext.put("Var1", "value 1");
+ ThreadContext.put("Var2", "value 2");
+ ThreadContext.put("Var3", "value 3");
+ ThreadContext.put("Var4", "value 4");
+ ThreadContext.put("Var5", "value 5");
+ ThreadContext.put("Var6", "value 6");
+ ThreadContext.put("Var7", "value 7");
+ ThreadContext.put("Var8", "value 8");
+ ThreadContext.put("Var9", "value 9");
+ ThreadContext.put("Var10", "value 10");
+ final int loopCount = 1000000;
+ Timer timer = new Timer("ThreadContextCopy", loopCount);
+ timer.start();
+ for (int i = 0; i < loopCount; ++i) {
+ Map<String, String> map = ThreadContext.getImmutableContext();
+ assertNotNull(map);
+ }
+ timer.stop();
+ complete.stop();
+ System.out.println(timer.toString());
+ System.out.println(complete.toString());
+ }
+
+ @Test
+ public void testGetContextReturnsEmptyMapIfEmpty() {
+ ThreadContext.clear();
+ assertTrue(ThreadContext.getContext().isEmpty());
+ }
+
+ @Test
+ public void testGetContextReturnsMutableCopy() {
+ ThreadContext.clear();
+ Map<String, String> map1 = ThreadContext.getContext();
+ assertTrue(map1.isEmpty());
+ map1.put("K", "val"); // no error
+ assertEquals("val", map1.get("K"));
+
+ // adding to copy does not affect thread context map
+ assertTrue(ThreadContext.getContext().isEmpty());
+
+ ThreadContext.put("key", "val2");
+ Map<String, String> map2 = ThreadContext.getContext();
+ assertEquals(1, map2.size());
+ assertEquals("val2", map2.get("key"));
+ map2.put("K", "val"); // no error
+ assertEquals("val", map2.get("K"));
+
+ // first copy is not affected
+ assertNotSame(map1, map2);
+ assertEquals(1, map1.size());
+ }
+
+ @Test
+ public void testGetImmutableContextReturnsEmptyMapIfEmpty() {
+ ThreadContext.clear();
+ assertTrue(ThreadContext.getImmutableContext().isEmpty());
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testGetImmutableContextReturnsImmutableMapIfNonEmpty() {
+ ThreadContext.clear();
+ ThreadContext.put("key", "val");
+ Map<String, String> immutable = ThreadContext.getImmutableContext();
+ immutable.put("otherkey", "otherval");
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testGetImmutableContextReturnsImmutableMapIfEmpty() {
+ ThreadContext.clear();
+ Map<String, String> immutable = ThreadContext.getImmutableContext();
+ immutable.put("otherkey", "otherval");
}
+ @Test
+ public void testGetImmutableStackReturnsEmptyStackIfEmpty() {
+ ThreadContext.clearStack();
+ assertTrue(ThreadContext.getImmutableStack().asList().isEmpty());
+ }
+
+ @Test
+ public void testPut() {
+ ThreadContext.clear();
+ assertNull(ThreadContext.get("testKey"));
+ ThreadContext.put("testKey", "testValue");
+ assertEquals("testValue", ThreadContext.get("testKey"));
+ }
+
+ @Test
+ public void testRemove() {
+ ThreadContext.clear();
+ assertNull(ThreadContext.get("testKey"));
+ ThreadContext.put("testKey", "testValue");
+ assertEquals("testValue", ThreadContext.get("testKey"));
+
+ ThreadContext.remove("testKey");
+ assertNull(ThreadContext.get("testKey"));
+ assertTrue(ThreadContext.isEmpty());
+ }
+
+ @Test
+ public void testContainsKey() {
+ ThreadContext.clear();
+ assertFalse(ThreadContext.containsKey("testKey"));
+ ThreadContext.put("testKey", "testValue");
+ assertTrue(ThreadContext.containsKey("testKey"));
+
+ ThreadContext.remove("testKey");
+ assertFalse(ThreadContext.containsKey("testKey"));
+ }
private class TestThread extends Thread {
Added: logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextMapTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextMapTest.java?rev=1486482&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextMapTest.java (added)
+++ logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextMapTest.java Sun May 26 22:11:29 2013
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.spi;
+
+import static org.junit.Assert.*;
+
+import java.util.Map;
+
+import org.junit.Test;
+
+/**
+ * Tests the {@code DefaultThreadContextMap} class.
+ */
+public class DefaultThreadContextMapTest {
+
+ @Test
+ public void testDoesNothingIfConstructedWithUseMapIsFalse() {
+ DefaultThreadContextMap map = new DefaultThreadContextMap(false);
+ assertTrue(map.isEmpty());
+ assertFalse(map.containsKey("key"));
+ map.put("key", "value");
+
+ assertTrue(map.isEmpty());
+ assertFalse(map.containsKey("key"));
+ assertNull(map.get("key"));
+ }
+
+ @Test
+ public void testPut() {
+ DefaultThreadContextMap map = new DefaultThreadContextMap(true);
+ assertTrue(map.isEmpty());
+ assertFalse(map.containsKey("key"));
+ map.put("key", "value");
+
+ assertFalse(map.isEmpty());
+ assertTrue(map.containsKey("key"));
+ assertEquals("value", map.get("key"));
+ }
+
+ /**
+ * Test method for
+ * {@link org.apache.logging.log4j.spi.DefaultThreadContextMap#remove(java.lang.String)}
+ * .
+ */
+ @Test
+ public void testRemove() {
+ DefaultThreadContextMap map = new DefaultThreadContextMap(true);
+ assertTrue(map.isEmpty());
+ map.put("key", "value");
+ map.put("key2", "value2");
+ assertEquals("value", map.get("key"));
+ assertEquals("value2", map.get("key2"));
+
+ map.remove("key");
+ assertFalse(map.containsKey("key"));
+ assertEquals("value2", map.get("key2"));
+ }
+
+ @Test
+ public void testClear() {
+ DefaultThreadContextMap map = new DefaultThreadContextMap(true);
+ assertTrue(map.isEmpty());
+ map.put("key", "value");
+ map.put("key2", "value2");
+ assertEquals("value", map.get("key"));
+ assertEquals("value2", map.get("key2"));
+
+ map.clear();
+ assertTrue(map.isEmpty());
+ assertFalse(map.containsKey("key"));
+ assertFalse(map.containsKey("key2"));
+ }
+
+ @Test
+ public void testGetCopyReturnsMutableMap() {
+ DefaultThreadContextMap map = new DefaultThreadContextMap(true);
+ assertTrue(map.isEmpty());
+ Map<String, String> copy = map.getCopy();
+ assertTrue(copy.isEmpty());
+
+ copy.put("key", "value"); // mutable
+ assertEquals("value", copy.get("key"));
+
+ // thread context map not affected
+ assertTrue(map.isEmpty());
+ }
+
+ @Test
+ public void testGetCopyReturnsMutableCopy() {
+ DefaultThreadContextMap map = new DefaultThreadContextMap(true);
+ map.put("key1", "value1");
+ assertFalse(map.isEmpty());
+ Map<String, String> copy = map.getCopy();
+ assertEquals("value1", copy.get("key1")); // copy has values too
+
+ copy.put("key", "value"); // copy is mutable
+ assertEquals("value", copy.get("key"));
+
+ // thread context map not affected
+ assertFalse(map.containsKey("key"));
+
+ // clearing context map does not affect copy
+ map.clear();
+ assertTrue(map.isEmpty());
+
+ assertFalse(copy.isEmpty());
+ }
+
+ @Test
+ public void testGetImmutableMapReturnsNullIfEmpty() {
+ DefaultThreadContextMap map = new DefaultThreadContextMap(true);
+ assertTrue(map.isEmpty());
+ assertNull(map.getImmutableMapOrNull());
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testGetImmutableMapReturnsImmutableMapIfNonEmpty() {
+ DefaultThreadContextMap map = new DefaultThreadContextMap(true);
+ map.put("key1", "value1");
+ assertFalse(map.isEmpty());
+
+ Map<String, String> immutable = map.getImmutableMapOrNull();
+ assertEquals("value1", immutable.get("key1")); // copy has values too
+
+ // immutable
+ immutable.put("key", "value"); // error
+ }
+
+ @Test
+ public void testGetImmutableMapCopyNotAffectdByContextMapChanges() {
+ DefaultThreadContextMap map = new DefaultThreadContextMap(true);
+ map.put("key1", "value1");
+ assertFalse(map.isEmpty());
+
+ Map<String, String> immutable = map.getImmutableMapOrNull();
+ assertEquals("value1", immutable.get("key1")); // copy has values too
+
+ // clearing context map does not affect copy
+ map.clear();
+ assertTrue(map.isEmpty());
+
+ assertFalse(immutable.isEmpty());
+ }
+}
Propchange: logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextMapTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextStackTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextStackTest.java?rev=1486482&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextStackTest.java (added)
+++ logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextStackTest.java Sun May 26 22:11:29 2013
@@ -0,0 +1,304 @@
+package org.apache.logging.log4j.spi;
+
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.junit.Test;
+
+public class DefaultThreadContextStackTest {
+
+ @Test
+ public void testDoesNothingIfConstructedWithUseStackIsFalse() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(false);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg");
+
+ // nothing was added
+ assertTrue(stack.isEmpty());
+ assertEquals(0, stack.size());
+ }
+
+ @Test
+ public void testPushAndAddIncreaseStack() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+
+ assertEquals(2, stack.size());
+ }
+
+ @Test
+ public void testPeekReturnsLastAddedItem() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+
+ assertEquals(2, stack.size());
+ assertEquals("msg2", stack.peek());
+
+ stack.push("msg3");
+ assertEquals("msg3", stack.peek());
+ }
+
+ @Test
+ public void testPopRemovesLastAddedItem() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+ assertEquals(3, stack.getDepth());
+
+ assertEquals("msg3", stack.pop());
+ assertEquals(2, stack.size());
+ assertEquals(2, stack.getDepth());
+
+ assertEquals("msg2", stack.pop());
+ assertEquals(1, stack.size());
+ assertEquals(1, stack.getDepth());
+
+ assertEquals("msg1", stack.pop());
+ assertEquals(0, stack.size());
+ assertEquals(0, stack.getDepth());
+ }
+
+ @Test
+ public void testAsList() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+
+ assertEquals(Arrays.asList("msg1", "msg2", "msg3"), stack.asList());
+ }
+
+ @Test
+ public void testTrim() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ stack.trim(1);
+ assertEquals(1, stack.size());
+ assertEquals("msg1", stack.peek());
+ }
+
+ @Test
+ public void testCopy() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ ThreadContextStack copy = stack.copy();
+ assertEquals(3, copy.size());
+ assertTrue(copy.containsAll(Arrays.asList("msg1", "msg2", "msg3")));
+
+ // clearing stack does not affect copy
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ assertEquals(3, copy.size()); // not affected
+ assertTrue(copy.containsAll(Arrays.asList("msg1", "msg2", "msg3")));
+
+ // adding to copy does not affect stack
+ copy.add("other");
+ assertEquals(4, copy.size()); // not affected
+ assertTrue(stack.isEmpty());
+
+ // adding to stack does not affect copy
+ stack.push("newStackMsg");
+ assertEquals(1, stack.size());
+ assertEquals(4, copy.size()); // not affected
+
+ // clearing copy does not affect stack
+ copy.clear();
+ assertTrue(copy.isEmpty());
+ assertEquals(1, stack.size());
+ }
+
+ @Test
+ public void testClear() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ }
+
+ @Test
+ public void testContains() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ assertTrue(stack.contains("msg1"));
+ assertTrue(stack.contains("msg2"));
+ assertTrue(stack.contains("msg3"));
+ }
+
+ @Test
+ public void testIteratorReturnsInListOrderNotStackOrder() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ Iterator<String> iter = stack.iterator();
+ assertTrue(iter.hasNext());
+ assertEquals("msg1", iter.next());
+ assertTrue(iter.hasNext());
+ assertEquals("msg2", iter.next());
+ assertTrue(iter.hasNext());
+ assertEquals("msg3", iter.next());
+ assertFalse(iter.hasNext());
+ }
+
+ @Test
+ public void testToArray() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ String[] expecteds = {"msg1", "msg2", "msg3"};
+ assertArrayEquals(expecteds, stack.toArray());
+ }
+
+ @Test
+ public void testToArrayTArray() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ String[] expecteds = {"msg1", "msg2", "msg3"};
+ String[] result = new String[3] ;
+ assertArrayEquals(expecteds, stack.toArray(result));
+ assertSame(result, stack.toArray(result));
+ }
+
+ @Test
+ public void testRemove() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+ assertTrue(stack.containsAll(Arrays.asList("msg1", "msg2", "msg3")));
+
+ stack.remove("msg1");
+ assertEquals(2, stack.size());
+ assertTrue(stack.containsAll(Arrays.asList("msg2", "msg3")));
+ assertEquals("msg3", stack.peek());
+
+ stack.remove("msg3");
+ assertEquals(1, stack.size());
+ assertTrue(stack.containsAll(Arrays.asList("msg2")));
+ assertEquals("msg2", stack.peek());
+ }
+
+ @Test
+ public void testContainsAll() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ assertTrue(stack.containsAll(Arrays.asList("msg1", "msg2", "msg3")));
+ }
+
+ @Test
+ public void testAddAll() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ stack.addAll(Arrays.asList("msg4", "msg5"));
+ assertEquals(5, stack.size());
+ assertTrue(stack.contains("msg1"));
+ assertTrue(stack.contains("msg2"));
+ assertTrue(stack.contains("msg3"));
+ assertTrue(stack.contains("msg4"));
+ assertTrue(stack.contains("msg5"));
+ }
+
+ @Test
+ public void testRemoveAll() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ stack.removeAll(Arrays.asList("msg1", "msg3"));
+ assertEquals(1, stack.size());
+ assertFalse(stack.contains("msg1"));
+ assertTrue(stack.contains("msg2"));
+ assertFalse(stack.contains("msg3"));
+ }
+
+ @Test
+ public void testRetainAll() {
+ DefaultThreadContextStack stack = new DefaultThreadContextStack(true);
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ stack.retainAll(Arrays.asList("msg1", "msg3"));
+ assertEquals(2, stack.size());
+ assertTrue(stack.contains("msg1"));
+ assertFalse(stack.contains("msg2"));
+ assertTrue(stack.contains("msg3"));
+ }
+
+}
Propchange: logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/DefaultThreadContextStackTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/MutableThreadContextStackTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/MutableThreadContextStackTest.java?rev=1486482&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/MutableThreadContextStackTest.java (added)
+++ logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/MutableThreadContextStackTest.java Sun May 26 22:11:29 2013
@@ -0,0 +1,323 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.spi;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.Test;
+
+public class MutableThreadContextStackTest {
+
+ @Test
+ public void testEmptyIfConstructedWithEmptyList() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ assertTrue(stack.isEmpty());
+ }
+
+ @Test
+ public void testConstructorCopiesListContents() {
+ List<String> initial = Arrays.asList("a", "b", "c");
+ MutableThreadContextStack stack = new MutableThreadContextStack(initial);
+ assertFalse(stack.isEmpty());
+ assertTrue(stack.containsAll(initial));
+ }
+
+ @Test
+ public void testPushAndAddIncreaseStack() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+
+ assertEquals(2, stack.size());
+ }
+
+ @Test
+ public void testPeekReturnsLastAddedItem() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+
+ assertEquals(2, stack.size());
+ assertEquals("msg2", stack.peek());
+
+ stack.push("msg3");
+ assertEquals("msg3", stack.peek());
+ }
+
+ @Test
+ public void testPopRemovesLastAddedItem() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+ assertEquals(3, stack.getDepth());
+
+ assertEquals("msg3", stack.pop());
+ assertEquals(2, stack.size());
+ assertEquals(2, stack.getDepth());
+
+ assertEquals("msg2", stack.pop());
+ assertEquals(1, stack.size());
+ assertEquals(1, stack.getDepth());
+
+ assertEquals("msg1", stack.pop());
+ assertEquals(0, stack.size());
+ assertEquals(0, stack.getDepth());
+ }
+
+ @Test
+ public void testAsList() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+
+ assertEquals(Arrays.asList("msg1", "msg2", "msg3"), stack.asList());
+ }
+
+ @Test
+ public void testTrim() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ stack.trim(1);
+ assertEquals(1, stack.size());
+ assertEquals("msg1", stack.peek());
+ }
+
+ @Test
+ public void testCopy() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ ThreadContextStack copy = stack.copy();
+ assertEquals(3, copy.size());
+ assertTrue(copy.containsAll(Arrays.asList("msg1", "msg2", "msg3")));
+
+ // clearing stack does not affect copy
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ assertEquals(3, copy.size()); // not affected
+ assertTrue(copy.containsAll(Arrays.asList("msg1", "msg2", "msg3")));
+
+ // adding to copy does not affect stack
+ copy.add("other");
+ assertEquals(4, copy.size()); // not affected
+ assertTrue(stack.isEmpty());
+
+ // adding to stack does not affect copy
+ stack.push("newStackMsg");
+ assertEquals(1, stack.size());
+ assertEquals(4, copy.size()); // not affected
+
+ // clearing copy does not affect stack
+ copy.clear();
+ assertTrue(copy.isEmpty());
+ assertEquals(1, stack.size());
+ }
+
+ @Test
+ public void testClear() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ }
+
+ @Test
+ public void testContains() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ assertTrue(stack.contains("msg1"));
+ assertTrue(stack.contains("msg2"));
+ assertTrue(stack.contains("msg3"));
+ }
+
+ @Test
+ public void testIteratorReturnsInListOrderNotStackOrder() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ Iterator<String> iter = stack.iterator();
+ assertTrue(iter.hasNext());
+ assertEquals("msg1", iter.next());
+ assertTrue(iter.hasNext());
+ assertEquals("msg2", iter.next());
+ assertTrue(iter.hasNext());
+ assertEquals("msg3", iter.next());
+ assertFalse(iter.hasNext());
+ }
+
+ @Test
+ public void testToArray() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ String[] expecteds = {"msg1", "msg2", "msg3"};
+ assertArrayEquals(expecteds, stack.toArray());
+ }
+
+ @Test
+ public void testToArrayTArray() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ String[] expecteds = {"msg1", "msg2", "msg3"};
+ String[] result = new String[3] ;
+ assertArrayEquals(expecteds, stack.toArray(result));
+ assertSame(result, stack.toArray(result));
+ }
+
+ @Test
+ public void testRemove() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+ assertTrue(stack.containsAll(Arrays.asList("msg1", "msg2", "msg3")));
+
+ stack.remove("msg1");
+ assertEquals(2, stack.size());
+ assertTrue(stack.containsAll(Arrays.asList("msg2", "msg3")));
+ assertEquals("msg3", stack.peek());
+
+ stack.remove("msg3");
+ assertEquals(1, stack.size());
+ assertTrue(stack.containsAll(Arrays.asList("msg2")));
+ assertEquals("msg2", stack.peek());
+ }
+
+ @Test
+ public void testContainsAll() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ assertTrue(stack.containsAll(Arrays.asList("msg1", "msg2", "msg3")));
+ }
+
+ @Test
+ public void testAddAll() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ stack.addAll(Arrays.asList("msg4", "msg5"));
+ assertEquals(5, stack.size());
+ assertTrue(stack.contains("msg1"));
+ assertTrue(stack.contains("msg2"));
+ assertTrue(stack.contains("msg3"));
+ assertTrue(stack.contains("msg4"));
+ assertTrue(stack.contains("msg5"));
+ }
+
+ @Test
+ public void testRemoveAll() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ stack.removeAll(Arrays.asList("msg1", "msg3"));
+ assertEquals(1, stack.size());
+ assertFalse(stack.contains("msg1"));
+ assertTrue(stack.contains("msg2"));
+ assertFalse(stack.contains("msg3"));
+ }
+
+ @Test
+ public void testRetainAll() {
+ MutableThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ stack.push("msg1");
+ stack.add("msg2");
+ stack.push("msg3");
+ assertEquals(3, stack.size());
+
+ stack.retainAll(Arrays.asList("msg1", "msg3"));
+ assertEquals(2, stack.size());
+ assertTrue(stack.contains("msg1"));
+ assertFalse(stack.contains("msg2"));
+ assertTrue(stack.contains("msg3"));
+ }
+}
Propchange: logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/spi/MutableThreadContextStackTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverter.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverter.java?rev=1486482&r1=1486481&r2=1486482&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverter.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverter.java Sun May 26 22:11:29 2013
@@ -18,10 +18,12 @@ package org.apache.logging.log4j.core.ap
import java.io.IOException;
import java.util.List;
+
import javax.persistence.AttributeConverter;
import javax.persistence.PersistenceException;
import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.spi.DefaultThreadContextStack;
import com.fasterxml.jackson.core.type.TypeReference;
@@ -56,6 +58,8 @@ public class ContextStackJsonAttributeCo
throw new PersistenceException("Failed to convert JSON string to list for stack.", e);
}
- return new ThreadContext.ImmutableStack(list);
+ DefaultThreadContextStack result = new DefaultThreadContextStack(true);
+ result.addAll(list);
+ return result;
}
}
Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java?rev=1486482&r1=1486481&r2=1486482&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java Sun May 26 22:11:29 2013
@@ -28,6 +28,8 @@ import org.apache.logging.log4j.message.
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -119,20 +121,21 @@ public class Log4jLogEvent implements Lo
}
private static Map<String, String> createMap(final List<Property> properties) {
- if (ThreadContext.isEmpty() && (properties == null || properties.size() == 0)) {
+ final Map<String, String> contextMap = ThreadContext.getImmutableContext();
+ if (contextMap == null && (properties == null || properties.size() == 0)) {
return null;
}
if (properties == null || properties.size() == 0) {
- return ThreadContext.getImmutableContext();
+ return contextMap; // contextMap is not null
}
- final Map<String, String> map = ThreadContext.getContext();
+ final Map<String, String> map = new HashMap<String, String>(contextMap);
for (final Property prop : properties) {
if (!map.containsKey(prop.getName())) {
map.put(prop.getName(), prop.getValue());
}
}
- return new ThreadContext.ImmutableMap(map);
+ return Collections.unmodifiableMap(map);
}
/**
Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/LocationPerfCheck.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/LocationPerfCheck.java?rev=1486482&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/LocationPerfCheck.java (added)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/LocationPerfCheck.java Sun May 26 22:11:29 2013
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.Timer;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class LocationPerfCheck {
+
+ private static final int LOOP_COUNT = 100000;
+
+
+ @Test
+ public void testLocation() {
+ Timer timer = new Timer("LogEvent", LOOP_COUNT);
+ timer.start();
+ for (int i = 0; i < LOOP_COUNT; ++i) {
+ final LogEvent event1 = new Log4jLogEvent(this.getClass().getName(), null,
+ "org.apache.logging.log4j.core.impl.Log4jLogEvent",
+ Level.INFO, new SimpleMessage("Hello, world!"), null);
+ StackTraceElement element = event1.getSource();
+ }
+ timer.stop();
+ System.out.println(timer.toString());
+ }
+}
Propchange: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/LocationPerfCheck.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverterTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverterTest.java?rev=1486482&r1=1486481&r2=1486482&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverterTest.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverterTest.java Sun May 26 22:11:29 2013
@@ -16,15 +16,16 @@
*/
package org.apache.logging.log4j.core.appender.db.jpa.converter;
+import static org.junit.Assert.*;
+
import java.util.Arrays;
import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.spi.MutableThreadContextStack;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import static org.junit.Assert.assertEquals;
-
public class ContextStackAttributeConverterTest {
private ContextStackAttributeConverter converter;
@@ -40,7 +41,8 @@ public class ContextStackAttributeConver
@Test
public void testConvertToDatabaseColumn01() {
- ThreadContext.ContextStack stack = new ThreadContext.ImmutableStack(Arrays.asList("value1", "another2"));
+ ThreadContext.ContextStack stack = new MutableThreadContextStack(
+ Arrays.asList("value1", "another2"));
assertEquals("The converted value is not correct.", "value1\nanother2",
this.converter.convertToDatabaseColumn(stack));
@@ -48,9 +50,11 @@ public class ContextStackAttributeConver
@Test
public void testConvertToDatabaseColumn02() {
- ThreadContext.ContextStack stack = new ThreadContext.ImmutableStack(Arrays.asList("key1", "value2", "my3"));
+ ThreadContext.ContextStack stack = new MutableThreadContextStack(
+ Arrays.asList("key1", "value2", "my3"));
- assertEquals("The converted value is not correct.", "key1\nvalue2\nmy3",
+ assertEquals("The converted value is not correct.",
+ "key1\nvalue2\nmy3",
this.converter.convertToDatabaseColumn(stack));
}
Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverterTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverterTest.java?rev=1486482&r1=1486481&r2=1486482&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverterTest.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverterTest.java Sun May 26 22:11:29 2013
@@ -16,15 +16,16 @@
*/
package org.apache.logging.log4j.core.appender.db.jpa.converter;
+import static org.junit.Assert.*;
+
import java.util.Arrays;
import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.spi.MutableThreadContextStack;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import static org.junit.Assert.*;
-
public class ContextStackJsonAttributeConverterTest {
private ContextStackJsonAttributeConverter converter;
@@ -40,29 +41,37 @@ public class ContextStackJsonAttributeCo
@Test
public void testConvert01() {
- ThreadContext.ContextStack stack = new ThreadContext.ImmutableStack(Arrays.asList("value1", "another2"));
+ ThreadContext.clearStack();
+ ThreadContext.ContextStack stack = new MutableThreadContextStack(
+ Arrays.asList("value1", "another2"));
String converted = this.converter.convertToDatabaseColumn(stack);
assertNotNull("The converted value should not be null.", converted);
- ThreadContext.ContextStack reversed = this.converter.convertToEntityAttribute(converted);
+ ThreadContext.ContextStack reversed = this.converter
+ .convertToEntityAttribute(converted);
assertNotNull("The reversed value should not be null.", reversed);
- assertEquals("The reversed value is not correct.", stack.asList(), reversed.asList());
+ assertEquals("The reversed value is not correct.", stack.asList(),
+ reversed.asList());
}
@Test
public void testConvert02() {
- ThreadContext.ContextStack stack = new ThreadContext.ImmutableStack(Arrays.asList("key1", "value2", "my3"));
+ ThreadContext.clearStack();
+ ThreadContext.ContextStack stack = new MutableThreadContextStack(
+ Arrays.asList("key1", "value2", "my3"));
String converted = this.converter.convertToDatabaseColumn(stack);
assertNotNull("The converted value should not be null.", converted);
- ThreadContext.ContextStack reversed = this.converter.convertToEntityAttribute(converted);
+ ThreadContext.ContextStack reversed = this.converter
+ .convertToEntityAttribute(converted);
assertNotNull("The reversed value should not be null.", reversed);
- assertEquals("The reversed value is not correct.", stack.asList(), reversed.asList());
+ assertEquals("The reversed value is not correct.", stack.asList(),
+ reversed.asList());
}
}
Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicyTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicyTest.java?rev=1486482&r1=1486481&r2=1486482&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicyTest.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicyTest.java Sun May 26 22:11:29 2013
@@ -16,12 +16,12 @@
*/
package org.apache.logging.log4j.core.appender.rewrite;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.MarkerManager;
-import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.helpers.KeyValuePair;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
@@ -29,6 +29,8 @@ import org.apache.logging.log4j.core.imp
import org.apache.logging.log4j.message.MapMessage;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.message.StructuredDataMessage;
+import org.apache.logging.log4j.spi.MutableThreadContextStack;
+import org.apache.logging.log4j.spi.ThreadContextStack;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -49,12 +51,13 @@ public class MapRewritePolicyTest {
logEvent1 = new Log4jLogEvent("test", null, "MapRewritePolicyTest.setupClass()", Level.ERROR,
new MapMessage(map), null, map, null, "none",
new StackTraceElement("MapRewritePolicyTest", "setupClass", "MapRewritePolicyTest", 29), 2);
+ ThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>(map.values()));
logEvent2 = new Log4jLogEvent("test", MarkerManager.getMarker("test"), "MapRewritePolicyTest.setupClass()",
Level.TRACE, new StructuredDataMessage("test", "Nothing", "test", map), new RuntimeException("test"), null,
- new ThreadContext.ImmutableStack(map.values()), "none", new StackTraceElement("MapRewritePolicyTest",
+ stack, "none", new StackTraceElement("MapRewritePolicyTest",
"setupClass", "MapRewritePolicyTest", 30), 20000000);
logEvent3 = new Log4jLogEvent("test", null, "MapRewritePolicyTest.setupClass()", Level.ALL, new MapMessage(map),
- null, map, new ThreadContext.ImmutableStack(map.values()), null, new StackTraceElement("MapRewritePolicyTest",
+ null, map, stack, null, new StackTraceElement("MapRewritePolicyTest",
"setupClass", "MapRewritePolicyTest", 31), Long.MAX_VALUE);
rewrite = new KeyValuePair[] {new KeyValuePair("test2", "2"), new KeyValuePair("test3", "three")};
}
Modified: logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java?rev=1486482&r1=1486481&r2=1486482&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java (original)
+++ logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java Sun May 26 22:11:29 2013
@@ -52,13 +52,13 @@ public class MDCContextMap implements Th
@Override
@SuppressWarnings("unchecked") // nothing we can do about this, restricted by SLF4J API
- public Map<String, String> getContext() {
+ public Map<String, String> getCopy() {
return MDC.getCopyOfContextMap();
}
@Override
@SuppressWarnings("unchecked") // nothing we can do about this, restricted by SLF4J API
- public Map<String, String> get() {
+ public Map<String, String> getImmutableMapOrNull() {
return MDC.getCopyOfContextMap();
}