[ 
https://issues.apache.org/jira/browse/LOG4J2-1255?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15102470#comment-15102470
 ] 

Gary Gregory commented on LOG4J2-1255:
--------------------------------------

Here's how I do it. You can omit the API counting stuff (TRACE_ENTER_MAP).

{code:java}
package ...

import java.util.Arrays;
import java.util.IllegalFormatException;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.spi.AbstractLogger;
import org.apache.logging.log4j.status.StatusLogger;

/**
 * Performs flow logging with more information than stock Log4j.
 */
public final class DvFlowLogger {

    private static final String _FLOW_ENTER = "Enter";
    private static final String _FLOW_EXIT = "Exit";
    private static final String _RETURN_SEPARATOR = " : ";
    private static final String _STRING_SEPARATOR = "\"";
    private static boolean CountTraceEnter = false;

    /**
     * Caches flow loggers like Log4j caches Loggers.
     */
    private static final Map<Logger, DvFlowLogger> loggerMap = new 
WeakHashMap<>();

    private static final int RETURN_BUFFER_MIN_SIZE = 1 + _FLOW_EXIT.length() + 
_RETURN_SEPARATOR.length();

    private static final ConcurrentHashMap<String, Integer> TRACE_ENTER_MAP = 
new ConcurrentHashMap<>();

    public static void clearTraceEnterMap() {
        TRACE_ENTER_MAP.clear();
    }

    public static DvFlowLogger createFlowLogger(final Logger logger) {
        // Caches flow loggers like Log4j caches Loggers.
        // Do not bother with synchronization for now.
        DvFlowLogger dvFlowLogger = loggerMap.get(logger);
        if (dvFlowLogger != null) {
            return dvFlowLogger;
        }
        dvFlowLogger = new DvFlowLogger(logger);
        loggerMap.put(logger, dvFlowLogger);
        return dvFlowLogger;
    }

    public static boolean getCountTraceEnter() {
        return CountTraceEnter;
    }

    public static Map<String, Integer> getTraceEnterMap() {
        return TRACE_ENTER_MAP;
    }

    public static void logTraceEnterMap(final Logger logger) {
        if (logger == null || !logger.isDebugEnabled()) {
            return;
        }
        logger.debug("JDBC API trace enter map size: %,d", 
TRACE_ENTER_MAP.size());
        final Map<String, Integer> sortedMap = new TreeMap<>(TRACE_ENTER_MAP);
        for (final Map.Entry<String, Integer> entry : sortedMap.entrySet()) {
            logger.debug("%s = %s", entry.getKey(), entry.getValue());
        }
    }

    public static void setCountTraceEnter(final boolean countTraceEnter) {
        CountTraceEnter = countTraceEnter;
    }

    private final Logger logger;

    public DvFlowLogger(final Logger logger) {
        super();
        Objects.requireNonNull(logger, "Logger must not be null");
        this.logger = logger;
    }

    StringBuilder appendMethodFlow(final StringBuilder sb, final String flow, 
final String method) {
        sb.append(flow);
        sb.append(' ');
        sb.append(method);
        return sb;
    }

    private void countTraceEnter(final Object self, final String method) {
        if (!CountTraceEnter) {
            return;
        }
        // Update pattern found here: 
http://www.javamex.com/tutorials/synchronization_concurrency_8_hashmap2.shtml
        // TODO Review
        final String key = self.getClass().getSimpleName() + "." + method;
        Integer oldVal, newVal;
        do {
            oldVal = TRACE_ENTER_MAP.get(key);
            newVal = oldVal == null ? 1 : oldVal + 1;
            if (oldVal == null) {
                TRACE_ENTER_MAP.put(key, newVal);
                oldVal = newVal;
            }
        } while (!TRACE_ENTER_MAP.replace(key, oldVal, newVal));
    }

    public Logger getLogger() {
        return logger;
    }

    String toFormattedMethod(final Object obj, final String messagePattern, 
final Object... args) {
        final String simpleName = DvLoggerFactory.toSimpleName(obj);
        final String formattedMethod = toFormattedString(messagePattern, args);
        final StringBuilder sb = new StringBuilder(simpleName.length() + 12 + 
formattedMethod.length());
        sb.append(simpleName);
        sb.append('@');
        sb.append(Integer.toHexString(Objects.hashCode(obj)));
        sb.append('.');
        sb.append(formattedMethod);
        return sb.toString();
    }

    String toFormattedString(final String messagePattern, final Object... args) 
{
        if (args != null) {
            try {
                return String.format(messagePattern, args);
            } catch (final IllegalFormatException e) {
                StatusLogger.getLogger().error("Unable to format msg: " + 
messagePattern, e);
            }
        }
        return messagePattern;
    }

    String toMethodEntry(final String method) {
        return toMethodFlow(_FLOW_ENTER, method);
    }

    String toMethodExit(final String method) {
        return toMethodFlow(_FLOW_EXIT, method);
    }

    String toMethodExit(final String method, final Object value) {
        final String valueToString = value instanceof CharSequence ? 
_STRING_SEPARATOR + value + _STRING_SEPARATOR : String.valueOf(value);
        final int capacity = method.length() + RETURN_BUFFER_MIN_SIZE + 
valueToString.length();
        return appendMethodFlow(new StringBuilder(capacity), _FLOW_EXIT, 
method).append(_RETURN_SEPARATOR).append(valueToString).toString();
    }

    String toMethodFlow(final String flow, final String method) {
        final int capacity = flow.length() + 1 + method.length();
        return appendMethodFlow(new StringBuilder(capacity), flow, 
method).toString();
    }

    public String traceEntry(final Object obj, final String method) {
        countTraceEnter(obj, method);
        if (logger.isTraceEnabled()) {
            final String formattedMethod = toFormattedMethod(obj, method);
            logger.trace(AbstractLogger.ENTRY_MARKER, 
toMethodEntry(formattedMethod));
            return formattedMethod;
        }
        return method;
    }

    public String traceEntry(final Object obj, final String method, final 
Object... args) {
        countTraceEnter(obj, method);
        if (logger.isTraceEnabled()) {
            final String formattedMethod = toFormattedMethod(obj, method, args);
            logger.trace(AbstractLogger.ENTRY_MARKER, 
toMethodEntry(formattedMethod));
            return formattedMethod;
        }
        return method;
    }

    public String traceEntry(final Object obj, final String method, final 
Object arg0) {
        countTraceEnter(obj, method);
        if (logger.isTraceEnabled()) {
            final String formattedMethod = toFormattedMethod(obj, method, arg0);
            logger.trace(AbstractLogger.ENTRY_MARKER, 
toMethodEntry(formattedMethod));
            return formattedMethod;
        }
        return method;
    }

    public String traceEntry(final Object obj, final String method, final 
Object arg0, final int[] arg1) {
        countTraceEnter(obj, method);
        if (logger.isTraceEnabled()) {
            final String formattedMethod = toFormattedMethod(obj, method, arg0, 
Arrays.toString(arg1));
            logger.trace(AbstractLogger.ENTRY_MARKER, 
toMethodEntry(formattedMethod));
            return formattedMethod;
        }
        return method;
    }

    public String traceEntry(final Object obj, final String method, final 
Object arg0, final Object arg1) {
        countTraceEnter(obj, method);
        if (logger.isTraceEnabled()) {
            final String formattedMethod = toFormattedMethod(obj, method, arg0, 
arg1);
            logger.trace(AbstractLogger.ENTRY_MARKER, 
toMethodEntry(formattedMethod));
            return formattedMethod;
        }
        return method;
    }

    public String traceEntry(final Object obj, final String method, final 
Object arg0, final Object arg1, final Object arg2) {
        countTraceEnter(obj, method);
        if (logger.isTraceEnabled()) {
            final String formattedMethod = toFormattedMethod(obj, method, arg0, 
arg1, arg2);
            logger.trace(AbstractLogger.ENTRY_MARKER, 
toMethodEntry(formattedMethod));
            return formattedMethod;
        }
        return method;
    }

    public String traceEntry(final Object obj, final String method, final 
Object arg0, final String[] arg1) {
        countTraceEnter(obj, method);
        if (logger.isTraceEnabled()) {
            final String formattedMethod = toFormattedMethod(obj, method, arg0, 
Arrays.toString(arg1));
            logger.trace(AbstractLogger.ENTRY_MARKER, 
toMethodEntry(formattedMethod));
            return formattedMethod;
        }
        return method;
    }

    public void traceExit(final String method) {
        if (logger.isTraceEnabled()) {
            logger.trace(AbstractLogger.EXIT_MARKER, toMethodExit(method));
        }
    }

    public <T> T traceExit(final String method, final T value) {
        if (logger.isTraceEnabled()) {
            logger.trace(AbstractLogger.EXIT_MARKER, toMethodExit(method, 
value));
        }
        return value;
    }

}
{code}

> Logger.entry and Logger.exit should support Messages.
> -----------------------------------------------------
>
>                 Key: LOG4J2-1255
>                 URL: https://issues.apache.org/jira/browse/LOG4J2-1255
>             Project: Log4j 2
>          Issue Type: Improvement
>          Components: API
>    Affects Versions: 2.5
>            Reporter: Ralph Goers
>            Assignee: Ralph Goers
>
> Logger.entry and Logger.exit currently do not support Message objects. This 
> reduces the flexibility of what can be logged on entry and exit to methods.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to