org.apache.sshd.common.util.logging.LoggingUtils Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including
all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and
JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
/*
* 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 super Field> 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 super Field> 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 super Field> 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);
}
}
}