Repository: logging-log4j2
Updated Branches:
  refs/heads/master 566449e9d -> 38cc8121b


LOG4J2-1255 - Add Messages to entry and exit tracing


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/fcb2d1fd
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/fcb2d1fd
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/fcb2d1fd

Branch: refs/heads/master
Commit: fcb2d1fde32b4250acb4c7b13e9e5cd899b792fc
Parents: 566449e
Author: Ralph Goers <[email protected]>
Authored: Sun Feb 7 14:20:54 2016 -0700
Committer: Ralph Goers <[email protected]>
Committed: Sun Feb 7 14:20:54 2016 -0700

----------------------------------------------------------------------
 log4j-api/pom.xml                               |  12 +
 .../java/org/apache/logging/log4j/Logger.java   | 196 ++++++++++++----
 .../logging/log4j/spi/AbstractLogger.java       | 229 ++++++++++++++++++-
 .../org/apache/logging/log4j/LoggerTest.java    |  51 +++++
 .../logging/log4j/message/JsonMessage.java      |  58 +++++
 src/changes/changes.xml                         |   3 +
 src/site/xdoc/manual/flowtracing.xml            |  39 +++-
 7 files changed, 517 insertions(+), 71 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fcb2d1fd/log4j-api/pom.xml
----------------------------------------------------------------------
diff --git a/log4j-api/pom.xml b/log4j-api/pom.xml
index 2f9e52e..0291d96 100644
--- a/log4j-api/pom.xml
+++ b/log4j-api/pom.xml
@@ -64,6 +64,18 @@
       <artifactId>commons-lang3</artifactId>
       <scope>test</scope>
     </dependency>
+    <!-- Required for JSON support -->
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <!-- Required for JSON support -->
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
   <build>
     <plugins>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fcb2d1fd/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java
index 63eb500..347718a 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java
@@ -30,7 +30,7 @@ import org.apache.logging.log4j.util.Supplier;
  * gets its own Logger named after its fully qualified class name (the default 
Logger name when obtained through the
  * {@link LogManager#getLogger()} method). Thus, the simplest way to use this 
would be like so:
  * </p>
- * 
+ *
  * <pre>
  * public class MyClass {
  *     private static final Logger LOGGER = LogManager.getLogger();
@@ -49,7 +49,7 @@ import org.apache.logging.log4j.util.Supplier;
  * Since 2.4, methods have been added to the {@code Logger} interface to 
support lambda expressions. The new methods
  * allow client code to lazily log messages without explicitly checking if the 
requested log level is enabled. For
  * example, previously one would write:
- * 
+ *
  * <pre>
  * // pre-Java 8 style optimization: explicitly check the log level
  * // to make sure the expensiveOperation() method is only called if necessary
@@ -59,7 +59,7 @@ import org.apache.logging.log4j.util.Supplier;
  * </pre>
  * <p>
  * With Java 8, the same effect can be achieved with a lambda expression:
- * 
+ *
  * <pre>
  * // Java-8 style optimization: no need to explicitly check the log level:
  * // the lambda expression is not evaluated if the TRACE level is not enabled
@@ -320,7 +320,7 @@ public interface Logger {
 
     /**
      * Logs entry to a method along with its parameters. For example,
-     * 
+     *
      * <pre>
      * public void doSomething(String foo, int bar) {
      *     LOGGER.entry(foo, bar);
@@ -332,11 +332,7 @@ public interface Logger {
      * bytecode manipulation tools. It can be rather tedious (and messy) to 
use this type of method manually.
      * </p>
      *
-     * @param params The parameters to the method. TODO Use of varargs results 
in array creation which can be a
-     *            substantial portion of no-op case. LogMF/LogSF provides 
several overrides to avoid vararg except in
-     *            edge cases. (RG) LogMF and LogSF implement these in LogXF 
which calls logger.callAppenders.
-     *            callAppenders is part of the implementation and cannot be 
used by the API. Adding more methods here
-     *            and in AbstractLogger is sufficient.
+     * @param params The parameters to the method.
      */
     void entry(Object... params);
 
@@ -413,11 +409,6 @@ public interface Logger {
      * @param message the message to log; the format depends on the message 
factory.
      * @param params parameters to the message.
      * @see #getMessageFactory()
-     *
-     *      TODO Likely to misinterpret existing log4j client code that 
intended to call info(Object,Throwable). Incurs
-     *      array creation expense on every call. (RG) I assume you meant 
error, not info. It isn't possible to be
-     *      misinterpreted as the previous method is for that signature. 
Methods should be added to avoid varargs for 1,
-     *      2 or 3 parameters.
      */
     void error(Marker marker, String message, Object... params);
 
@@ -529,11 +520,6 @@ public interface Logger {
      * @param message the message to log; the format depends on the message 
factory.
      * @param params parameters to the message.
      * @see #getMessageFactory()
-     *
-     *      TODO Likely to misinterpret existing log4j client code that 
intended to call info(Object,Throwable). Incurs
-     *      array creation expense on every call. (RG) I assume you meant 
error, not info. It isn't possible to be
-     *      misinterpreted as the previous method is for that signature. 
Methods should be added to avoid varargs for 1,
-     *      2 or 3 parameters.
      */
     void error(String message, Object... params);
 
@@ -583,7 +569,7 @@ public interface Logger {
 
     /**
      * Logs exiting from a method with the result. This may be coded as:
-     * 
+     *
      * <pre>
      * return LOGGER.exit(myResult);
      * </pre>
@@ -667,11 +653,6 @@ public interface Logger {
      * @param message the message to log; the format depends on the message 
factory.
      * @param params parameters to the message.
      * @see #getMessageFactory()
-     *
-     *      TODO Likely to misinterpret existing log4j client code that 
intended to call info(Object,Throwable). Incurs
-     *      array creation expense on every call.(RG) I assume you meant 
fatal, not info. It isn't possible to be
-     *      misinterpreted as the previous method is for that signature. 
Methods should be added to avoid varargs for 1,
-     *      2 or 3 parameters.
      */
     void fatal(Marker marker, String message, Object... params);
 
@@ -783,11 +764,6 @@ public interface Logger {
      * @param message the message to log; the format depends on the message 
factory.
      * @param params parameters to the message.
      * @see #getMessageFactory()
-     *
-     *      TODO Likely to misinterpret existing log4j client code that 
intended to call info(Object,Throwable). Incurs
-     *      array creation expense on every call.(RG) I assume you meant 
fatal, not info. It isn't possible to be
-     *      misinterpreted as the previous method is for that signature. 
Methods should be added to avoid varargs for 1,
-     *      2 or 3 parameters.
      */
     void fatal(String message, Object... params);
 
@@ -924,10 +900,6 @@ public interface Logger {
      * @param message the message to log; the format depends on the message 
factory.
      * @param params parameters to the message.
      * @see #getMessageFactory()
-     *
-     *      TODO Likely to misinterpret existing log4j client code that 
intended to call info(Object,Throwable). Incurs
-     *      array creation expense on every call. (RG) It isn't possible to be 
misinterpreted as the previous method is
-     *      for that signature. Methods should be added to avoid varargs for 
1, 2 or 3 parameters.
      */
     void info(Marker marker, String message, Object... params);
 
@@ -1039,10 +1011,6 @@ public interface Logger {
      * @param message the message to log; the format depends on the message 
factory.
      * @param params parameters to the message.
      * @see #getMessageFactory()
-     *
-     *      TODO Likely to misinterpret existing log4j client code that 
intended to call info(Object,Throwable). Incurs
-     *      array creation expense on every call. (RG) It isn't possible to be 
misinterpreted as the previous method is
-     *      for that signature. Methods should be added to avoid varargs for 
1, 2 or 3 parameters.
      */
     void info(String message, Object... params);
 
@@ -1470,7 +1438,7 @@ public interface Logger {
 
     /**
      * Logs an exception or error to be thrown. This may be coded as:
-     * 
+     *
      * <pre>
      * throw logger.throwing(Level.DEBUG, myException);
      * </pre>
@@ -1484,7 +1452,7 @@ public interface Logger {
 
     /**
      * Logs an exception or error to be thrown. This may be coded as:
-     * 
+     *
      * <pre>
      * throw logger.throwing(myException);
      * </pre>
@@ -1726,6 +1694,144 @@ public interface Logger {
     void trace(Supplier<?> msgSupplier, Throwable t);
 
     /**
+     * Logs entry to a method. Used when the method in question has no 
parameters or when the parameters should not be
+     * logged.
+     */
+    void traceEntry();
+
+    /**
+     * Logs entry to a method along with its parameters. For example,
+     *
+     * <pre>
+     * public void doSomething(String foo, int bar) {
+     *     LOGGER.traceEntry("Parameters: {} and {}", foo, bar);
+     *     // do something
+     * }
+     * </pre>
+     *
+     * @param format The format String for the parameters.
+     * @param params The parameters to the method.
+     */
+    void traceEntry(final String format, final Object... params);
+
+    /**
+     * Logs entry to a method along with its parameters. For example,
+     *
+     * <pre>
+     * public void doSomething(Request foo) {
+     *     LOGGER.traceEntry(()->gson.toJson(foo));
+     *     // do something
+     * }
+     * </pre>
+     *
+     * @param paramSuppliers The Suppliers for the parameters to the method.
+     */
+    void traceEntry(final Supplier<?>... paramSuppliers);
+
+    /**
+     * Logs entry to a method along with its parameters. For example,
+     *
+     * <pre>
+     * public void doSomething(String foo, int bar) {
+     *     LOGGER.traceEntry("Parameters: {} and {}", ()->gson.toJson(foo), 
()-> bar);
+     *     // do something
+     * }
+     * </pre>
+     *
+     * @param format The format String for the parameters.
+     * @param paramSuppliers The Suppliers for the parameters to the method.
+     */
+    void traceEntry(final String format, final Supplier<?>... paramSuppliers);
+
+    /**
+     * Logs entry to a method using a Message to describe the parameters.
+     * <pre>
+     * public void doSomething(Request foo) {
+     *     LOGGER.traceEntry(new JsonMessage(foo));
+     *     // do something
+     * }
+     * </pre>
+     *
+     * @param message The message.
+     */
+    void traceEntry(final Message message);
+
+    /**
+     * Logs entry to a method using a Message to describe the parameters.
+     * <pre>
+     * public void doSomething(Request foo) {
+     *     LOGGER.traceEntry(new JsonMessage(foo));
+     *     // do something
+     * }
+     * </pre>
+     *
+     * @param msgSupplier The Supplier of the Message.
+     */
+    void traceEntry(final MessageSupplier msgSupplier);
+
+    /**
+     * Logs exit from a method. Used for methods that do not return anything.
+     */
+    void traceExit();
+
+    /**
+     * Logs exiting from a method with the result. This may be coded as:
+     *
+     * <pre>
+     * return LOGGER.traceExit(myResult);
+     * </pre>
+     *
+     * @param <R> The type of the parameter and object being returned.
+     * @param result The result being returned from the method call.
+     * @return the result.
+     */
+    <R> R traceExit(R result);
+
+    /**
+     * Logs exiting from a method with the result. This may be coded as:
+     *
+     * <pre>
+     * return LOGGER.traceExit("Result: {}", myResult);
+     * </pre>
+     *
+     * @param <R> The type of the parameter and object being returned.
+     * @param format The format String for the result.
+     * @param result The result being returned from the method call.
+     * @return the result.
+     */
+    <R> R traceExit(final String format, final R result);
+
+    /**
+     * Logs exiting from a method with the result. Used when construction of 
the Message might be
+     * expensive. This may be coded as:
+     *
+     * <pre>
+     * return LOGGER.traceExit(myResult, () -> new 
ParameterizedMessage("MyResult: field1: {}, field2: {}",
+     *           myResult.field1.toString(), myResult.field2.toString());
+     * </pre>
+     *
+     * @param <R> The type of the parameter and object being returned.
+     * @param result The result being returned from the method call.
+     * @param messageSupplier The supplier of the Message.
+     * @return the result.
+     */
+    <R> R traceExit(final R result, final MessageSupplier messageSupplier);
+
+    /**
+     * Logs exiting from a method with the result. Allows custom formatting of 
the result. This may be coded as:
+     *
+     * <pre>
+     * return LOGGER.traceExit(myResult, new JsonMessage(myResult));
+     * </pre>
+     *
+     * @param <R> The type of the parameter and object being returned.
+     * @param result The result being returned from the method call.
+     * @param message The Message containing the formatted result.
+     * @return the result.
+     */
+    <R> R traceExit(final R result, final Message message);
+
+    /**
      * Logs a message with the specific Marker at the {@link Level#WARN WARN} 
level.
      *
      * @param marker the marker data specific to this log statement
@@ -1798,11 +1904,6 @@ public interface Logger {
      * @param message the message to log; the format depends on the message 
factory.
      * @param params parameters to the message.
      * @see #getMessageFactory()
-     *
-     *      TODO Likely to misinterpret existing log4j client code that 
intended to call info(Object,Throwable). Incurs
-     *      array creation expense on every call. (RG) I assume you meant 
warn, not info. It isn't possible to be
-     *      misinterpreted as the previous method is for that 
signature.Methods should be added to avoid varargs for 1,
-     *      2 or 3 parameters.
      */
     void warn(Marker marker, String message, Object... params);
 
@@ -1914,11 +2015,6 @@ public interface Logger {
      * @param message the message to log; the format depends on the message 
factory.
      * @param params parameters to the message.
      * @see #getMessageFactory()
-     *
-     *      TODO Likely to misinterpret existing log4j client code that 
intended to call info(Object,Throwable). Incurs
-     *      array creation expense on every call. (RG) I assume you meant 
warn, not info. It isn't possible to be
-     *      misinterpreted as the previous method is for that 
signature.Methods should be added to avoid varargs for 1,
-     *      2 or 3 parameters.
      */
     void warn(String message, Object... params);
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fcb2d1fd/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
----------------------------------------------------------------------
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
index dea99c7..ab74188 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
@@ -24,6 +24,7 @@ import org.apache.logging.log4j.MarkerManager;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.MessageFactory;
 import org.apache.logging.log4j.message.ParameterizedMessageFactory;
+import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.logging.log4j.message.StringFormattedMessage;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.LambdaUtil;
@@ -294,9 +295,47 @@ public abstract class AbstractLogger implements 
ExtendedLogger, Serializable {
         logIfEnabled(FQCN, Level.DEBUG, null, msgSupplier, t);
     }
 
+    /**
+     * Logs entry to a method with location information.
+     *
+     * @param fqcn The fully qualified class name of the <b>caller</b>.
+     * @param format Format String for the parameters.
+     * @param paramSuppliers The Suppliers of the parameters.
+     */
+    protected void enter(final String fqcn, final String format, final 
Supplier<?>... paramSuppliers) {
+        if (isEnabled(Level.TRACE, ENTRY_MARKER, (Object) null, null)) {
+            logMessage(fqcn, Level.TRACE, ENTRY_MARKER, entryMsg(format, 
paramSuppliers.length, paramSuppliers), null);
+        }
+    }
+
+    /**
+     * Logs entry to a method with location information.
+     *
+     * @param fqcn The fully qualified class name of the <b>caller</b>.
+     * @param format The format String for the parameters.
+     * @param params The parameters to the method.
+     */
+    protected void enter(final String fqcn, final String format, final 
Object... params) {
+        if (isEnabled(Level.TRACE, ENTRY_MARKER, (Object) null, null)) {
+            logMessage(fqcn, Level.TRACE, ENTRY_MARKER, entryMsg(format, 
params.length, params), null);
+        }
+    }
+
+    /**
+     * Logs entry to a method with location information.
+     *
+     * @param fqcn The fully qualified class name of the <b>caller</b>.
+     * @param msgSupplier The Supplier of the Message.
+     */
+    protected void enter(final String fqcn, final MessageSupplier msgSupplier) 
{
+        if (isEnabled(Level.TRACE, ENTRY_MARKER, (Object) null, null)) {
+            logMessage(fqcn, Level.TRACE, ENTRY_MARKER, new 
EntryMessage(msgSupplier.get()), null);
+        }
+    }
+
     @Override
     public void entry() {
-        entry(FQCN);
+        entry(FQCN, (String) null);
     }
 
     @Override
@@ -312,15 +351,28 @@ public abstract class AbstractLogger implements 
ExtendedLogger, Serializable {
      */
     protected void entry(final String fqcn, final Object... params) {
         if (isEnabled(Level.TRACE, ENTRY_MARKER, (Object) null, null)) {
-            logIfEnabled(fqcn, Level.TRACE, ENTRY_MARKER, 
entryMsg(params.length, params), null);
+            logMessage(fqcn, Level.TRACE, ENTRY_MARKER, entryMsg(null, 
params.length, params), null);
         }
     }
 
     protected Message entryMsg(final int count, final Object... params) {
+        return entryMsg(null, count, params);
+    }
+
+    protected Message entryMsg(final String format, final int count, final 
Object... params) {
         if (count == 0) {
-            return messageFactory.newMessage("entry");
+            if (format == null) {
+                return messageFactory.newMessage("entry");
+            } else {
+                return messageFactory.newMessage("entry: " + format);
+            }
+        }
+        final StringBuilder sb = new StringBuilder("entry");
+        if (format != null) {
+            sb.append(": ").append(format);
+            return messageFactory.newMessage(sb.toString(), params);
         }
-        final StringBuilder sb = new StringBuilder("entry params(");
+        sb.append(" params(");
         for (int i = 0; i < params.length; i++) {
             Object parm = params[i];
             sb.append(parm != null ? parm.toString() : "null");
@@ -332,6 +384,14 @@ public abstract class AbstractLogger implements 
ExtendedLogger, Serializable {
         return messageFactory.newMessage(sb.toString());
     }
 
+    protected Message entryMsg(final String format, final int count, final 
Supplier<?>... paramSuppliers) {
+        Object[] params = new Object[count];
+        for (int i = 0; i < count; i++) {
+            params[i] = paramSuppliers[i].get();
+        }
+        return entryMsg(format, count, params);
+    }
+
     @Override
     public void error(final Marker marker, final Message msg) {
         logIfEnabled(FQCN, Level.ERROR, marker, msg, null);
@@ -454,7 +514,7 @@ public abstract class AbstractLogger implements 
ExtendedLogger, Serializable {
 
     @Override
     public void exit() {
-        exit(FQCN, null);
+        exit(FQCN, (Object) null);
     }
 
     @Override
@@ -471,17 +531,36 @@ public abstract class AbstractLogger implements 
ExtendedLogger, Serializable {
      * @return the return value passed to this method.
      */
     protected <R> R exit(final String fqcn, final R result) {
-        if (isEnabled(Level.TRACE, EXIT_MARKER, (Object) null, null)) {
-            logIfEnabled(fqcn, Level.TRACE, EXIT_MARKER, exitMsg(result), 
null);
-        }
+        logIfEnabled(fqcn, Level.TRACE, EXIT_MARKER, exitMsg(null, result), 
null);
+        return result;
+    }
+
+    /**
+     * Logs exiting from a method with the result and location information.
+     *
+     * @param fqcn The fully qualified class name of the <b>caller</b>.
+     * @param <R> The type of the parameter and object being returned.
+     * @param result The result being returned from the method call.
+     * @return the return value passed to this method.
+     */
+    protected <R> R exit(final String fqcn, final String format, final R 
result) {
+        logIfEnabled(fqcn, Level.TRACE, EXIT_MARKER, exitMsg(format, result), 
null);
         return result;
     }
 
-    protected Message exitMsg(final Object result) {
+    protected Message exitMsg(final String format, final Object result) {
         if (result == null) {
-            return messageFactory.newMessage("exit");
+            if (format == null) {
+                return messageFactory.newMessage("exit");
+            }
+            return messageFactory.newMessage("exit: " + format);
+        } else  {
+            if (format == null) {
+                return messageFactory.newMessage("exit with(" + result + ')');
+            }
+            return messageFactory.newMessage("exit: " + format, result);
         }
-        return messageFactory.newMessage("exit with(" + result + ')');
+
     }
 
     @Override
@@ -1195,6 +1274,73 @@ public abstract class AbstractLogger implements 
ExtendedLogger, Serializable {
     }
 
     @Override
+    public void traceEntry() {
+        enter(FQCN, null, null);
+    }
+
+    @Override
+    public void traceEntry(final String format, final Object... params) {
+        enter(FQCN, format, params);
+    }
+
+
+    @Override
+    public void traceEntry(final Supplier<?>... paramSuppliers) {
+        enter(FQCN, null, paramSuppliers);
+    }
+
+    @Override
+    public void traceEntry(final String format, final Supplier<?>... 
paramSuppliers) {
+        enter(FQCN, format, paramSuppliers);
+    }
+
+
+    @Override
+    public void traceEntry(final Message message) {
+        enter(FQCN, new MessageSupplier() { @Override public Message get() { 
return message; }});
+    }
+
+    @Override
+    public void traceEntry(final MessageSupplier msgSupplier) {
+        enter(FQCN, msgSupplier);
+    }
+
+    @Override
+    public void traceExit() {
+        exit(FQCN, null, null);
+    }
+
+    @Override
+    public <R> R traceExit(final R result) {
+        return exit(FQCN, null, result);
+    }
+
+    @Override
+    public <R> R traceExit(final String format, final R result) {
+        return exit(FQCN, format, result);
+    }
+
+
+    @Override
+    public <R> R traceExit(final R result, final MessageSupplier 
messageSupplier) {
+        if (isEnabled(Level.TRACE, EXIT_MARKER, messageSupplier, null)) {
+            logMessage(FQCN, Level.TRACE, EXIT_MARKER, new MessageSupplier() {
+                public Message get() { return new 
ExitMessage(messageSupplier.get()); }; }, null);
+        }
+        return result;
+    }
+
+    @Override
+    public <R> R traceExit(final R result, final Message message) {
+        if (isEnabled(Level.TRACE, EXIT_MARKER, message, null)) {
+            logMessage(FQCN, Level.TRACE, EXIT_MARKER, new MessageSupplier() {
+                public Message get() { return new ExitMessage(message); }; }, 
null);
+        }
+        return result;
+    }
+
+
+    @Override
     public void warn(final Marker marker, final Message msg) {
         logIfEnabled(FQCN, Level.WARN, marker, msg, null);
     }
@@ -1313,4 +1459,65 @@ public abstract class AbstractLogger implements 
ExtendedLogger, Serializable {
     public void warn(final MessageSupplier msgSupplier, final Throwable t) {
         logIfEnabled(FQCN, Level.WARN, null, msgSupplier, t);
     }
+
+    private static class FlowMessage implements Message {
+
+        private static final long serialVersionUID = 7580175170272152912L;
+        private Message message;
+        private final String text;
+
+        FlowMessage(String text, Message message) {
+            this.message = message;
+            this.text = text;
+        }
+
+        @Override
+        public String getFormattedMessage() {
+            if (message != null) {
+                return text + ": " + message.getFormattedMessage();
+            }
+            return text;
+        }
+
+        @Override
+        public String getFormat() {
+            if (message != null) {
+                return text + ": " + message.getFormat();
+            }
+            return text;
+        }
+
+        @Override
+        public Object[] getParameters() {
+            if (message != null) {
+                return message.getParameters();
+            }
+            return null;
+        }
+
+        @Override
+        public Throwable getThrowable() {
+            if (message != null) {
+                return message.getThrowable();
+            }
+            return null;
+        }
+    }
+
+    private static class EntryMessage extends FlowMessage {
+
+        EntryMessage(Message message) {
+            super("entry", message);
+        }
+
+    }
+
+
+    private static class ExitMessage extends FlowMessage {
+
+        ExitMessage(Message message) {
+            super("exit", message);
+        }
+
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fcb2d1fd/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java 
b/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java
index a2d4ade..702146f 100644
--- a/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java
@@ -20,10 +20,13 @@ import java.util.Date;
 import java.util.List;
 import java.util.Locale;
 
+import org.apache.logging.log4j.message.JsonMessage;
+import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.ParameterizedMessageFactory;
 import org.apache.logging.log4j.message.SimpleMessageFactory;
 import org.apache.logging.log4j.message.StringFormatterMessageFactory;
 import org.apache.logging.log4j.message.StructuredDataMessage;
+import org.apache.logging.log4j.util.MessageSupplier;
 import org.apache.logging.log4j.util.Strings;
 import org.junit.Before;
 import org.junit.Test;
@@ -58,6 +61,27 @@ public class LoggerTest {
     }
 
     @Test
+    public void jsonFlow1() {
+        logger.traceEntry(new MessageSupplier() {
+            @Override
+            public Message get() {
+                return new JsonMessage(System.getProperties());
+            }
+        });
+        final Response response = new Response(-1, "Generic error");
+        logger.traceExit(response, new MessageSupplier() {
+            @Override public Message get() {
+                return new JsonMessage(response);
+            }
+        });
+        assertEquals(2, results.size());
+        assertThat("Incorrect Entry", results.get(0), startsWith("ENTRY[ FLOW 
] TRACE entry"));
+        assertThat("Missing entry data", results.get(0), 
containsString("\"java.runtime.name\":"));
+        assertThat("incorrect Exit", results.get(1), startsWith("EXIT[ FLOW ] 
TRACE exit"));
+        assertThat("Missing exit data", results.get(1), 
containsString("\"message\":\"Generic error\""));
+    }
+
+    @Test
     public void catching() {
         try {
             throw new NullPointerException();
@@ -397,4 +421,31 @@ public class LoggerTest {
         assertThat("Incorrect Throwing",
                 results.get(0), startsWith("THROWING[ EXCEPTION ] ERROR 
throwing java.lang.IllegalArgumentException: Test Exception"));
     }
+
+
+    private class Response {
+        int status;
+        String message;
+
+        public Response(int status, String message) {
+            this.status = status;
+            this.message = message;
+        }
+
+        public int getStatus() {
+            return status;
+        }
+
+        public void setStatus(int status) {
+            this.status = status;
+        }
+
+        public String getMessage() {
+            return message;
+        }
+
+        public void setMessage(String message) {
+            this.message = message;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fcb2d1fd/log4j-api/src/test/java/org/apache/logging/log4j/message/JsonMessage.java
----------------------------------------------------------------------
diff --git 
a/log4j-api/src/test/java/org/apache/logging/log4j/message/JsonMessage.java 
b/log4j-api/src/test/java/org/apache/logging/log4j/message/JsonMessage.java
new file mode 100644
index 0000000..9183c94
--- /dev/null
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/message/JsonMessage.java
@@ -0,0 +1,58 @@
+/*
+ * 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.message;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Converts an Object to a JSON String.
+ */
+public class JsonMessage implements Message {
+
+    private static final ObjectMapper mapper = new ObjectMapper();
+    private final Object object;
+
+    public JsonMessage(final Object object) {
+        this.object = object;
+    }
+
+    @Override
+    public String getFormattedMessage() {
+        try {
+            return mapper.writeValueAsString(object);
+        } catch (JsonProcessingException ex) {
+            System.err.println("Caught exception: " + ex.getMessage());
+            return object.toString();
+        }
+    }
+
+    @Override
+    public String getFormat() {
+        return object.toString();
+    }
+
+    @Override
+    public Object[] getParameters() {
+        return new Object[] {object};
+    }
+
+    @Override
+    public Throwable getThrowable() {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fcb2d1fd/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index e2cc4c4..a302ce3 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -24,6 +24,9 @@
   </properties>
   <body>
     <release version="2.6" date="201Y-MM-DD" description="GA Release 2.6">
+      <action issue="LOG4J2-1255" dev="rgoers" type="update">
+        Add enhanced entry and exit methods.
+      </action>
       <action issue="LOG4J2-124" dev="rgoers" type="add">
         Add shutdown methods to LogManager.
       </action>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fcb2d1fd/src/site/xdoc/manual/flowtracing.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/manual/flowtracing.xml 
b/src/site/xdoc/manual/flowtracing.xml
index a7a015f..666e81b 100644
--- a/src/site/xdoc/manual/flowtracing.xml
+++ b/src/site/xdoc/manual/flowtracing.xml
@@ -40,18 +40,26 @@
               <li>help educate new developers in learning the application.</li>
             </ul>
             <p>
-              The two most used methods are the entry() and exit() methods. 
entry() should be placed at the
-              beginning of methods, except perhaps for simple getters and 
setters. entry() can be called
-              passing from 0 to 4 parameters. Typically these will be 
parameters passed to the method.
-              The entry() method logs with a level of TRACE and uses a Marker 
with a name of "ENTER" which
-              is also a "FLOW" Marker.
+              The most used methods are the entry() or traceEntry() and exit() 
or traceExit() methods. entry()
+              or traceEntry() should be placed at the beginning of methods, 
except perhaps for simple
+              getters and setters. entry() can be calledpassing from 0 to 4 
parameters. Typically these will be
+              parameters passed to the method. traceEntry() can be passed a 
format String and a variable list of
+              parameters, or a Message. The entry() and traceEntry() methods 
log with a level of TRACE and uses
+              a Marker with a name of "ENTER" which is also a "FLOW" Marker 
and all message strings will begin
+              with "event", even if a format String or Message is used.
             </p>
+            <p>The main difference between the entry and traceEntry methods is 
that the entry method accepts a
+              variable list of objects where presumably each is a method 
parameter. The traceEntry method
+              accepts a format string followed by a variable list of objects, 
presumably included in the
+              format String. It is not possible to have a single method that 
includes both of these as it would
+              be ambiguous whether the first String is a parameter or a format 
String.</p>
             <p>
-              The exit() method should be placed before any return statement 
or as the last statement of
-              methods without a return. exit() can be called with or without a 
parameter. Typically, methods
-              that return void will use exit() while methods that return an 
Object will use exit(Object obj).
-              The exit() method logs with a level of TRACE and uses a Marker 
with a name of "EXIT" which is
-              also a "FLOW" Marker.
+              An exit() or traceExit() method should be placed before any 
return statement or as the last statement of
+              methods without a return. exit() and traceExit() can be called 
with or without a parameter. Typically,
+              methods that return void will use exit() or traceExit() while 
methods that return an Object will use
+              exit(Object obj) or traceExit(object, new SomeMessage(object)). 
The exit() and traceExit() methods log
+              with a level of TRACE and uses a Marker with a name of "EXIT" 
which is also a "FLOW" Marker and all
+              message strings will begin with "exit", even if a format String 
or Message is used.
             </p>
             <p>
               The throwing() method can be used by an application when it is 
throwing an exception that is
@@ -87,6 +95,17 @@ public class TestService {
     };
     private Random rand = new Random(1);
 
+    public void setMessages(String[] messages) {
+        logger.traceEntry(new JsonMessage(messages));
+        this.messages = messages;
+        logger.traceExit();
+    }
+
+    public String[] getMessages() {
+        logger.traceEntry();
+        return logger.traceExit(messages, new JsonMessage(messages));
+    }
+
     public String retrieveMessage() {
         logger.entry();
 

Reply via email to