This commit was manufactured by cvs2svn to create tag 'v1_2_1'.
git-svn-id: https://svn.apache.org/repos/asf/logging/log4j/tags/v1_2_1@309531 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/BRANCHES b/BRANCHES
new file mode 100644
index 0000000..da0e39d
--- /dev/null
+++ b/BRANCHES
@@ -0,0 +1,61 @@
+
+Given that log4j 1.3 is not likely to be released before a few months,
+I have created a branch called v1_2-branch in our CVS repository. The
+branch was created by issuing the following command:
+
+cvs -d :ext:ceki@cvs.apache.org:/home/cvs rtag -b -r v1_2final v1_2-branch jakarta-log4j
+
+Using the 1.2 branch, we can incorporate patches to log4j version 1.2
+while version 1.3 continues to be developed on the main trunk. For
+example, we can officially release LogFactor5 (including
+documentation) already in log4j 1.2.1.
+
+The command to access the v1_2-branch is:
+
+cvs -d XYZ checkout -r v1_2-branch jakarta-log4j
+
+where XYZ is the remote repository name, that is
+":ext:ceki@cvs.apache.org:/home/cvs" for me.
+
+Alternatively, you can issue following update command from within any
+existing work copy.
+
+ cvs update -r v1_2-branch
+
+Working with branches is not completely trivial and requires a little
+coordination between committers, in particular in relation with branch
+merge operations. In order to avoid multiple merge conflicts, each
+time we merge from the 1.2 branch to the main trunk, we should tag the
+merged version on the 1.2 branch. Subsequent merges should use the tag
+referring to the latest merged version of the branch. Also do not
+forget to publicly announce a merge operation.
+
+I am suggesting that (1.2 -> trunk) merge operations be done in a
+concerted manner. Before doing a merge you tell everyone that you are
+going to do a merge, you execute the merge operation, and then tag the
+merged version on the 1.2 branch, for example v_1_2_-merged-bug666
+
+The *next* merge operation would be performed as
+
+ cvs update -j v_1_2_-merged-bug666 -j v1_2-branch
+
+from within a working copy of the *trunk*. This merge operation would
+obviously also need to be tagged. According to the CVS manual, this
+procedure eliminates the side effects of merging already merged
+changes.
+
+Bug fixes should and documentation improvements, should be made to the
+1.2 branch, not the trunk. I'll take care of merging the changes to
+the main trunk.
+
+If this sounds like mambo jumbo, I urge you to consult the CVS
+documentation and experiment with branches before hitting the log4j
+repository. Branches are not that complicated really although they
+require slightly more discipline on the part of committers. Do not
+hesitate to shout if you need help.
+
+If you have a better alternative for working with branches please let
+us know.
+
+--
+Ceki
\ No newline at end of file
diff --git a/INSTALL b/INSTALL
index cf4fd20..d3db76b 100644
--- a/INSTALL
+++ b/INSTALL
@@ -11,7 +11,8 @@
version number, under PATH_OF_YOUR_CHOICE. We will refer to the
directory PATH_OF_YOUR_CHOICE/jakarta-log4j-VERSION/ as $LOG4J_HOME/.
-3) Add $LOG4J_HOME/dist/lib/log4j-1.2.jar to your CLASSPATH.
+3) Assuming you are using log4j version 1.2, add
+ $LOG4J_HOME/dist/lib/log4j-1.2.jar to your CLASSPATH,
4) You can now test your installation by first compiling the following
simple program.
@@ -57,8 +58,7 @@
log4j dependencies
==================
-The log4j distribution comes with pre-compiled classes. Log4j is based
-on JDK 1.1 with the following additional requirements:
+Log4j is based on JDK 1.1 with the following additional requirements:
----------------------------
Package org.apache.log4j.xml
@@ -82,7 +82,8 @@
The SMTPAppender relies on the JavaMail API. It has been tested with
JavaMail API version 1.2. The JavaMail API requires the
- JavaBeans Activation Framework package. You can download the JavaMail API at:
+ JavaBeans Activation Framework package. You can download the
+ JavaMail API at:
http://java.sun.com/products/javamail/
@@ -104,8 +105,8 @@
-----------------------
Log4j uses the JUnit framework version 3.7 for internal unit
- testing. If you want to compile all log4j source code, then you
- will need JUnit. JUnit is available from:
+ testing. If you want to compile the source code in the tests/
+ directory, then you will need JUnit. JUnit is available from:
http://www.junit.org
@@ -121,7 +122,7 @@
build.properties.sample file.
In case of problems send an e-mail note to
-log4j-user@jakarta.apache.org. Please do not directly e-mail any of
-the log4j developers. The answer to your question might be useful to
-other users. Moreover, there are many knowledgeable users on the
-log4j-user mailing lists who can quickly answer your questions.
+log4j-user@jakarta.apache.org. Please do not directly e-mail any
+log4j developers. The answer to your question might be useful to other
+users. Moreover, there are many knowledgeable users on the log4j-user
+mailing lists who can quickly answer your questions.
diff --git a/build.xml b/build.xml
index 9bcb740..4f2baaf 100644
--- a/build.xml
+++ b/build.xml
@@ -17,7 +17,7 @@
<!-- prefixed with "env". -->
<property environment="env"/>
- <property name="version" value="1.2"/>
+ <property name="version" value="1.2.1"/>
<!-- The base directory relative to which most targets are built -->
<property name="base" value="."/>
@@ -413,6 +413,7 @@
examples/**,
build/*,
build.xml,
+ build.properties.sample,
manifest.mf,
INSTALL,
LICENSE.txt,
@@ -423,6 +424,7 @@
**/*.bak, **/goEnv.bat,
**/Makefile, **/goEnv.bat,
docs/pub-support/*,
+ dist/classes/org/**,
src/java/org/apache/log4j/test/**/*,
**/.#*"/>
</copy>
diff --git a/docs/HISTORY b/docs/HISTORY
index d20fba1..f8974e3 100644
--- a/docs/HISTORY
+++ b/docs/HISTORY
@@ -5,7 +5,18 @@
client code.
[***] Changes requiring important modifications to existing client code.
- April, 2002
+ May 17th, 2002
+
+ - Relase of version 1.2.1
+
+ - This minor release fixes bug #9155 reported by Nicko Cadell.
+ LoggingEvent.getMDCCopy() method now sets mdcCopyLookupRequired
+ instead of ndcLookupRequired. This bug would cause the wrong MDC
+ information to appear on a log server. It could only occur if the
+ client wrapped an AsyncAppender around a SocketAppender or if the
+ server used an AsyncAppender for its logging. [*]
+
+ May, 2002
- Release of version 1.2
diff --git a/docs/manual.html b/docs/manual.html
index 50c5331..2c24f45 100644
--- a/docs/manual.html
+++ b/docs/manual.html
@@ -90,7 +90,7 @@
application. If too verbose, it can cause scrolling blindness. To
alleviate these concerns, log4j is designed to be reliable, fast and
extensible. Since logging is rarely the main focus of an application,
-log4j API strives to be simple to understand and to use.
+the log4j API strives to be simple to understand and to use.
<h2>Loggers, Appenders and Layouts</h2>
@@ -114,13 +114,13 @@
earlier versions of log4j, the <code>Logger</code> class can be
considered as a mere alias to the <code>Category</code> class.
-<p> Loggers are named entities. Logger names are case-sensitive and
+<p>Loggers are named entities. Logger names are case-sensitive and
they follow the hierarchical naming rule:
<p>
<table bgcolor="#EEEE99">
<tr>
- <td>
+ <td>
<dl>
<dt><b>Named Hierarchy</b>
@@ -142,11 +142,11 @@
should be familiar to most developers.
<p>The root logger resides at the top of the logger hierarchy. It
-is exceptional in two ways:
+is exceptional in two ways:
<ol>
<li> it always exists,
-<li> it cannot be retrieved by name.
+<li> it cannot be retrieved by name.
</ol>
<p>Invoking the class static <a
href="api/org/apache/log4j/Logger.html#getRootLogger()">Logger.getRootLogger</a>
@@ -162,18 +162,19 @@
<td>
<pre>
package org.apache.log4j;
-
+
public class <b>Logger</b> {
-
+
// Creation & retrieval methods:
public static Logger getRootLogger();
public static Logger getLogger(String name);
-
+
// printing methods:
public void debug(Object message);
public void info(Object message);
public void warn(Object message);
public void error(Object message);
+ public void fatal(Object message);
// generic printing method:
public void log(Level l, Object message);
@@ -183,19 +184,19 @@
</table>
<p>Loggers <em>may</em> be assigned levels. The set of possible
-levels, that is
+levels, that is
-<a href="api/org/apache/log4j/Level.html#DEBUG">DEBUG</a>,
-<a href="api/org/apache/log4j/Level.html#INFO">INFO</a>,
-<a href="api/org/apache/log4j/Level.html#WARN">WARN</a>,
-<a href="api/org/apache/log4j/Level.html#ERROR">ERROR</a> and
-<a href="api/org/apache/log4j/Level.html#FATAL">FATAL</a>
+<a href="api/org/apache/log4j/Level.html#DEBUG">DEBUG</a>,
+<a href="api/org/apache/log4j/Level.html#INFO">INFO</a>,
+<a href="api/org/apache/log4j/Level.html#WARN">WARN</a>,
+<a href="api/org/apache/log4j/Level.html#ERROR">ERROR</a> and
+<a href="api/org/apache/log4j/Level.html#FATAL">FATAL</a>
are defined in the <code><a
href="api/org/apache/log4j/Level.html">org.apache.log4j.Level</a></code>
-class. Although we do not encourage you from doing so, you may define
+class. Although we do not encourage you to do so, you may define
your own levels by sub-classing the <code>Level</code> class. A
-perhaps better approach is will be explained later on.
+perhaps better approach will be explained later on.
<p>If a given logger is not assigned a level, then it inherits
one from its closest ancestor with an assigned level. More
@@ -205,7 +206,7 @@
<p>
<table bgcolor="#EEEE99">
<tr>
- <td>
+ <td>
<dl>
<dt><b>Level Inheritance</b>
@@ -231,10 +232,10 @@
<tr align=left><td>X </td> <td>none</td> <td>Proot</td></tr>
<tr align=left><td>X.Y </td> <td>none</td> <td>Proot</td></tr>
<tr align=left><td>X.Y.Z</td> <td>none</td> <td>Proot</td></tr>
- <caption align=bottom>Example 1</caption>
+ <caption align=bottom>Example 1</caption>
</table>
-<p>In example 1 above, only the root logger is assinged a
+<p>In example 1 above, only the root logger is assigned a
level. This level value, <code>Proot</code>, is inherited by the
other loggers <code>X</code>, <code>X.Y</code> and
<code>X.Y.Z</code>.
@@ -288,17 +289,17 @@
<p>Logging requests are made by invoking one of the printing methods
-of a logger instance. These printing methods are
+of a logger instance. These printing methods are
<code>
<a href="api/org/apache/log4j/Logger.html#debug(java.lang.Object)">debug</a>,
-<a href="api/org/apache/log4j/Logger.html#info(java.lang.Object)">info</a>,
+<a href="api/org/apache/log4j/Logger.html#info(java.lang.Object)">info</a>,
-<a href="api/org/apache/log4j/Logger.html#warn(java.lang.Object)">warn</a>,
+<a href="api/org/apache/log4j/Logger.html#warn(java.lang.Object)">warn</a>,
<a href="api/org/apache/log4j/Logger.html#error(java.lang.Object)">error</a>,
<a href="api/org/apache/log4j/Logger.html#fatal(java.lang.Object)">fatal</a>
- and <a href="api/org/apache/log4j/Logger.html#log(org.apache.log4j.Level, java.lang.Object)">log</a></code>.
+ and <a href="api/org/apache/log4j/Logger.html#log(org.apache.log4j.Level, java.lang.Object)">log</a></code>.
<p>By definition, the printing method determines the level of a
@@ -321,8 +322,8 @@
<dt><b>Basic Selection Rule</b>
<dd><p>A log request of level <i>p</i> in a logger with
- inherited level <i>q</i>, is enabled if <i> p >=
- q</i>.
+ (either assigned or inherited, whichever is appropriate) level <i>q</i>, is enabled if <i> p >=
+ q</i>.
</dl>
</table>
@@ -330,7 +331,7 @@
ordered. For the standard levels, we have <code>DEBUG < INFO
< WARN < ERROR < FATAL</code>.
-<p>Here is an example of this rule.
+<p>Here is an example of this rule.
<p><table bgcolor="CCCCCC">
<tr><td>
@@ -339,35 +340,35 @@
// get a logger instance named "com.foo"
Logger logger = Logger.getLogger(<strong>"com.foo"</strong>);
- // Now set its level. Normally you do not need to set the
- // level of a logger progamitcally. This is usually done
+ // Now set its level. Normally you do not need to set the
+ // level of a logger programmatically. This is usually done
// in configuration files.
<strong>logger</strong>.setLevel(<font
color="0000AA"><strong>Level.INFO</strong></font>);
Logger barlogger = Logger.getLogger(<strong>"com.foo.Bar"</strong>);
-
+
// This request is enabled, because <font color="00AA00"><strong>WARN</strong></font> >= <font color="0000AA"><strong>INFO</strong></font>.
logger.<font color="00AA00"><strong>warn</strong></font>("Low fuel level.");
-
- // This request is disabled, because <font color="00AA00"><strong>DEBUG</strong></font> < <font color="0000AA"><strong>INFO</strong></font>.
- logger.<font color="00AA00"><strong>debug</strong></font>("Starting search for nearest gas station.");
-
- // The logger instance barlogger, named "com.foo.Bar",
- // will inherit its level from the logger named
- // "com.foo" Thus, the following request is enabled
- // because <font color="00AA00"><strong>INFO</strong></font> >= <font color="0000AA"><strong>INFO</strong></font>.
- barlogger.<font color="00AA00"><strong>info</strong></font>("Located nearest gas station.");
// This request is disabled, because <font color="00AA00"><strong>DEBUG</strong></font> < <font color="0000AA"><strong>INFO</strong></font>.
- barlogger.<font color="00AA00"><strong>debug</strong></font>("Exiting gas station search");
+ logger.<font color="00AA00"><strong>debug</strong></font>("Starting search for nearest gas station.");
+
+ // The logger instance barlogger, named "com.foo.Bar",
+ // will inherit its level from the logger named
+ // "com.foo" Thus, the following request is enabled
+ // because <font color="00AA00"><strong>INFO</strong></font> >= <font color="0000AA"><strong>INFO</strong></font>.
+ barlogger.<font color="00AA00"><strong>info</strong></font>("Located nearest gas station.");
+
+ // This request is disabled, because <font color="00AA00"><strong>DEBUG</strong></font> < <font color="0000AA"><strong>INFO</strong></font>.
+ barlogger.<font color="00AA00"><strong>debug</strong></font>("Exiting gas station search");
</pre>
-</table>
+</table>
<p>Calling the <code>getLogger</code> method with the same name will
-always return a reference to the exact same logger object.
+always return a reference to the exact same logger object.
-<p>For example, in
+<p>For example, in
<table bgcolor="CCCCCC">
<tr><td>
@@ -422,7 +423,7 @@
Event Loggers</a>, and remote UNIX <a
href="api/org/apache/log4j/net/SyslogAppender.html">Syslog</a>
daemons. It is also possible to log <a href="api/org/apache/log4j/AsyncAppender.html">asynchronously</a>.
-
+
<p>More than one appender can be attached to a logger.
<p>The <a
@@ -486,14 +487,14 @@
<tr><td>x.y <td>none <td>true <td>A1, A-x1, A-x2
<td>Appenders of "x" and root.
-<tr><td>x.y.z <td>A-xyz1 <td>true <td>A1, A-x1, A-x2, A-xyz1
+<tr><td>x.y.z <td>A-xyz1 <td>true <td>A1, A-x1, A-x2, A-xyz1
<td>Appenders in "x.y.z", "x" and root.
-<tr><td>security <td>A-sec <td><font color="blue">false</font>
+<tr><td>security <td>A-sec <td><font color="blue">false</font>
<td>A-sec
<td>No appender accumulation since the additivity flag is set to
- <code>false</code>.
+ <code>false</code>.
<tr><td>security.access <td>none <td> true <td> A-sec <td>Only
appenders of "security" because the additivity flag in "security" is
@@ -507,7 +508,7 @@
associating a <em>layout</em> with an appender. The layout is
responsible for formatting the logging request according to the user's
wishes, whereas an appender takes care of sending the formatted output
-to its destination.
+to its destination.
The <a
href="api/org/apache/log4j/PatternLayout.html">PatternLayout</a>, part
@@ -533,7 +534,7 @@
frequently need to log <code>Oranges</code>, an object type used in
your current project, then you can register an
<code>OrangeRenderer</code> that will be invoked whenever an orange
-needs to be logged.
+needs to be logged.
<p>Object rendering follows the class hierarchy. For example, assuming
oranges are fruits, if you register an <code>FruitRenderer</code>, all
@@ -570,7 +571,7 @@
// Import log4j classes.
<b>import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;</b>
-
+
public class MyApp {
// Define a static logger variable so that it references the
@@ -585,7 +586,7 @@
logger.info("Entering application.");
Bar bar = new Bar();
bar.doIt();
- logger.info("Exiting application.");
+ logger.info("Exiting application.");
}
}
</pre>
@@ -603,12 +604,12 @@
<pre>
<b>package com.foo;</b>
import org.apache.log4j.Logger;
-
+
public class Bar {
<strong>static</strong> Logger logger = <strong>Logger.getLogger(Bar.class);</strong>
-
+
public void doIt() {
- logger.debug("Did it again!");
+ logger.debug("Did it again!");
}
}
</pre>
@@ -624,7 +625,7 @@
to the pattern "%-4r [%t] %-5p %c %x - %m%n".
<p>Note that by default, the root logger is assigned to
-<code>Level.DEBUG</code>.
+<code>Level.DEBUG</code>.
<p>The output of MyApp is:
<pre>
@@ -635,7 +636,7 @@
<p>The figure below depicts the object diagram of <code>MyApp</code>
after just having called the <code>BasicConfigurator.configure</code>
-method.
+method.
<p>
<center>
@@ -658,7 +659,7 @@
<p>The previous example always outputs the same log information.
Fortunately, it is easy to modify <code>MyApp</code> so that the log
output can be controlled at run-time. Here is a slightly modified
-version.
+version.
<p><table bgcolor="CCCCCC"><tr><td>
<pre>
@@ -666,21 +667,21 @@
import org.apache.log4j.Logger;
<b>import org.apache.log4j.PropertyConfigurator;</b>
-
+
public class MyApp {
static Logger logger = Logger.getLogger(MyApp.class.getName());
public static void main(String[] args) {
-
+
// BasicConfigurator replaced with PropertyConfigurator.
<strong>PropertyConfigurator.configure(args[0]);</strong>
logger.info("Entering application.");
Bar bar = new Bar();
bar.doIt();
- logger.info("Exiting application.");
+ logger.info("Exiting application.");
}
}
</pre>
@@ -697,10 +698,10 @@
<pre>
# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, A1
-
-# A1 is set to be a ConsoleAppender.
+
+# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
-
+
# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
@@ -721,10 +722,10 @@
log4j.rootLogger=DEBUG, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
-
+
# <strong>Print the date in ISO 8601 format</strong>
log4j.appender.A1.layout.ConversionPattern=<strong>%d</strong> [%t] %-5p %c - %m%n
-
+
# Print only messages of level WARN or above in the package com.foo.
<strong>log4j.logger.com.foo=WARN</strong>
</pre>
@@ -932,7 +933,7 @@
tells log4j to use the file <code>c:\foobar.lcf</code> as the default
configuration file. The configuration file is fully specified by the
URL <code>file:/c:/foobar.lcf</code>. Thus, the same configuration
-file will be used for all web-applications.
+file will be used for all web-applications.
<p>Different web-applications will load the log4j classes through
@@ -963,9 +964,9 @@
import java.io.IOException;
public class Log4jInit extends HttpServlet {
-
+
public
- void <b>init()</b> {
+ void <b>init()</b> {
String prefix = getServletContext().getRealPath("/");
String file = getInitParameter("log4j-init-file");
// if the log4j-init-file is not set, then no point in trying
@@ -1029,19 +1030,19 @@
<em>Nested Diagnostic Context</em>. The NDC class is shown below.
<pre>
- public class NDC {
- // Used when printing the diagnostic
- public <strong>static</strong> String get();
-
+ public class NDC {
+ // Used when printing the diagnostic
+ public <strong>static</strong> String get();
+
// Remove the top of the context from the NDC.
- public <strong>static</strong> String pop();
-
+ public <strong>static</strong> String pop();
+
// Add diagnostic context for the current thread.
- public <strong>static</strong> void push(String message);
-
- // Remove the diagnostic context for this thread.
- public <strong>static</strong> void remove();
- }
+ public <strong>static</strong> void push(String message);
+
+ // Remove the diagnostic context for this thread.
+ public <strong>static</strong> void remove();
+ }
</pre>
<p>The NDC is managed per thread as a <em>stack</em> of contextual
@@ -1096,7 +1097,7 @@
machine this cost is typically in the 5 to 50 nanosecond range.
<p>However, The method invocation involves the "hidden" cost of
- parameter construction.
+ parameter construction.
<p>For example, for some logger <code>cat</code>, writing,
<pre>
@@ -1113,12 +1114,12 @@
<p>To avoid the parameter construction cost write:
- <pre>
+ <pre>
if(logger.isDebugEnabled() {
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}
</pre>
-
+
<p>This will not incur the cost of parameter
construction if debugging is disabled. On the other hand, if
the logger is debug-enabled, it will incur twice the cost of
@@ -1127,7 +1128,7 @@
<code>debug</code>. This is an insignificant
overhead because evaluating a logger takes about 1%
of the time it takes to actually log.
-
+
<p>In log4j, logging requests are made to instances of the Logger
class. Logger is a class and not an interface. This measurably
reduces the cost of method invocation at the cost of some
diff --git a/src/java/org/apache/log4j/NDC.java b/src/java/org/apache/log4j/NDC.java
index aa44615..b032744 100644
--- a/src/java/org/apache/log4j/NDC.java
+++ b/src/java/org/apache/log4j/NDC.java
@@ -192,7 +192,8 @@
/**
- Used when printing the diagnostic context.
+ <font color="#FF4040"><b>Never use this method directly, use the {@link
+ org.apache.log4j.spi.LoggingEvent#getNDC} method instead.</b></font>
*/
static
public
diff --git a/src/java/org/apache/log4j/spi/LoggingEvent.java b/src/java/org/apache/log4j/spi/LoggingEvent.java
index 5cd6e42..b35332c 100644
--- a/src/java/org/apache/log4j/spi/LoggingEvent.java
+++ b/src/java/org/apache/log4j/spi/LoggingEvent.java
@@ -62,18 +62,16 @@
/** Have we tried to do an NDC lookup? If we did, there is no need
- to do it again. Note that its value is always false when
- serialized. Thus, a receiving SocketNode will never use it's own
- (incorrect) NDC. See also writeObject method. */
+ * to do it again. Note that its value is always false when
+ * serialized. Thus, a receiving SocketNode will never use it's own
+ * (incorrect) NDC. See also writeObject method. */
private boolean ndcLookupRequired = true;
- /** Have we tried to do an MDC lookup? If we did, there is no need to
- do it again. Note that its value is always false when
- serialized. Thus, a receiving SocketNode will never use it's own
- (incorrect) MDC. See also writeObject method. */
- private boolean mdcLookupRequired = true;
-
+ /** Have we tried to do an MDC lookup? If we did, there is no need
+ * to do it again. Note that its value is always false when
+ * serialized. See also the getMDC and getMDCCopy methods. */
+ private boolean mdcCopyLookupRequired = true;
/** The application supplied message of logging event. */
transient private Object message;
@@ -187,6 +185,11 @@
}
}
+ /**
+ * This method returns the NDC for this event. It will return the
+ * correct content even if the event was generated in a different
+ * thread or even on a different machine. The {@link NDC#get} method
+ * should <em>never</em> be called directly. */
public
String getNDC() {
if(ndcLookupRequired) {
@@ -199,9 +202,11 @@
/**
Returns the the context corresponding to the <code>key</code>
- parameter. If there is a local MDC copy (probably from a remote
- machine, the we use it, if that fails then the current thread's
- <code>MDC</code> is used.
+ parameter. If there is a local MDC copy, possibly because we are
+ in a logging server or running inside AsyncAppender, then we
+ search for the key in MDC copy, if a value is found it is
+ returned. Otherwise, if the search in MDC copy returns a null
+ result, then the current thread's <code>MDC</code> is used.
<p>Note that <em>both</em> the local MDC copy and the current
thread's MDC are searched.
@@ -223,11 +228,12 @@
/**
Obtain a copy of this thread's MDC prior to serialization or
- asynchronous logging. */
+ asynchronous logging.
+ */
public
void getMDCCopy() {
- if(mdcLookupRequired) {
- ndcLookupRequired = false;
+ if(mdcCopyLookupRequired) {
+ mdcCopyLookupRequired = false;
// the clone call is required for asynchronous logging.
// See also bug #5932.
Hashtable t = (Hashtable) MDC.getContext();
diff --git a/src/xdocs/documentation.xml b/src/xdocs/documentation.xml
index 0f2690a..ec3ea81 100644
--- a/src/xdocs/documentation.xml
+++ b/src/xdocs/documentation.xml
@@ -58,10 +58,6 @@
Add logging to your Java Applications</a> by Kevin Brown
</li>
- <li><a href="http://www.entwickler.com/jm/ausgaben/2001/4/artikel/17/online.shtml">
- Computer: captains, new entry... DasJakarta Logging-System log4j</a> by Thomas Poschmann
- </li>
-
<li>
<a href="http://www.opensymphony.com/guidelines/logging.jsp">OpenSymphony Logging Primer</a>
</li>
diff --git a/src/xdocs/download.xml b/src/xdocs/download.xml
index 6f40fb1..4e8db25 100644
--- a/src/xdocs/download.xml
+++ b/src/xdocs/download.xml
@@ -9,13 +9,19 @@
<meta name="keywords" content="java, logging, tracing, component, framework, API, log4j"/>
<body>
- <section name="log4j version 1.2 (final)">
- <p>log4j 1.2 is now available in <a
- href="../jakarta-log4j-1.2.tar.gz"><b>TAR.GZ</b></a> format or
- in <a href="../jakarta-log4j-1.2.zip"><b>ZIP</b></a> format.
+ <section name="log4j version 1.2.1">
+ <p>log4j 1.2.1 is now available in <a
+ href="../jakarta-log4j-1.2.1.tar.gz"><b>TAR.GZ</b></a> format
+ or in <a href="../jakarta-log4j-1.2.1.zip"><b>ZIP</b></a>
+ format.
</p>
-
+ <p>This minor release fixes bug #9155 reported by Nicko
+ Cadell. With the exception of this bug fix and some
+ documentation improvements, it is identical to log4j 1.2
+ final.
+ </p>
+
<p>In addition to many performance improvements, bug fixes, and
other small enhancements, log4j 1.2 adds JMX support, Mapped
Diagnostic Contexts, JDBC logging, graphical log viewer
@@ -57,9 +63,9 @@
<dt><a
href="http://logui.sourceforge.net/"><b>Chainsaw</b></a></dt>
- <dd>Chainsaw is now integrated with log4j and ships with the
- official distribution. Chainsaw is a graphical log viewer and
- filter for the log4j package. It listens for <a
+ <dd><b>Chainsaw is now integrated with log4j and ships with
+ the official distribution.</b> Chainsaw is a graphical log
+ viewer and filter for the log4j package. It listens for <a
href="http://jakarta.apache.org/log4j/docs/api/org/apache/log4j/spi/LoggingEvent.html">LoggingEvent</a>
objects sent using the <a
href="http://jakarta.apache.org/log4j/docs/api/org/apache/log4j/net/SocketAppender.html">SocketAppender</a>
diff --git a/tests/build.xml b/tests/build.xml
index a249bdd..809c301 100644
--- a/tests/build.xml
+++ b/tests/build.xml
@@ -172,7 +172,7 @@
<target name="SocketServer" depends="build">
<parallel>
<java classname="org.apache.log4j.net.ShortSocketServer" fork="yes">
- <arg value="4"/>
+ <arg value="5"/>
<arg value="input/socketServer"/>
<classpath refid="tests.classpath"/>
</java>
diff --git a/tests/input/socketServer5.properties b/tests/input/socketServer5.properties
new file mode 100644
index 0000000..9772442
--- /dev/null
+++ b/tests/input/socketServer5.properties
@@ -0,0 +1,8 @@
+log4j.rootLogger=DEBUG, A
+log4j.Logger.org.apache.log4j.test.ShortSocketServer=WARN
+log4j.Logger.org.apache.log4j.net.SocketNode=WARN
+log4j.appender.A=org.apache.log4j.FileAppender
+log4j.appender.A.file=output/temp
+log4j.appender.A.Append=false
+log4j.appender.A.layout=org.apache.log4j.PatternLayout
+log4j.appender.A.layout.ConversionPattern=%5p %x %X{key1}%X{key5} [%t] %c{1} - %m%n
diff --git a/tests/src/java/org/apache/log4j/net/ShortSocketServer.java b/tests/src/java/org/apache/log4j/net/ShortSocketServer.java
index 99b8d5c..4da0259 100644
--- a/tests/src/java/org/apache/log4j/net/ShortSocketServer.java
+++ b/tests/src/java/org/apache/log4j/net/ShortSocketServer.java
@@ -20,10 +20,15 @@
import org.apache.log4j.net.SocketServer;
/**
- This SocketServer exits after just one connection from a client.
-
- @author Ceki Gulcu
-*/
+ * This SocketServer exits after certain number of connections from a
+ * client. This number is determined the totalsTest parameter, that is
+ * the first argument on the commmand line. The second argument,
+ * prefix, determines the prefix of the configuration file to
+ * use. Each run of the server will use a different properties
+ * file. For the i-th run, the path to the file is
+ * (prefix+i+".properties").
+ *
+ * @author Ceki Gulcu */
public class ShortSocketServer {
@@ -61,7 +66,7 @@
static
- void usage(String msg) {
+ void usage(String msg) {
System.err.println(msg);
System.err.println(
"Usage: java " +ShortSocketServer.class.getName() + " totalTests configFilePrefix");
diff --git a/tests/src/java/org/apache/log4j/net/SocketServerTestCase.java b/tests/src/java/org/apache/log4j/net/SocketServerTestCase.java
index 3810ac2..defbbd4 100644
--- a/tests/src/java/org/apache/log4j/net/SocketServerTestCase.java
+++ b/tests/src/java/org/apache/log4j/net/SocketServerTestCase.java
@@ -55,6 +55,9 @@
static String PAT4 = "^(DEBUG| INFO| WARN|ERROR|FATAL|LETHAL) some T4 MDC-TEST4 \\[main]\\"
+ " (root|SocketServerTestCase) - Message \\d{1,2}";
+ static String PAT5 = "^(DEBUG| INFO| WARN|ERROR|FATAL|LETHAL) some5 T5 MDC-TEST5 \\[main]\\"
+ + " (root|SocketServerTestCase) - Message \\d{1,2}";
+
static String EXCEPTION1 = "java.lang.Exception: Just testing";
static String EXCEPTION2 = "\\s*at .*\\(.*:\\d{1,4}\\)";
@@ -72,8 +75,6 @@
public void setUp() {
System.out.println("Setting up test case.");
- socketAppender = new SocketAppender("localhost", PORT);
- rootLogger.addAppender(socketAppender);
}
public void tearDown() {
@@ -81,8 +82,15 @@
socketAppender = null;
rootLogger.removeAllAppenders();
}
-
+
+ /**
+ * The pattern on the server side: %5p %x [%t] %c %m%n
+ *
+ * We are testing NDC functionality across the wire.
+ */
public void test1() throws Exception {
+ socketAppender = new SocketAppender("localhost", PORT);
+ rootLogger.addAppender(socketAppender);
common("T1", "key1", "MDC-TEST1");
delay(1);
ControlFilter cf = new ControlFilter(new String[]{PAT1, EXCEPTION1,
@@ -93,7 +101,16 @@
assertTrue(Compare.compare(FILTERED, "witness/socketServer.1"));
}
+ /**
+ * The pattern on the server side: %5p %x [%t] %C (%F:%L) %m%n
+ *
+ * We are testing NDC across the wire. Localization is turned off by
+ * default so it is not tested here even if the conversion pattern
+ * uses localization. */
public void test2() throws Exception {
+ socketAppender = new SocketAppender("localhost", PORT);
+ rootLogger.addAppender(socketAppender);
+
common("T2", "key2", "MDC-TEST2");
delay(1);
ControlFilter cf = new ControlFilter(new String[]{PAT2, EXCEPTION1,
@@ -104,8 +121,15 @@
assertTrue(Compare.compare(FILTERED, "witness/socketServer.2"));
}
+ /**
+ * The pattern on the server side: %5p %x [%t] %C (%F:%L) %m%n
+ * meaning that we are testing NDC and locatization functionality
+ * across the wire. */
public void test3() throws Exception {
+ socketAppender = new SocketAppender("localhost", PORT);
socketAppender.setLocationInfo(true);
+ rootLogger.addAppender(socketAppender);
+
common("T3", "key3", "MDC-TEST3");
delay(1);
ControlFilter cf = new ControlFilter(new String[]{PAT3, EXCEPTION1,
@@ -116,10 +140,19 @@
assertTrue(Compare.compare(FILTERED, "witness/socketServer.3"));
}
+ /**
+ * The pattern on the server side: %5p %x %X{key1}%X{key4} [%t] %c{1} - %m%n
+ * meaning that we are testing NDC, MDC and localization functionality across
+ * the wire.
+ */
public void test4() throws Exception {
+ socketAppender = new SocketAppender("localhost", PORT);
socketAppender.setLocationInfo(true);
+ rootLogger.addAppender(socketAppender);
+
NDC.push("some");
common("T4", "key4", "MDC-TEST4");
+ NDC.pop();
delay(1);
ControlFilter cf = new ControlFilter(new String[]{PAT4, EXCEPTION1,
EXCEPTION2, EXCEPTION3});
@@ -129,6 +162,41 @@
assertTrue(Compare.compare(FILTERED, "witness/socketServer.4"));
}
+ /**
+ * The pattern on the server side: %5p %x %X{key1}%X{key5} [%t] %c{1} - %m%n
+ *
+ * The test case uses wraps an AsyncAppender around the
+ * SocketAppender. This tests was written specifically for bug
+ * report #9155.
+
+ * Prior to the bug fix the output on the server did not contain the
+ * MDC-TEST5 string because the MDC clone operation (in getMDCCopy
+ * method) operation is performed twice, once from the main thread
+ * which is correct, and a second time from the AsyncAppender's
+ * dispatch thread which is incrorrect.
+
+ */
+ public void test5() throws Exception {
+ socketAppender = new SocketAppender("localhost", PORT);
+ socketAppender.setLocationInfo(true);
+ AsyncAppender asyncAppender = new AsyncAppender();
+ asyncAppender.setLocationInfo(true);
+ asyncAppender.addAppender(socketAppender);
+ rootLogger.addAppender(asyncAppender);
+
+ NDC.push("some5");
+ common("T5", "key5", "MDC-TEST5");
+ NDC.pop();
+ delay(2);
+ ControlFilter cf = new ControlFilter(new String[]{PAT5, EXCEPTION1,
+ EXCEPTION2, EXCEPTION3});
+
+ Transformer.transform(TEMP, FILTERED, new Filter[] {cf, new LineNumberFilter()});
+
+ assertTrue(Compare.compare(FILTERED, "witness/socketServer.5"));
+ }
+
+
static
void common(String dc, String key, Object o) {
int i = -1;
@@ -161,6 +229,7 @@
suite.addTest(new SocketServerTestCase("test2"));
suite.addTest(new SocketServerTestCase("test3"));
suite.addTest(new SocketServerTestCase("test4"));
+ suite.addTest(new SocketServerTestCase("test5"));
return suite;
}
}
diff --git a/tests/witness/socketServer.5 b/tests/witness/socketServer.5
new file mode 100644
index 0000000..dec6b0e
--- /dev/null
+++ b/tests/witness/socketServer.5
@@ -0,0 +1,35 @@
+DEBUG some5 T5 MDC-TEST5 [main] SocketServerTestCase - Message 1
+DEBUG some5 T5 MDC-TEST5 [main] root - Message 2
+ INFO some5 T5 MDC-TEST5 [main] SocketServerTestCase - Message 3
+ WARN some5 T5 MDC-TEST5 [main] SocketServerTestCase - Message 4
+LETHAL some5 T5 MDC-TEST5 [main] SocketServerTestCase - Message 5
+DEBUG some5 T5 MDC-TEST5 [main] SocketServerTestCase - Message 6
+java.lang.Exception: Just testing
+ at org.apache.log4j.net.SocketServerTestCase.common(SocketServerTestCase.java:XXX)
+ at org.apache.log4j.net.SocketServerTestCase.test5(SocketServerTestCase.java:XXX)
+ at java.lang.reflect.Method.invoke(Native Method)
+ at junit.framework.TestCase.runTest(TestCase.java:XXX)
+ at junit.framework.TestCase.runBare(TestCase.java:XXX)
+ at junit.framework.TestResult$1.protect(TestResult.java:XXX)
+ at junit.framework.TestResult.runProtected(TestResult.java:XXX)
+ at junit.framework.TestResult.run(TestResult.java:XXX)
+ at junit.framework.TestCase.run(TestCase.java:XXX)
+ at junit.framework.TestSuite.runTest(TestSuite.java:XXX)
+ at junit.framework.TestSuite.run(TestSuite.java:XXX)
+ at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:XXX)
+ at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.java:XXX)
+ERROR some5 T5 MDC-TEST5 [main] root - Message 7
+java.lang.Exception: Just testing
+ at org.apache.log4j.net.SocketServerTestCase.common(SocketServerTestCase.java:XXX)
+ at org.apache.log4j.net.SocketServerTestCase.test5(SocketServerTestCase.java:XXX)
+ at java.lang.reflect.Method.invoke(Native Method)
+ at junit.framework.TestCase.runTest(TestCase.java:XXX)
+ at junit.framework.TestCase.runBare(TestCase.java:XXX)
+ at junit.framework.TestResult$1.protect(TestResult.java:XXX)
+ at junit.framework.TestResult.runProtected(TestResult.java:XXX)
+ at junit.framework.TestResult.run(TestResult.java:XXX)
+ at junit.framework.TestCase.run(TestCase.java:XXX)
+ at junit.framework.TestSuite.runTest(TestSuite.java:XXX)
+ at junit.framework.TestSuite.run(TestSuite.java:XXX)
+ at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:XXX)
+ at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.java:XXX)