All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.sshd.common.util.logging.LoggingUtils Maven / Gradle / Ivy

The newest version!
/*
 * 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.sshd.common.util.logging;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.logging.Level;

import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.NumberUtils;
import org.apache.sshd.common.util.ReflectionUtils;
import org.slf4j.Logger;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;

/**
 * @author Apache MINA SSHD Project
 */
public final class LoggingUtils {
    public static final Set SLF4J_LEVELS
            = Collections.unmodifiableSet(EnumSet.allOf(org.slf4j.event.Level.class));

    private LoggingUtils() {
        throw new UnsupportedOperationException("No instance");
    }

    public static org.slf4j.event.Level slf4jLevelFromName(String name) {
        return GenericUtils.isEmpty(name)
                ? null
                : SLF4J_LEVELS.stream()
                        .filter(l -> name.equalsIgnoreCase(l.name()))
                        .findAny()
                        .orElse(null);
    }

    /**
     * Scans using reflection API for all fields that are {@code public static final} that start with the given common
     * prefix (case sensitive) and are of type {@link Number}.
     *
     * @param  clazz        The {@link Class} to query
     * @param  commonPrefix The expected common prefix
     * @return              A {@link NavigableMap} of all the matching fields, where key=the field's {@link Integer}
     *                      value and mapping=the field's name
     * @see                 #generateMnemonicMap(Class, Predicate)
     */
    public static NavigableMap generateMnemonicMap(Class clazz, final String commonPrefix) {
        return generateMnemonicMap(clazz, f -> {
            String name = f.getName();
            return name.startsWith(commonPrefix);
        });
    }

    /**
     * Scans using reflection API for all numeric {@code public static final} fields that are also accepted by
     * the predicate. Any field that is not such or fail to retrieve its value, or has a duplicate value is
     * silently skipped.
     *
     * @param  clazz    The {@link Class} to query
     * @param  acceptor The {@link Predicate} used to decide whether to process the {@link Field} (besides being a
     *                  {@link Number} and {@code public static final}).
     * @return          A {@link NavigableMap} of all the matching fields, where key=the field's {@link Integer} value
     *                  and mapping=the field's name
     * @see             #getMnemonicFields(Class, Predicate)
     */
    public static NavigableMap generateMnemonicMap(Class clazz, Predicate acceptor) {
        Collection fields = getMnemonicFields(clazz, acceptor);
        if (GenericUtils.isEmpty(fields)) {
            return Collections.emptyNavigableMap();
        }

        NavigableMap result = new TreeMap<>(Comparator.naturalOrder());
        for (Field f : fields) {
            String name = f.getName();
            try {
                Number value = (Number) f.get(null);
                String prev = result.put(NumberUtils.toInteger(value), name);
                if (prev != null) {
                    // noinspection UnnecessaryContinue
                    continue; // debug breakpoint
                }
            } catch (Exception e) {
                // noinspection UnnecessaryContinue
                continue; // debug breakpoint
            }
        }

        return result;
    }

    /**
     * Scans using reflection API for all numeric {@code public static final} fields that have a common prefix
     * and whose value is used by several of the other matching fields
     *
     * @param  clazz        The {@link Class} to query
     * @param  commonPrefix The expected common prefix
     * @return              A {@link Map} of all the mnemonic fields names whose value is the same as other fields in
     *                      this map. The key is the field's name and value is its associated opcode.
     * @see                 #getAmbiguousMenmonics(Class, Predicate)
     */
    public static Map getAmbiguousMenmonics(Class clazz, String commonPrefix) {
        return getAmbiguousMenmonics(clazz, f -> {
            String name = f.getName();
            return name.startsWith(commonPrefix);
        });
    }

    /**
     * Scans using reflection API for all numeric {@code public static final} fields that are also accepted by
     * the predicate and whose value is used by several of the other matching fields
     *
     * @param  clazz    The {@link Class} to query
     * @param  acceptor The {@link Predicate} used to decide whether to process the {@link Field} (besides being a
     *                  {@link Number} and {@code public static final}).
     * @return          A {@link Map} of all the mnemonic fields names whose value is the same as other fields in this
     *                  map. The key is the field's name and value is its associated opcode.
     * @see             #getMnemonicFields(Class, Predicate)
     */
    public static Map getAmbiguousMenmonics(Class clazz, Predicate acceptor) {
        Collection fields = getMnemonicFields(clazz, acceptor);
        if (GenericUtils.isEmpty(fields)) {
            return Collections.emptyMap();
        }

        Map result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
        Map> opcodesMap = new TreeMap<>(Comparator.naturalOrder());
        for (Field f : fields) {
            String name = f.getName();
            try {
                Number value = (Number) f.get(null);
                Integer key = NumberUtils.toInteger(value);
                List nameList = opcodesMap.get(key);
                if (nameList == null) {
                    nameList = new ArrayList<>();
                    opcodesMap.put(key, nameList);
                }
                nameList.add(name);

                int numOpcodes = nameList.size();
                if (numOpcodes > 1) {
                    result.put(name, key);
                    if (numOpcodes == 2) { // add the 1st name as well
                        result.put(nameList.get(0), key);
                    }
                }
            } catch (Exception e) {
                continue; // debug breakpoint
            }
        }

        return result;
    }

    /**
     * Scans using reflection API for all numeric {@code public static final} fields that are also accepted by
     * the predicate.
     *
     * @param  clazz    The {@link Class} to query
     * @param  acceptor The {@link Predicate} used to decide whether to process the {@link Field} (besides being a
     *                  {@link Number} and {@code public static final}).
     * @return          A {@link Collection} of all the fields that have satisfied all conditions
     */
    public static Collection getMnemonicFields(Class clazz, Predicate acceptor) {
        return ReflectionUtils.getMatchingFields(clazz, f -> {
            int mods = f.getModifiers();
            if ((!Modifier.isPublic(mods)) || (!Modifier.isStatic(mods)) || (!Modifier.isFinal(mods))) {
                return false;
            }

            Class type = f.getType();
            if (!NumberUtils.isNumericClass(type)) {
                return false;
            }

            return acceptor.test(f);
        });
    }

    public static SimplifiedLog wrap(Logger logger) {
        if (logger == null) {
            return SimplifiedLog.EMPTY;
        } else {
            return new SimplifiedLog() {
                @Override
                public void log(Level level, Object message, Throwable t) {
                    if (isEnabledLevel(level)) {
                        logMessage(logger, level, message, t);
                    }

                }

                @Override
                public boolean isEnabledLevel(Level level) {
                    return isLoggable(logger, level);
                }
            };
        }
    }

    // NOTE: assume that level enabled has been checked !!!
    public static void logMessage(Logger logger, Level level, Object message, Throwable t) {
        if ((logger == null) || (level == null) || Level.OFF.equals(level)) {
            return;
        } else if (Level.SEVERE.equals(level)) {
            logger.error(Objects.toString(message), t);
        } else if (Level.WARNING.equals(level)) {
            logger.warn(Objects.toString(message), t);
        } else if (Level.INFO.equals(level) || Level.ALL.equals(level)) {
            logger.info(Objects.toString(message), t);
        } else if (Level.CONFIG.equals(level) || Level.FINE.equals(level)) {
            logger.debug(Objects.toString(message), t);
        } else {
            logger.trace(Objects.toString(message), t);
        }
    }

    /**
     * @param  logger The {@link Logger} instance - ignored if {@code null}
     * @param  level  The validate log {@link Level} - ignored if {@code null}
     * @return
     *                

* {@code true} if the level is enabled for the logger. The mapping of the level to the logger is as * follows: *

*
    *
  • {@link Level#OFF} always returns {@code false}
  • *
  • {@link Level#SEVERE} returns {@link Logger#isErrorEnabled()}
  • *
  • {@link Level#WARNING} returns {@link Logger#isWarnEnabled()}
  • *
  • {@link Level#INFO} and {@link Level#ALL} returns {@link Logger#isInfoEnabled()}
  • *
  • {@link Level#CONFIG} and {@link Level#FINE} returns {@link Logger#isDebugEnabled()}
  • *
  • All other levels return {@link Logger#isTraceEnabled()}
  • *
*/ public static boolean isLoggable(Logger logger, Level level) { if ((logger == null) || (level == null) || Level.OFF.equals(level)) { return false; } else if (Level.SEVERE.equals(level)) { return logger.isErrorEnabled(); } else if (Level.WARNING.equals(level)) { return logger.isWarnEnabled(); } else if (Level.INFO.equals(level) || Level.ALL.equals(level)) { return logger.isInfoEnabled(); } else if (Level.CONFIG.equals(level) || Level.FINE.equals(level)) { return logger.isDebugEnabled(); } else { return logger.isTraceEnabled(); } } /** * @param Generic message type consumer * @param logger The {@link Logger} instance to use * @param level The log {@link Level} mapped as follows:
* *
    *
  • {@link Level#OFF} - {@link #nologClosure(Logger)}
  • *
  • {@link Level#SEVERE} - {@link #errorClosure(Logger)}
  • *
  • {@link Level#WARNING} - {@link #warnClosure(Logger)}
  • *
  • {@link Level#INFO}/{@link Level#ALL} - {@link #infoClosure(Logger)}
  • *
  • {@link Level#CONFIG}/{@link Level#FINE} - {@link #debugClosure(Logger)}
  • *
  • All others - {@link #traceClosure(Logger)}
  • *
* @return A consumer whose {@link Consumer#accept(Object)} method logs the {@link String#valueOf(Object)} * value of its argument if the specific level is enabled */ public static Consumer loggingClosure(Logger logger, Level level) { return loggingClosure(logger, level, null); } public static Consumer loggingClosure(Logger logger, Level level, Throwable t) { Objects.requireNonNull(level, "No level provided"); if (Level.OFF.equals(level)) { return nologClosure(logger); } else if (Level.SEVERE.equals(level)) { return errorClosure(logger, t); } else if (Level.WARNING.equals(level)) { return warnClosure(logger, t); } else if (Level.INFO.equals(level) || Level.ALL.equals(level)) { return infoClosure(logger, t); } else if (Level.CONFIG.equals(level) || Level.FINE.equals(level)) { return debugClosure(logger, t); } else { return traceClosure(logger, t); } } /** * @param Generic message type consumer * @param logger The {@link Logger} instance to use * @return A consumer whose {@link Consumer#accept(Object)} method logs nothing when invoked */ public static Consumer nologClosure(Logger logger) { Objects.requireNonNull(logger, "No logger provided"); return t -> { /* do nothing */ }; } /** * @param Generic message type consumer * @param logger The {@link Logger} instance to use * @return A consumer whose {@link Consumer#accept(Object)} method logs the {@link String#valueOf(Object)} * value of its argument if {@link Logger#isErrorEnabled()} */ public static Consumer errorClosure(Logger logger) { return errorClosure(logger, null); } /** * @param Generic message type consumer * @param logger The {@link Logger} instance to use * @param thrown A {@link Throwable} to attach to the message - ignored if {@code null} * @return A consumer whose {@link Consumer#accept(Object)} method logs the {@link String#valueOf(Object)} * value of its argument if {@link Logger#isErrorEnabled()} */ public static Consumer errorClosure(Logger logger, Throwable thrown) { Objects.requireNonNull(logger, "No logger provided"); return new Consumer() { @Override public void accept(T input) { if (logger.isErrorEnabled()) { String msg = String.valueOf(input); if (thrown == null) { logger.error(msg); } else { logger.error(msg, thrown); } } } @Override public String toString() { return "ERROR"; } }; } /** * @param Generic message type consumer * @param logger The {@link Logger} instance to use * @return A consumer whose {@link Consumer#accept(Object)} method logs the {@link String#valueOf(Object)} * value of its argument if {@link Logger#isWarnEnabled()} */ public static Consumer warnClosure(Logger logger) { return warnClosure(logger, null); } /** * @param Generic message type consumer * @param logger The {@link Logger} instance to use * @param thrown A {@link Throwable} to attach to the message - ignored if {@code null} * @return A consumer whose {@link Consumer#accept(Object)} method logs the {@link String#valueOf(Object)} * value of its argument if {@link Logger#isWarnEnabled()} */ public static Consumer warnClosure(Logger logger, Throwable thrown) { Objects.requireNonNull(logger, "No logger provided"); return new Consumer() { @Override public void accept(T input) { if (logger.isWarnEnabled()) { String msg = String.valueOf(input); if (thrown == null) { logger.warn(msg); } else { logger.warn(msg, thrown); } } } @Override public String toString() { return "WARN"; } }; } /** * @param Generic message type consumer * @param logger The {@link Logger} instance to use * @return A consumer whose {@link Consumer#accept(Object)} method logs the {@link String#valueOf(Object)} * value of its argument if {@link Logger#isInfoEnabled()} */ public static Consumer infoClosure(Logger logger) { return infoClosure(logger, null); } /** * @param Generic message type consumer * @param logger The {@link Logger} instance to use * @param thrown A {@link Throwable} to attach to the message - ignored if {@code null} * @return A consumer whose {@link Consumer#accept(Object)} method logs the {@link String#valueOf(Object)} * value of its argument if {@link Logger#isInfoEnabled()} */ public static Consumer infoClosure(Logger logger, Throwable thrown) { Objects.requireNonNull(logger, "No logger provided"); return new Consumer() { @Override public void accept(T input) { if (logger.isInfoEnabled()) { String msg = String.valueOf(input); if (thrown == null) { logger.info(msg); } else { logger.info(msg, thrown); } } } @Override public String toString() { return "INFO"; } }; } /** * @param Generic message type consumer * @param logger The {@link Logger} instance to use * @return A consumer whose {@link Consumer#accept(Object)} method logs the {@link String#valueOf(Object)} * value of its argument if {@link Logger#isDebugEnabled()} */ public static Consumer debugClosure(Logger logger) { return debugClosure(logger, null); } /** * @param Generic message type consumer * @param logger The {@link Logger} instance to use * @param thrown A {@link Throwable} to attach to the message - ignored if {@code null} * @return A consumer whose {@link Consumer#accept(Object)} method logs the {@link String#valueOf(Object)} * value of its argument if {@link Logger#isDebugEnabled()} */ public static Consumer debugClosure(Logger logger, Throwable thrown) { Objects.requireNonNull(logger, "No logger provided"); return new Consumer() { @Override public void accept(T input) { if (logger.isDebugEnabled()) { String msg = String.valueOf(input); if (thrown == null) { logger.debug(msg); } else { logger.debug(msg, thrown); } } } @Override public String toString() { return "DEBUG"; } }; } /** * @param Generic message type consumer * @param logger The {@link Logger} instance to use * @return A consumer whose {@link Consumer#accept(Object)} method logs the {@link String#valueOf(Object)} * value of its argument if {@link Logger#isTraceEnabled()} */ public static Consumer traceClosure(Logger logger) { return traceClosure(logger, null); } /** * @param Generic message type consumer * @param logger The {@link Logger} instance to use * @param thrown A {@link Throwable} to attach to the message - ignored if {@code null} * @return A consumer whose {@link Consumer#accept(Object)} method logs the {@link String#valueOf(Object)} * value of its argument if {@link Logger#isTraceEnabled()} */ public static Consumer traceClosure(Logger logger, Throwable thrown) { Objects.requireNonNull(logger, "No logger provided"); return new Consumer() { @Override public void accept(T input) { if (logger.isTraceEnabled()) { String msg = String.valueOf(input); if (thrown == null) { logger.trace(msg); } else { logger.trace(msg, thrown); } } } @Override public String toString() { return "TRACE"; } }; } /** * Formats an {@code slf4j} message using its formatting structure - mainly the usage of positional arguments * - e.g., "Value1={}, Value2={}, ..." * * @param format The formatting instructions - ignored if {@code null}/empty * @param arguments The formatting arguments - ignored if {@code null}/empty * @return The formatted message - or the format itself if no arguments or no format string */ public static String formatMessage(String format, Object... arguments) { if (GenericUtils.isEmpty(format) || GenericUtils.isEmpty(arguments)) { return format; } FormattingTuple tuple = MessageFormatter.arrayFormat(format, arguments, null); return tuple.getMessage(); } public static void debug(Logger log, String message, Object o1, Object o2, Throwable t) { if (log.isTraceEnabled() && (t != null)) { log.debug(message, o1, o2, t); } else if (log.isDebugEnabled()) { log.debug(message, o1, o2); } } public static void debug(Logger log, String message, Object o1, Object o2, Object o3, Throwable t) { if (log.isTraceEnabled() && (t != null)) { log.debug(message, o1, o2, o3, t); } else if (log.isDebugEnabled()) { log.debug(message, o1, o2, o3); } } public static void debug(Logger log, String message, Object o1, Object o2, Object o3, Object o4, Throwable t) { if (log.isTraceEnabled() && (t != null)) { log.debug(message, o1, o2, o3, o4, t); } else if (log.isDebugEnabled()) { log.debug(message, o1, o2, o3, o4); } } public static void debug(Logger log, String message, Object o1, Object o2, Object o3, Object o4, Object o5, Throwable t) { if (log.isTraceEnabled() && (t != null)) { log.debug(message, o1, o2, o3, o4, o5, t); } else if (log.isDebugEnabled()) { log.debug(message, o1, o2, o3, o4, o5); } } @SuppressWarnings("all") public static void debug( Logger log, String message, Object o1, Object o2, Object o3, Object o4, Object o5, Object o6, Throwable t) { if (log.isTraceEnabled() && (t != null)) { log.debug(message, o1, o2, o3, o4, o5, o6, t); } else if (log.isDebugEnabled()) { log.debug(message, o1, o2, o3, o4, o5, o6); } } public static void info(Logger log, String message, Object o1, Object o2, Throwable t) { if (log.isDebugEnabled() && (t != null)) { log.info(message, o1, o2, t); } else { log.info(message, o1, o2); } } public static void info(Logger log, String message, Object o1, Object o2, Object o3, Throwable t) { if (log.isDebugEnabled() && (t != null)) { log.info(message, o1, o2, o3, t); } else { log.info(message, o1, o2, o3); } } public static void warn(Logger log, String message, Object o1, Object o2, Throwable t) { if (log.isDebugEnabled() && (t != null)) { log.warn(message, o1, o2, t); } else { log.warn(message, o1, o2); } } public static void warn(Logger log, String message, Object o1, Object o2, Object o3, Throwable t) { if (log.isDebugEnabled() && (t != null)) { log.warn(message, o1, o2, o3, t); } else { log.warn(message, o1, o2, o3); } } public static void warn(Logger log, String message, Object o1, Object o2, Object o3, Object o4, Throwable t) { if (log.isDebugEnabled() && (t != null)) { log.warn(message, o1, o2, o3, o4, t); } else { log.warn(message, o1, o2, o3, o4); } } public static void warn(Logger log, String message, Object o1, Object o2, Object o3, Object o4, Object o5, Throwable t) { if (log.isDebugEnabled() && (t != null)) { log.warn(message, o1, o2, o3, o4, o5, t); } else { log.warn(message, o1, o2, o3, o4, o5); } } @SuppressWarnings("all") public static void warn( Logger log, String message, Object o1, Object o2, Object o3, Object o4, Object o5, Object o6, Throwable t) { if (log.isDebugEnabled() && (t != null)) { log.warn(message, o1, o2, o3, o4, o5, o6, t); } else { log.warn(message, o1, o2, o3, o4, o5, o6); } } @SuppressWarnings("all") public static void warn( Logger log, String message, Object o1, Object o2, Object o3, Object o4, Object o5, Object o6, Object o7, Throwable t) { if (log.isDebugEnabled() && (t != null)) { log.warn(message, o1, o2, o3, o4, o5, o6, o7, t); } else { log.warn(message, o1, o2, o3, o4, o5, o6, o7); } } @SuppressWarnings("all") public static void warn( Logger log, String message, Object o1, Object o2, Object o3, Object o4, Object o5, Object o6, Object o7, Object o8, Throwable t) { if (log.isDebugEnabled() && (t != null)) { log.warn(message, o1, o2, o3, o4, o5, o6, o7, o8, t); } else { log.warn(message, o1, o2, o3, o4, o5, o6, o7, o8); } } @SuppressWarnings("all") public static void warn( Logger log, String message, Object o1, Object o2, Object o3, Object o4, Object o5, Object o6, Object o7, Object o8, Object o9, Throwable t) { if (log.isDebugEnabled() && (t != null)) { log.warn(message, o1, o2, o3, o4, o5, o6, o7, o8, o9, t); } else { log.warn(message, o1, o2, o3, o4, o5, o6, o7, o8, o9); } } public static void error(Logger log, String message, Object o1, Object o2, Throwable t) { if (log.isDebugEnabled() && (t != null)) { log.error(message, o1, o2, t); } else { log.error(message, o1, o2); } } public static void error(Logger log, String message, Object o1, Object o2, Object o3, Throwable t) { if (log.isDebugEnabled() && (t != null)) { log.error(message, o1, o2, o3, t); } else { log.error(message, o1, o2, o3); } } public static void error(Logger log, String message, Object o1, Object o2, Object o3, Object o4, Throwable t) { if (log.isDebugEnabled() && (t != null)) { log.error(message, o1, o2, o3, o4, t); } else { log.error(message, o1, o2, o3, o4); } } public static void error(Logger log, String message, Object o1, Object o2, Object o3, Object o4, Object o5, Throwable t) { if (log.isDebugEnabled() && (t != null)) { log.error(message, o1, o2, o3, o4, o5, t); } else { log.error(message, o1, o2, o3, o4, o5); } } @SuppressWarnings("all") public static void error( Logger log, String message, Object o1, Object o2, Object o3, Object o4, Object o5, Object o6, Throwable t) { if (log.isDebugEnabled() && (t != null)) { log.error(message, o1, o2, o3, o4, o5, o6, t); } else { log.error(message, o1, o2, o3, o4, o5, o6); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy