-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #379 from dmlloyd/ndc
Add NDC Provider
- Loading branch information
Showing
3 changed files
with
211 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package org.jboss.logmanager; | ||
|
||
public interface NDCProvider { | ||
|
||
/** | ||
* Push a value on to the NDC stack, returning the new stack depth which should later be used to restore the stack. | ||
* | ||
* @param context the new value | ||
* @return the new stack depth | ||
*/ | ||
int push(String context); | ||
|
||
/** | ||
* Pop the topmost value from the NDC stack and return it. | ||
* | ||
* @return the old topmost value | ||
*/ | ||
String pop(); | ||
|
||
/** | ||
* Clear the thread's NDC stack. | ||
*/ | ||
void clear(); | ||
|
||
/** | ||
* Trim the thread NDC stack down to no larger than the given size. Used to restore the stack to the depth returned | ||
* by a {@code push()}. | ||
* | ||
* @param size the new size | ||
*/ | ||
void trimTo(int size); | ||
|
||
/** | ||
* Get the current NDC stack depth. | ||
* | ||
* @return the stack depth | ||
*/ | ||
int getDepth(); | ||
|
||
/** | ||
* Get the current NDC value. | ||
* | ||
* @return the current NDC value, or {@code ""} if there is none | ||
*/ | ||
String get(); | ||
|
||
/** | ||
* Provided for compatibility with log4j. Get the NDC value that is {@code n} entries from the bottom. | ||
* | ||
* @param n the index | ||
* @return the value or {@code null} if there is none | ||
*/ | ||
String get(int n); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package org.jboss.logmanager; | ||
|
||
import java.util.Arrays; | ||
|
||
final class ThreadLocalNDC implements NDCProvider { | ||
private static final Holder ndc = new Holder(); | ||
|
||
@Override | ||
public int push(String context) { | ||
final Stack<String> stack = ndc.get(); | ||
try { | ||
return stack.depth(); | ||
} finally { | ||
stack.push(context); | ||
} | ||
} | ||
|
||
@Override | ||
public String pop() { | ||
final Stack<String> stack = ndc.get(); | ||
if (stack.isEmpty()) { | ||
return ""; | ||
} else { | ||
return stack.pop(); | ||
} | ||
} | ||
|
||
@Override | ||
public void clear() { | ||
ndc.get().trimTo(0); | ||
} | ||
|
||
@Override | ||
public void trimTo(int size) { | ||
ndc.get().trimTo(size); | ||
} | ||
|
||
@Override | ||
public int getDepth() { | ||
return ndc.get().depth(); | ||
} | ||
|
||
@Override | ||
public String get() { | ||
final Stack<String> stack = ndc.get(); | ||
if (stack.isEmpty()) { | ||
return ""; | ||
} else { | ||
return stack.toString(); | ||
} | ||
} | ||
|
||
@Override | ||
public String get(int n) { | ||
return ndc.get().get(n); | ||
} | ||
|
||
private static final class Holder extends ThreadLocal<Stack<String>> { | ||
protected Stack<String> initialValue() { | ||
return new Stack<>(); | ||
} | ||
} | ||
|
||
private static final class Stack<T> { | ||
private Object[] data = new Object[32]; | ||
private int sp; | ||
|
||
public void push(T value) { | ||
if (sp == data.length) { | ||
data = Arrays.copyOf(data, (data.length << 1) + data.length >>> 1); | ||
} | ||
data[sp++] = value; | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
public T pop() { | ||
try { | ||
return (T) data[--sp]; | ||
} finally { | ||
data[sp] = null; | ||
} | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
public T top() { | ||
return (T) data[sp - 1]; | ||
} | ||
|
||
public boolean isEmpty() { | ||
return sp == 0; | ||
} | ||
|
||
public int depth() { | ||
return sp; | ||
} | ||
|
||
public void trimTo(int max) { | ||
final int sp = this.sp; | ||
if (sp > max) { | ||
Arrays.fill(data, max, sp - 1, null); | ||
this.sp = max; | ||
} | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
public T get(int n) { | ||
return n < sp ? (T) data[n] : null; | ||
} | ||
|
||
public String toString() { | ||
final StringBuilder b = new StringBuilder(); | ||
final int sp = this.sp; | ||
for (int i = 0; i < sp; i++) { | ||
b.append(data[i]); | ||
if ((i + 1) < sp) { | ||
b.append('.'); | ||
} | ||
} | ||
return b.toString(); | ||
} | ||
} | ||
} |