clean history

This commit is contained in:
Looly
2019-08-14 10:02:32 +08:00
commit 6b011af032
1215 changed files with 159913 additions and 0 deletions

View File

@@ -0,0 +1,148 @@
package cn.hutool.log;
import java.io.Serializable;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.level.Level;
/**
* 抽象日志类<br>
* 实现了一些通用的接口
*
* @author Looly
*
*/
public abstract class AbstractLog implements Log, Serializable{
private static final long serialVersionUID = -3211115409504005616L;
private static final String FQCN = AbstractLog.class.getName();
@Override
public boolean isEnabled(Level level) {
switch (level) {
case TRACE:
return isTraceEnabled();
case DEBUG:
return isDebugEnabled();
case INFO:
return isInfoEnabled();
case WARN:
return isWarnEnabled();
case ERROR:
return isErrorEnabled();
default:
throw new Error(StrUtil.format("Can not identify level: {}", level));
}
}
@Override
public void trace(Throwable t) {
trace(t, ExceptionUtil.getSimpleMessage(t));
}
@Override
public void trace(String format, Object... arguments) {
trace(null, format, arguments);
}
@Override
public void trace(Throwable t, String format, Object... arguments) {
trace(FQCN, t, format, arguments);
}
@Override
public void debug(Throwable t) {
debug(t, ExceptionUtil.getSimpleMessage(t));
}
@Override
public void debug(String format, Object... arguments) {
if(null != arguments && 1 == arguments.length && arguments[0] instanceof Throwable) {
// 兼容Slf4j中的xxx(String message, Throwable e)
debug((Throwable)arguments[0], format);
} else {
debug(null, format, arguments);
}
}
@Override
public void debug(Throwable t, String format, Object... arguments) {
debug(FQCN, t, format, arguments);
}
@Override
public void info(Throwable t) {
info(t, ExceptionUtil.getSimpleMessage(t));
}
@Override
public void info(String format, Object... arguments) {
if(null != arguments && 1 == arguments.length && arguments[0] instanceof Throwable) {
// 兼容Slf4j中的xxx(String message, Throwable e)
info((Throwable)arguments[0], format);
} else {
info(null, format, arguments);
}
}
@Override
public void info(Throwable t, String format, Object... arguments) {
info(FQCN, t, format, arguments);
}
@Override
public void warn(Throwable t) {
warn(t, ExceptionUtil.getSimpleMessage(t));
}
@Override
public void warn(String format, Object... arguments) {
if(null != arguments && 1 == arguments.length && arguments[0] instanceof Throwable) {
// 兼容Slf4j中的xxx(String message, Throwable e)
warn((Throwable)arguments[0], format);
} else {
warn(null, format, arguments);
}
}
@Override
public void warn(Throwable t, String format, Object... arguments) {
warn(FQCN, t, format, arguments);
}
@Override
public void error(Throwable t) {
this.error(t, ExceptionUtil.getSimpleMessage(t));
}
@Override
public void error(String format, Object... arguments) {
if(null != arguments && 1 == arguments.length && arguments[0] instanceof Throwable) {
// 兼容Slf4j中的xxx(String message, Throwable e)
error((Throwable)arguments[0], format);
} else {
error(null, format, arguments);
}
}
@Override
public void error(Throwable t, String format, Object... arguments) {
error(FQCN, t, format, arguments);
}
@Override
public void log(Level level, String format, Object... arguments) {
if(null != arguments && 1 == arguments.length && arguments[0] instanceof Throwable) {
// 兼容Slf4j中的xxx(String message, Throwable e)
log(level, (Throwable)arguments[0], format);
} else {
log(level, null, format, arguments);
}
}
@Override
public void log(Level level, Throwable t, String format, Object... arguments) {
this.log(FQCN, level, t, format, arguments);
}
}

View File

@@ -0,0 +1,76 @@
package cn.hutool.log;
import cn.hutool.log.dialect.commons.ApacheCommonsLogFactory;
import cn.hutool.log.dialect.console.ConsoleLogFactory;
import cn.hutool.log.dialect.jdk.JdkLogFactory;
import cn.hutool.log.dialect.log4j.Log4jLogFactory;
import cn.hutool.log.dialect.log4j2.Log4j2LogFactory;
import cn.hutool.log.dialect.slf4j.Slf4jLogFactory;
/**
* 全局日志工厂类<br>
* 用于减少日志工厂创建,减少日志库探测
*
* @author looly
* @since 4.0.3
*/
public class GlobalLogFactory {
private static volatile LogFactory currentLogFactory;
private static final Object lock = new Object();
/**
* 获取单例日志工厂类,如果不存在创建之
*
* @return 当前使用的日志工厂
*/
public static LogFactory get() {
if (null == currentLogFactory) {
synchronized (lock) {
if (null == currentLogFactory) {
currentLogFactory = LogFactory.create();
}
}
}
return currentLogFactory;
}
/**
* 自定义日志实现
*
* @see Slf4jLogFactory
* @see Log4jLogFactory
* @see Log4j2LogFactory
* @see ApacheCommonsLogFactory
* @see JdkLogFactory
* @see ConsoleLogFactory
*
* @param logFactoryClass 日志工厂类
* @return 自定义的日志工厂类
*/
public static LogFactory set(Class<? extends LogFactory> logFactoryClass) {
try {
return set(logFactoryClass.newInstance());
} catch (Exception e) {
throw new IllegalArgumentException("Can not instance LogFactory class!", e);
}
}
/**
* 自定义日志实现
*
* @see Slf4jLogFactory
* @see Log4jLogFactory
* @see Log4j2LogFactory
* @see ApacheCommonsLogFactory
* @see JdkLogFactory
* @see ConsoleLogFactory
*
* @param logFactory 日志工厂类对象
* @return 自定义的日志工厂类
*/
public static LogFactory set(LogFactory logFactory) {
logFactory.getLog(GlobalLogFactory.class).debug("Custom Use [{}] Logger.", logFactory.name);
currentLogFactory = logFactory;
return currentLogFactory;
}
}

View File

@@ -0,0 +1,58 @@
package cn.hutool.log;
import cn.hutool.log.level.DebugLog;
import cn.hutool.log.level.ErrorLog;
import cn.hutool.log.level.InfoLog;
import cn.hutool.log.level.Level;
import cn.hutool.log.level.TraceLog;
import cn.hutool.log.level.WarnLog;
/**
* 日志统一接口
*
* @author Looly
*
*/
public interface Log extends TraceLog, DebugLog, InfoLog, WarnLog, ErrorLog {
/**
* @return 日志对象的Name
*/
public String getName();
/**
* 是否开启指定日志
* @param level 日志级别
* @return 是否开启指定级别
*/
boolean isEnabled(Level level);
/**
* 打印指定级别的日志
* @param level 级别
* @param format 消息模板
* @param arguments 参数
*/
void log(Level level, String format, Object... arguments);
/**
* 打印 指定级别的日志
*
* @param level 级别
* @param t 错误对象
* @param format 消息模板
* @param arguments 参数
*/
void log(Level level, Throwable t, String format, Object... arguments);
/**
* 打印 ERROR 等级的日志
*
* @param fqcn 完全限定类名(Fully Qualified Class Name),用于定位日志位置
* @param level 级别
* @param t 错误对象
* @param format 消息模板
* @param arguments 参数
*/
void log(String fqcn, Level level, Throwable t, String format, Object... arguments);
}

View File

@@ -0,0 +1,263 @@
package cn.hutool.log;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.lang.caller.CallerUtil;
import cn.hutool.log.dialect.commons.ApacheCommonsLogFactory;
import cn.hutool.log.dialect.console.ConsoleLogFactory;
import cn.hutool.log.dialect.jboss.JbossLogFactory;
import cn.hutool.log.dialect.jdk.JdkLogFactory;
import cn.hutool.log.dialect.log4j.Log4jLogFactory;
import cn.hutool.log.dialect.log4j2.Log4j2LogFactory;
import cn.hutool.log.dialect.slf4j.Slf4jLogFactory;
import cn.hutool.log.dialect.tinylog.TinyLogFactory;
/**
* 日志工厂类
*
* @see Slf4jLogFactory
* @see Log4j2LogFactory
* @see Log4jLogFactory
* @see ApacheCommonsLogFactory
* @see TinyLogFactory
* @see JbossLogFactory
* @see ConsoleLogFactory
* @see JdkLogFactory
*
* @author Looly
*
*/
public abstract class LogFactory {
/** 日志框架名,用于打印当前所用日志框架 */
protected String name;
/** 日志对象缓存 */
private Map<Object, Log> logCache;
/**
* 构造
*
* @param name 日志框架名
*/
public LogFactory(String name) {
this.name = name;
logCache = new ConcurrentHashMap<>();
}
/**
* 获取日志框架名,用于打印当前所用日志框架
*
* @return 日志框架名
* @since 4.1.21
*/
public String getName() {
return this.name;
}
/**
* 获得日志对象
*
* @param name 日志对象名
* @return 日志对象
*/
public Log getLog(String name) {
Log log = logCache.get(name);
if (null == log) {
log = createLog(name);
logCache.put(name, log);
}
return log;
}
/**
* 获得日志对象
*
* @param clazz 日志对应类
* @return 日志对象
*/
public Log getLog(Class<?> clazz) {
Log log = logCache.get(clazz);
if (null == log) {
log = createLog(clazz);
logCache.put(clazz, log);
}
return log;
}
/**
* 创建日志对象
*
* @param name 日志对象名
* @return 日志对象
*/
public abstract Log createLog(String name);
/**
* 创建日志对象
*
* @param clazz 日志对应类
* @return 日志对象
*/
public abstract Log createLog(Class<?> clazz);
/**
* 检查日志实现是否存在<br>
* 此方法仅用于检查所提供的日志相关类是否存在当传入的日志类类不存在时抛出ClassNotFoundException<br>
* 此方法的作用是在detectLogFactory方法自动检测所用日志时如果实现类不存在调用此方法会自动抛出异常从而切换到下一种日志的检测。
*
* @param logClassName 日志实现相关类
*/
protected void checkLogExist(Class<?> logClassName) {
// 不做任何操作
}
// ------------------------------------------------------------------------- Static start
/**
* @return 当前使用的日志工厂
*/
public static LogFactory getCurrentLogFactory() {
return GlobalLogFactory.get();
}
/**
* 自定义日志实现
*
* @see Slf4jLogFactory
* @see Log4j2LogFactory
* @see Log4jLogFactory
* @see ApacheCommonsLogFactory
* @see TinyLogFactory
* @see JbossLogFactory
* @see ConsoleLogFactory
* @see JdkLogFactory
*
* @param logFactoryClass 日志工厂类
* @return 自定义的日志工厂类
*/
public static LogFactory setCurrentLogFactory(Class<? extends LogFactory> logFactoryClass) {
return GlobalLogFactory.set(logFactoryClass);
}
/**
* 自定义日志实现
*
* @see Slf4jLogFactory
* @see Log4j2LogFactory
* @see Log4jLogFactory
* @see ApacheCommonsLogFactory
* @see TinyLogFactory
* @see JbossLogFactory
* @see ConsoleLogFactory
* @see JdkLogFactory
*
* @param logFactory 日志工厂类对象
* @return 自定义的日志工厂类
*/
public static LogFactory setCurrentLogFactory(LogFactory logFactory) {
return GlobalLogFactory.set(logFactory);
}
/**
* 获得日志对象
*
* @param name 日志对象名
* @return 日志对象
*/
public static Log get(String name) {
return getCurrentLogFactory().getLog(name);
}
/**
* 获得日志对象
*
* @param clazz 日志对应类
* @return 日志对象
*/
public static Log get(Class<?> clazz) {
return getCurrentLogFactory().getLog(clazz);
}
/**
* @return 获得调用者的日志
*/
public static Log get() {
return get(CallerUtil.getCallerCaller());
}
/**
* 决定日志实现
* <p>
* 依次按照顺序检查日志库的jar是否被引入如果未引入任何日志库则检查ClassPath下的logging.properties存在则使用JdkLogFactory否则使用ConsoleLogFactory
*
* @see Slf4jLogFactory
* @see Log4j2LogFactory
* @see Log4jLogFactory
* @see ApacheCommonsLogFactory
* @see TinyLogFactory
* @see JbossLogFactory
* @see ConsoleLogFactory
* @see JdkLogFactory
* @return 日志实现类
*/
public static LogFactory create() {
final LogFactory factory = doCreate();
factory.getLog(LogFactory.class).debug("Use [{}] Logger As Default.", factory.name);
return factory;
}
/**
* 决定日志实现
* <p>
* 依次按照顺序检查日志库的jar是否被引入如果未引入任何日志库则检查ClassPath下的logging.properties存在则使用JdkLogFactory否则使用ConsoleLogFactory
*
* @see Slf4jLogFactory
* @see Log4j2LogFactory
* @see Log4jLogFactory
* @see ApacheCommonsLogFactory
* @see TinyLogFactory
* @see JbossLogFactory
* @see ConsoleLogFactory
* @see JdkLogFactory
* @return 日志实现类
*/
private static LogFactory doCreate() {
try {
return new Slf4jLogFactory(true);
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new Log4j2LogFactory();
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new Log4jLogFactory();
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new ApacheCommonsLogFactory();
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new TinyLogFactory();
} catch (NoClassDefFoundError e) {
// ignore
}
try {
return new JbossLogFactory();
} catch (NoClassDefFoundError e) {
// ignore
}
// 未找到任何可支持的日志库时判断依据当JDK Logging的配置文件位于classpath中使用JDK Logging否则使用Console
final URL url = ResourceUtil.getResource("logging.properties");
return (null != url) ? new JdkLogFactory() : new ConsoleLogFactory();
}
// ------------------------------------------------------------------------- Static end
}

View File

@@ -0,0 +1,244 @@
package cn.hutool.log;
import cn.hutool.core.lang.caller.CallerUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.level.Level;
/**
* 静态日志类,用于在不引入日志对象的情况下打印日志
*
* @author Looly
*
*/
public final class StaticLog {
private static final String FQCN = StaticLog.class.getName();
private StaticLog() {
}
// ----------------------------------------------------------- Log method start
// ------------------------ Trace
/**
* Trace等级日志小于debug<br>
* 由于动态获取Log效率较低建议在非频繁调用的情况下使用
*
* @param format 格式文本,{} 代表变量
* @param arguments 变量对应的参数
*/
public static void trace(String format, Object... arguments) {
trace(LogFactory.get(CallerUtil.getCallerCaller()), format, arguments);
}
/**
* Trace等级日志小于Debug
*
* @param log 日志对象
* @param format 格式文本,{} 代表变量
* @param arguments 变量对应的参数
*/
public static void trace(Log log, String format, Object... arguments) {
log.trace(FQCN, null, format, arguments);
}
// ------------------------ debug
/**
* Debug等级日志小于Info<br>
* 由于动态获取Log效率较低建议在非频繁调用的情况下使用
*
* @param format 格式文本,{} 代表变量
* @param arguments 变量对应的参数
*/
public static void debug(String format, Object... arguments) {
debug(LogFactory.get(CallerUtil.getCallerCaller()), format, arguments);
}
/**
* Debug等级日志小于Info
*
* @param log 日志对象
* @param format 格式文本,{} 代表变量
* @param arguments 变量对应的参数
*/
public static void debug(Log log, String format, Object... arguments) {
log.debug(FQCN, null, format, arguments);
}
// ------------------------ info
/**
* Info等级日志小于Warn<br>
* 由于动态获取Log效率较低建议在非频繁调用的情况下使用
*
* @param format 格式文本,{} 代表变量
* @param arguments 变量对应的参数
*/
public static void info(String format, Object... arguments) {
info(LogFactory.get(CallerUtil.getCallerCaller()), format, arguments);
}
/**
* Info等级日志小于Warn
*
* @param log 日志对象
* @param format 格式文本,{} 代表变量
* @param arguments 变量对应的参数
*/
public static void info(Log log, String format, Object... arguments) {
log.info(FQCN, null, format, arguments);
}
// ------------------------ warn
/**
* Warn等级日志小于Error<br>
* 由于动态获取Log效率较低建议在非频繁调用的情况下使用
*
* @param format 格式文本,{} 代表变量
* @param arguments 变量对应的参数
*/
public static void warn(String format, Object... arguments) {
warn(LogFactory.get(CallerUtil.getCallerCaller()), format, arguments);
}
/**
* Warn等级日志小于Error<br>
* 由于动态获取Log效率较低建议在非频繁调用的情况下使用
*
* @param e 需在日志中堆栈打印的异常
* @param format 格式文本,{} 代表变量
* @param arguments 变量对应的参数
*/
public static void warn(Throwable e, String format, Object... arguments) {
warn(LogFactory.get(CallerUtil.getCallerCaller()), e, StrUtil.format(format, arguments));
}
/**
* Warn等级日志小于Error
*
* @param log 日志对象
* @param format 格式文本,{} 代表变量
* @param arguments 变量对应的参数
*/
public static void warn(Log log, String format, Object... arguments) {
warn(log, null, format, arguments);
}
/**
* Warn等级日志小于Error
*
* @param log 日志对象
* @param e 需在日志中堆栈打印的异常
* @param format 格式文本,{} 代表变量
* @param arguments 变量对应的参数
*/
public static void warn(Log log, Throwable e, String format, Object... arguments) {
log.warn(FQCN, e, format, arguments);
}
// ------------------------ error
/**
* Error等级日志<br>
* 由于动态获取Log效率较低建议在非频繁调用的情况下使用
*
* @param e 需在日志中堆栈打印的异常
*/
public static void error(Throwable e) {
error(LogFactory.get(CallerUtil.getCallerCaller()), e);
}
/**
* Error等级日志<br>
* 由于动态获取Log效率较低建议在非频繁调用的情况下使用
*
* @param format 格式文本,{} 代表变量
* @param arguments 变量对应的参数
*/
public static void error(String format, Object... arguments) {
error(LogFactory.get(CallerUtil.getCallerCaller()), format, arguments);
}
/**
* Error等级日志<br>
* 由于动态获取Log效率较低建议在非频繁调用的情况下使用
*
* @param e 需在日志中堆栈打印的异常
* @param format 格式文本,{} 代表变量
* @param arguments 变量对应的参数
*/
public static void error(Throwable e, String format, Object... arguments) {
error(LogFactory.get(CallerUtil.getCallerCaller()), e, format, arguments);
}
/**
* Error等级日志<br>
*
* @param log 日志对象
* @param e 需在日志中堆栈打印的异常
*/
public static void error(Log log, Throwable e) {
error(log, e, e.getMessage());
}
/**
* Error等级日志<br>
*
* @param log 日志对象
* @param format 格式文本,{} 代表变量
* @param arguments 变量对应的参数
*/
public static void error(Log log, String format, Object... arguments) {
error(log, null, format, arguments);
}
/**
* Error等级日志<br>
*
* @param log 日志对象
* @param e 需在日志中堆栈打印的异常
* @param format 格式文本,{} 代表变量
* @param arguments 变量对应的参数
*/
public static void error(Log log, Throwable e, String format, Object... arguments) {
log.error(FQCN, e, format, arguments);
}
// ------------------------ Log
/**
* 打印日志<br>
*
* @param level 日志级别
* @param t 需在日志中堆栈打印的异常
* @param format 格式文本,{} 代表变量
* @param arguments 变量对应的参数
*/
public static void log(Level level, Throwable t, String format, Object... arguments) {
LogFactory.get(CallerUtil.getCallerCaller()).log(FQCN, level, t, format, arguments);
}
// ----------------------------------------------------------- Log method end
/**
* 获得Log
*
* @param clazz 日志发出的类
* @return Log
*/
public static Log get(Class<?> clazz) {
return LogFactory.get(clazz);
}
/**
* 获得Log
*
* @param name 自定义的日志发出者名称
* @return Log
*/
public static Log get(String name) {
return LogFactory.get(name);
}
/**
* @return 获得日志,自动判定日志发出者
*/
public static Log get() {
return LogFactory.get(CallerUtil.getCallerCaller());
}
}

View File

@@ -0,0 +1,146 @@
package cn.hutool.log.dialect.commons;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.AbstractLog;
import cn.hutool.log.level.Level;
/**
* Apache Commons Logging
* @author Looly
*
*/
public class ApacheCommonsLog extends AbstractLog {
private static final long serialVersionUID = -6843151523380063975L;
private final transient Log logger;
private final String name;
// ------------------------------------------------------------------------- Constructor
public ApacheCommonsLog(Log logger, String name) {
this.logger = logger;
this.name = name;
}
public ApacheCommonsLog(Class<?> clazz) {
this(LogFactory.getLog(clazz), null == clazz ? StrUtil.NULL : clazz.getName());
}
public ApacheCommonsLog(String name) {
this(LogFactory.getLog(name), name);
}
@Override
public String getName() {
return this.name;
}
// ------------------------------------------------------------------------- Trace
@Override
public boolean isTraceEnabled() {
return logger.isTraceEnabled();
}
@Override
public void trace(String fqcn, Throwable t, String format, Object... arguments) {
// fqcn此处无效
if(isTraceEnabled()){
logger.trace(StrUtil.format(format, arguments), t);
}
}
// ------------------------------------------------------------------------- Debug
@Override
public boolean isDebugEnabled() {
return logger.isDebugEnabled();
}
@Override
public void debug(String fqcn, Throwable t, String format, Object... arguments) {
// fqcn此处无效
if(isDebugEnabled()){
logger.debug(StrUtil.format(format, arguments), t);
}
}
// ------------------------------------------------------------------------- Info
@Override
public boolean isInfoEnabled() {
return logger.isInfoEnabled();
}
@Override
public void info(String fqcn, Throwable t, String format, Object... arguments) {
// fqcn此处无效
if(isInfoEnabled()){
logger.info(StrUtil.format(format, arguments), t);
}
}
// ------------------------------------------------------------------------- Warn
@Override
public boolean isWarnEnabled() {
return logger.isWarnEnabled();
}
@Override
public void warn(String format, Object... arguments) {
if(isWarnEnabled()){
logger.warn(StrUtil.format(format, arguments));
}
}
@Override
public void warn(Throwable t, String format, Object... arguments) {
}
@Override
public void warn(String fqcn, Throwable t, String format, Object... arguments) {
// fqcn此处无效
if(isWarnEnabled()){
logger.warn(StrUtil.format(format, arguments), t);
}
}
// ------------------------------------------------------------------------- Error
@Override
public boolean isErrorEnabled() {
return logger.isErrorEnabled();
}
@Override
public void error(String fqcn, Throwable t, String format, Object... arguments) {
// fqcn此处无效
if(isErrorEnabled()){
logger.warn(StrUtil.format(format, arguments), t);
}
}
// ------------------------------------------------------------------------- Log
@Override
public void log(String fqcn, Level level, Throwable t, String format, Object... arguments) {
switch (level) {
case TRACE:
trace(t, format, arguments);
break;
case DEBUG:
debug(t, format, arguments);
break;
case INFO:
info(t, format, arguments);
break;
case WARN:
warn(t, format, arguments);
break;
case ERROR:
error(t, format, arguments);
break;
default:
throw new Error(StrUtil.format("Can not identify level: {}", level));
}
}
// ------------------------------------------------------------------------- Private method
}

View File

@@ -0,0 +1,28 @@
package cn.hutool.log.dialect.commons;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.impl.Log4JLogger;
import cn.hutool.log.dialect.log4j.Log4jLog;
/**
* Apache Commons Logging for Log4j
* @author Looly
*
*/
public class ApacheCommonsLog4JLog extends Log4jLog {
private static final long serialVersionUID = -6843151523380063975L;
// ------------------------------------------------------------------------- Constructor
public ApacheCommonsLog4JLog(Log logger) {
super(((Log4JLogger) logger).getLogger());
}
public ApacheCommonsLog4JLog(Class<?> clazz) {
super(clazz);
}
public ApacheCommonsLog4JLog(String name) {
super(name);
}
}

View File

@@ -0,0 +1,42 @@
package cn.hutool.log.dialect.commons;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
/**
* Apache Commons Logging
* @author Looly
*
*/
public class ApacheCommonsLogFactory extends LogFactory{
public ApacheCommonsLogFactory() {
super("Apache Common Logging");
checkLogExist(org.apache.commons.logging.LogFactory.class);
}
@Override
public Log createLog(String name) {
try {
return new ApacheCommonsLog4JLog(name);
} catch (Exception e) {
return new ApacheCommonsLog(name);
}
}
@Override
public Log createLog(Class<?> clazz) {
try {
return new ApacheCommonsLog4JLog(clazz);
} catch (Exception e) {
return new ApacheCommonsLog(clazz);
}
}
@Override
protected void checkLogExist(Class<?> logClassName) {
super.checkLogExist(logClassName);
//Commons Logging在调用getLog时才检查是否有日志实现在此提前检查如果没有实现则跳过之
getLog(ApacheCommonsLogFactory.class);
}
}

View File

@@ -0,0 +1,7 @@
/**
* Apache-Commons-Logging日志库的实现封装
*
* @author looly
*
*/
package cn.hutool.log.dialect.commons;

View File

@@ -0,0 +1,140 @@
package cn.hutool.log.dialect.console;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.AbstractLog;
import cn.hutool.log.level.Level;
/**
* 利用System.out.println()打印日志
* @author Looly
*
*/
public class ConsoleLog extends AbstractLog {
private static final long serialVersionUID = -6843151523380063975L;
private static String logFormat = "[{date}] [{level}] {name}: {msg}";
private static Level currentLevel = Level.DEBUG;
private String name;
//------------------------------------------------------------------------- Constructor
/**
* 构造
*
* @param clazz 类
*/
public ConsoleLog(Class<?> clazz) {
this.name = (null == clazz) ? StrUtil.NULL : clazz.getName();
}
/**
* 构造
*
* @param name 类名
*/
public ConsoleLog(String name) {
this.name = name;
}
@Override
public String getName() {
return this.name;
}
/**
* 设置自定义的日志显示级别
* @param customLevel 自定义级别
* @since 4.1.10
*/
public static void setLevel(Level customLevel) {
Assert.notNull(customLevel);
currentLevel = customLevel;
}
//------------------------------------------------------------------------- Trace
@Override
public boolean isTraceEnabled() {
return isEnabled(Level.TRACE);
}
@Override
public void trace(String fqcn, Throwable t, String format, Object... arguments) {
log(fqcn, Level.TRACE, t, format, arguments);
}
//------------------------------------------------------------------------- Debug
@Override
public boolean isDebugEnabled() {
return isEnabled(Level.DEBUG);
}
@Override
public void debug(String fqcn, Throwable t, String format, Object... arguments) {
log(fqcn, Level.DEBUG, t, format, arguments);
}
//------------------------------------------------------------------------- Info
@Override
public boolean isInfoEnabled() {
return isEnabled(Level.INFO);
}
@Override
public void info(String fqcn, Throwable t, String format, Object... arguments) {
log(fqcn, Level.INFO, t, format, arguments);
}
//------------------------------------------------------------------------- Warn
@Override
public boolean isWarnEnabled() {
return isEnabled(Level.WARN);
}
@Override
public void warn(String fqcn, Throwable t, String format, Object... arguments) {
log(fqcn, Level.WARN, t, format, arguments);
}
//------------------------------------------------------------------------- Error
@Override
public boolean isErrorEnabled() {
return isEnabled(Level.ERROR);
}
@Override
public void error(String fqcn, Throwable t, String format, Object... arguments) {
log(fqcn, Level.ERROR, t, format, arguments);
}
//------------------------------------------------------------------------- Log
@Override
public void log(String fqcn, Level level, Throwable t, String format, Object... arguments) {
// fqcn 无效
if(false == isEnabled(level)){
return;
}
final Dict dict = Dict.create()
.set("date", DateUtil.now())
.set("level", level.toString())
.set("name", this.name)
.set("msg", StrUtil.format(format, arguments));
final String logMsg = StrUtil.format(logFormat, dict);
//WARN以上级别打印至System.err
if(level.ordinal() >= Level.WARN.ordinal()){
Console.error(t, logMsg);
}else{
Console.log(t, logMsg);
}
}
@Override
public boolean isEnabled(Level level) {
return currentLevel.compareTo(level) <= 0;
}
}

View File

@@ -0,0 +1,27 @@
package cn.hutool.log.dialect.console;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
/**
* 利用System.out.println()打印日志
* @author Looly
*
*/
public class ConsoleLogFactory extends LogFactory {
public ConsoleLogFactory() {
super("Hutool Console Logging");
}
@Override
public Log createLog(String name) {
return new ConsoleLog(name);
}
@Override
public Log createLog(Class<?> clazz) {
return new ConsoleLog(clazz);
}
}

View File

@@ -0,0 +1,7 @@
/**
* 控制台输出的实现封装
*
* @author looly
*
*/
package cn.hutool.log.dialect.console;

View File

@@ -0,0 +1,141 @@
package cn.hutool.log.dialect.jboss;
import org.jboss.logging.Logger;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.AbstractLog;
import cn.hutool.log.level.Level;
/**
* <a href="https://github.com/jboss-logging">Jboss-Logging</a> log.
*
* @author Looly
*
*/
public class JbossLog extends AbstractLog {
private static final long serialVersionUID = -6843151523380063975L;
private final transient Logger logger;
// ------------------------------------------------------------------------- Constructor
/**
* 构造
*
* @param logger {@link Logger}
*/
public JbossLog(Logger logger) {
this.logger = logger;
}
/**
* 构造
*
* @param clazz 日志打印所在类
*/
public JbossLog(Class<?> clazz) {
this((null == clazz) ? StrUtil.NULL : clazz.getName());
}
/**
* 构造
*
* @param name 日志打印所在类名
*/
public JbossLog(String name) {
this(Logger.getLogger(name));
}
@Override
public String getName() {
return logger.getName();
}
// ------------------------------------------------------------------------- Trace
@Override
public boolean isTraceEnabled() {
return logger.isTraceEnabled();
}
@Override
public void trace(String fqcn, Throwable t, String format, Object... arguments) {
if (isTraceEnabled()) {
logger.trace(fqcn, StrUtil.format(format, arguments), t);
}
}
// ------------------------------------------------------------------------- Debug
@Override
public boolean isDebugEnabled() {
return logger.isDebugEnabled();
}
@Override
public void debug(String fqcn, Throwable t, String format, Object... arguments) {
if (isDebugEnabled()) {
logger.debug(fqcn, StrUtil.format(format, arguments), t);
}
}
// ------------------------------------------------------------------------- Info
@Override
public boolean isInfoEnabled() {
return logger.isInfoEnabled();
}
@Override
public void info(String fqcn, Throwable t, String format, Object... arguments) {
if (isInfoEnabled()) {
logger.info(fqcn, StrUtil.format(format, arguments), t);
}
}
// ------------------------------------------------------------------------- Warn
@Override
public boolean isWarnEnabled() {
return logger.isEnabled(Logger.Level.WARN);
}
@Override
public void warn(String fqcn, Throwable t, String format, Object... arguments) {
if (isWarnEnabled()) {
logger.warn(fqcn, StrUtil.format(format, arguments), t);
}
}
// ------------------------------------------------------------------------- Error
@Override
public boolean isErrorEnabled() {
return logger.isEnabled(Logger.Level.ERROR);
}
@Override
public void error(String fqcn, Throwable t, String format, Object... arguments) {
if (isErrorEnabled()) {
logger.error(fqcn, StrUtil.format(format, arguments), t);
}
}
// ------------------------------------------------------------------------- Log
@Override
public void log(String fqcn, Level level, Throwable t, String format, Object... arguments) {
switch (level) {
case TRACE:
trace(fqcn, t, format, arguments);
break;
case DEBUG:
debug(fqcn, t, format, arguments);
break;
case INFO:
info(fqcn, t, format, arguments);
break;
case WARN:
warn(fqcn, t, format, arguments);
break;
case ERROR:
error(fqcn, t, format, arguments);
break;
default:
throw new Error(StrUtil.format("Can not identify level: {}", level));
}
}
}

View File

@@ -0,0 +1,32 @@
package cn.hutool.log.dialect.jboss;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
/**
* <a href="https://github.com/jboss-logging">Jboss-Logging</a> log.
*
* @author Looly
* @since 4.1.21
*/
public class JbossLogFactory extends LogFactory {
/**
* 构造
*/
public JbossLogFactory() {
super("JBoss Logging");
checkLogExist(org.jboss.logging.Logger.class);
}
@Override
public Log createLog(String name) {
return new JbossLog(name);
}
@Override
public Log createLog(Class<?> clazz) {
return new JbossLog(clazz);
}
}

View File

@@ -0,0 +1,7 @@
/**
* jboss-logging实现
*
* @author looly
*
*/
package cn.hutool.log.dialect.jboss;

View File

@@ -0,0 +1,166 @@
package cn.hutool.log.dialect.jdk;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.AbstractLog;
/**
* <a href="http://java.sun.com/javase/6/docs/technotes/guides/logging/index.html">java.util.logging</a> log.
*
* @author Looly
*
*/
public class JdkLog extends AbstractLog {
private static final long serialVersionUID = -6843151523380063975L;
private final transient Logger logger;
// ------------------------------------------------------------------------- Constructor
public JdkLog(Logger logger) {
this.logger = logger;
}
public JdkLog(Class<?> clazz) {
this((null == clazz) ? StrUtil.NULL : clazz.getName());
}
public JdkLog(String name) {
this(Logger.getLogger(name));
}
@Override
public String getName() {
return logger.getName();
}
// ------------------------------------------------------------------------- Trace
@Override
public boolean isTraceEnabled() {
return logger.isLoggable(Level.FINEST);
}
@Override
public void trace(String fqcn, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, Level.FINEST, t, format, arguments);
}
// ------------------------------------------------------------------------- Debug
@Override
public boolean isDebugEnabled() {
return logger.isLoggable(Level.FINE);
}
@Override
public void debug(String fqcn, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, Level.FINE, t, format, arguments);
}
// ------------------------------------------------------------------------- Info
@Override
public boolean isInfoEnabled() {
return logger.isLoggable(Level.INFO);
}
@Override
public void info(String fqcn, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, Level.INFO, t, format, arguments);
}
// ------------------------------------------------------------------------- Warn
@Override
public boolean isWarnEnabled() {
return logger.isLoggable(Level.WARNING);
}
@Override
public void warn(String fqcn, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, Level.WARNING, t, format, arguments);
}
// ------------------------------------------------------------------------- Error
@Override
public boolean isErrorEnabled() {
return logger.isLoggable(Level.SEVERE);
}
@Override
public void error(String fqcn, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, Level.SEVERE, t, format, arguments);
}
// ------------------------------------------------------------------------- Log
@Override
public void log(String fqcn, cn.hutool.log.level.Level level, Throwable t, String format, Object... arguments) {
Level jdkLevel;
switch (level) {
case TRACE:
jdkLevel = Level.FINEST;
break;
case DEBUG:
jdkLevel = Level.FINE;
break;
case INFO:
jdkLevel = Level.INFO;
break;
case WARN:
jdkLevel = Level.WARNING;
break;
case ERROR:
jdkLevel = Level.SEVERE;
break;
default:
throw new Error(StrUtil.format("Can not identify level: {}", level));
}
logIfEnabled(fqcn, jdkLevel, t, format, arguments);
}
// ------------------------------------------------------------------------- Private method
/**
* 打印对应等级的日志
*
* @param callerFQCN 调用者的完全限定类名(Fully Qualified Class Name)
* @param level 等级
* @param throwable 异常对象
* @param format 消息模板
* @param arguments 参数
*/
private void logIfEnabled(String callerFQCN, Level level, Throwable throwable, String format, Object[] arguments){
if(logger.isLoggable(level)){
LogRecord record = new LogRecord(level, StrUtil.format(format, arguments));
record.setLoggerName(getName());
record.setThrown(throwable);
fillCallerData(callerFQCN, record);
logger.log(record);
}
}
/**
* 传入调用日志类的信息
* @param callerFQCN 调用者全限定类名
* @param superFQCN 调用者父类全限定名
* @param record The record to update
*/
private static void fillCallerData(String callerFQCN, LogRecord record) {
StackTraceElement[] steArray = Thread.currentThread().getStackTrace();
int found = -1;
String className;
for (int i = steArray.length -2; i > -1; i--) {
// 此处初始值为length-2表示从倒数第二个堆栈开始检查如果是倒数第一个那调用者就获取不到
className = steArray[i].getClassName();
if (callerFQCN.equals(className)) {
found = i;
break;
}
}
if (found > -1) {
StackTraceElement ste = steArray[found+1];
record.setSourceClassName(ste.getClassName());
record.setSourceMethodName(ste.getMethodName());
}
}
}

View File

@@ -0,0 +1,59 @@
package cn.hutool.log.dialect.jdk;
import java.io.InputStream;
import java.util.logging.LogManager;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
/**
* JDK日志工厂类
* <a href="http://java.sun.com/javase/6/docs/technotes/guides/logging/index.html">java.util.logging</a> log.
* @author Looly
*
*/
public class JdkLogFactory extends LogFactory{
public JdkLogFactory() {
super("JDK Logging");
readConfig();
}
@Override
public Log createLog(String name) {
return new JdkLog(name);
}
@Override
public Log createLog(Class<?> clazz) {
return new JdkLog(clazz);
}
/**
* 读取ClassPath下的logging.properties配置文件
*/
private void readConfig() {
//避免循环引用Log初始化的时候不使用相关工具类
InputStream in = ResourceUtil.getStreamSafe("logging.properties");
if(null == in){
System.err.println("[WARN] Can not find [logging.properties], use [%JRE_HOME%/lib/logging.properties] as default!");
return;
}
try {
LogManager.getLogManager().readConfiguration(in);
} catch (Exception e) {
Console.error(e, "Read [logging.properties] from classpath error!");
try {
LogManager.getLogManager().readConfiguration();
} catch (Exception e1) {
Console.error(e, "Read [logging.properties] from [%JRE_HOME%/lib/logging.properties] error!");
}
} finally {
IoUtil.close(in);
}
}
}

View File

@@ -0,0 +1,7 @@
/**
* JDK-Logging的实现封装
*
* @author looly
*
*/
package cn.hutool.log.dialect.jdk;

View File

@@ -0,0 +1,120 @@
package cn.hutool.log.dialect.log4j;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.AbstractLog;
/**
* <a href="http://logging.apache.org/log4j/1.2/index.html">Apache Log4J</a> log.<br>
*
* @author Looly
*
*/
public class Log4jLog extends AbstractLog {
private static final long serialVersionUID = -6843151523380063975L;
private final Logger logger;
// ------------------------------------------------------------------------- Constructor
public Log4jLog(Logger logger) {
this.logger = logger;
}
public Log4jLog(Class<?> clazz) {
this((null == clazz) ? StrUtil.NULL : clazz.getName());
}
public Log4jLog(String name) {
this(Logger.getLogger(name));
}
@Override
public String getName() {
return logger.getName();
}
// ------------------------------------------------------------------------- Trace
@Override
public boolean isTraceEnabled() {
return logger.isTraceEnabled();
}
@Override
public void trace(String fqcn, Throwable t, String format, Object... arguments) {
log(fqcn, cn.hutool.log.level.Level.TRACE, t, format, arguments);
}
// ------------------------------------------------------------------------- Debug
@Override
public boolean isDebugEnabled() {
return logger.isDebugEnabled();
}
@Override
public void debug(String fqcn, Throwable t, String format, Object... arguments) {
log(fqcn, cn.hutool.log.level.Level.DEBUG, t, format, arguments);
}
// ------------------------------------------------------------------------- Info
@Override
public boolean isInfoEnabled() {
return logger.isInfoEnabled();
}
@Override
public void info(String fqcn, Throwable t, String format, Object... arguments) {
log(fqcn, cn.hutool.log.level.Level.INFO, t, format, arguments);
}
// ------------------------------------------------------------------------- Warn
@Override
public boolean isWarnEnabled() {
return logger.isEnabledFor(Level.WARN);
}
@Override
public void warn(String fqcn, Throwable t, String format, Object... arguments) {
log(fqcn, cn.hutool.log.level.Level.WARN, t, format, arguments);
}
// ------------------------------------------------------------------------- Error
@Override
public boolean isErrorEnabled() {
return logger.isEnabledFor(Level.ERROR);
}
@Override
public void error(String fqcn, Throwable t, String format, Object... arguments) {
log(fqcn, cn.hutool.log.level.Level.ERROR, t, format, arguments);
}
// ------------------------------------------------------------------------- Log
@Override
public void log(String fqcn, cn.hutool.log.level.Level level, Throwable t, String format, Object... arguments) {
Level log4jLevel;
switch (level) {
case TRACE:
log4jLevel = Level.TRACE;
break;
case DEBUG:
log4jLevel = Level.DEBUG;
break;
case INFO:
log4jLevel = Level.INFO;
break;
case WARN:
log4jLevel = Level.WARN;
break;
case ERROR:
log4jLevel = Level.ERROR;
break;
default:
throw new Error(StrUtil.format("Can not identify level: {}", level));
}
if(logger.isEnabledFor(log4jLevel)) {
logger.log(fqcn, log4jLevel, StrUtil.format(format, arguments), t);
}
}
}

View File

@@ -0,0 +1,28 @@
package cn.hutool.log.dialect.log4j;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
/**
* <a href="http://logging.apache.org/log4j/1.2/index.html">Apache Log4J</a> log.<br>
* @author Looly
*
*/
public class Log4jLogFactory extends LogFactory{
public Log4jLogFactory() {
super("Log4j");
checkLogExist(org.apache.log4j.Logger.class);
}
@Override
public Log createLog(String name) {
return new Log4jLog(name);
}
@Override
public Log createLog(Class<?> clazz) {
return new Log4jLog(clazz);
}
}

View File

@@ -0,0 +1,7 @@
/**
* Log4j的实现封装
*
* @author looly
*
*/
package cn.hutool.log.dialect.log4j;

View File

@@ -0,0 +1,147 @@
package cn.hutool.log.dialect.log4j2;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.spi.AbstractLogger;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.AbstractLog;
/**
* <a href="http://logging.apache.org/log4j/2.x/index.html">Apache Log4J 2</a> log.<br>
*
* @author Looly
*
*/
public class Log4j2Log extends AbstractLog {
private static final long serialVersionUID = -6843151523380063975L;
private final transient Logger logger;
// ------------------------------------------------------------------------- Constructor
public Log4j2Log(Logger logger) {
this.logger = logger;
}
public Log4j2Log(Class<?> clazz) {
this(LogManager.getLogger(clazz));
}
public Log4j2Log(String name) {
this(LogManager.getLogger(name));
}
@Override
public String getName() {
return logger.getName();
}
// ------------------------------------------------------------------------- Trace
@Override
public boolean isTraceEnabled() {
return logger.isTraceEnabled();
}
@Override
public void trace(String fqcn, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, Level.TRACE, t, format, arguments);
}
// ------------------------------------------------------------------------- Debug
@Override
public boolean isDebugEnabled() {
return logger.isDebugEnabled();
}
@Override
public void debug(String format, Object... arguments) {
debug(null, format, arguments);
}
@Override
public void debug(String fqcn, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, Level.DEBUG, t, format, arguments);
}
// ------------------------------------------------------------------------- Info
@Override
public boolean isInfoEnabled() {
return logger.isInfoEnabled();
}
@Override
public void info(String fqcn, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, Level.INFO, t, format, arguments);
}
// ------------------------------------------------------------------------- Warn
@Override
public boolean isWarnEnabled() {
return logger.isWarnEnabled();
}
@Override
public void warn(String fqcn, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, Level.WARN, t, format, arguments);
}
// ------------------------------------------------------------------------- Error
@Override
public boolean isErrorEnabled() {
return logger.isErrorEnabled();
}
@Override
public void error(String fqcn, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, Level.ERROR, t, format, arguments);
}
// ------------------------------------------------------------------------- Log
@Override
public void log(String fqcn, cn.hutool.log.level.Level level, Throwable t, String format, Object... arguments) {
Level log4j2Level;
switch (level) {
case TRACE:
log4j2Level = Level.TRACE;
break;
case DEBUG:
log4j2Level = Level.DEBUG;
break;
case INFO:
log4j2Level = Level.INFO;
break;
case WARN:
log4j2Level = Level.WARN;
break;
case ERROR:
log4j2Level = Level.ERROR;
break;
default:
throw new Error(StrUtil.format("Can not identify level: {}", level));
}
logIfEnabled(fqcn, log4j2Level, t, format, arguments);
}
// ------------------------------------------------------------------------- Private method
/**
* 打印日志<br>
* 此方法用于兼容底层日志实现,通过传入当前包装类名,以解决打印日志中行号错误问题
*
* @param fqcn 完全限定类名(Fully Qualified Class Name),用于纠正定位错误行号
* @param level 日志级别使用org.apache.logging.log4j.Level中的常量
* @param t 异常
* @param msgTemplate 消息模板
* @param arguments 参数
*/
private void logIfEnabled(String fqcn, Level level, Throwable t, String msgTemplate, Object... arguments) {
if(this.logger.isEnabled(level)) {
if(this.logger instanceof AbstractLogger){
((AbstractLogger)this.logger).logIfEnabled(fqcn, level, null, StrUtil.format(msgTemplate, arguments), t);
} else {
// FQCN无效
this.logger.log(level, StrUtil.format(msgTemplate, arguments), t);
}
}
}
}

View File

@@ -0,0 +1,28 @@
package cn.hutool.log.dialect.log4j2;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
/**
* <a href="http://logging.apache.org/log4j/2.x/index.html">Apache Log4J 2</a> log.<br>
* @author Looly
*
*/
public class Log4j2LogFactory extends LogFactory{
public Log4j2LogFactory() {
super("Log4j2");
checkLogExist(org.apache.logging.log4j.LogManager.class);
}
@Override
public Log createLog(String name) {
return new Log4j2Log(name);
}
@Override
public Log createLog(Class<?> clazz) {
return new Log4j2Log(clazz);
}
}

View File

@@ -0,0 +1,7 @@
/**
* Log4j2的实现封装
*
* @author looly
*
*/
package cn.hutool.log.dialect.log4j2;

View File

@@ -0,0 +1,7 @@
/**
* 第三方日志库的实现封装
*
* @author looly
*
*/
package cn.hutool.log.dialect;

View File

@@ -0,0 +1,181 @@
package cn.hutool.log.dialect.slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.spi.LocationAwareLogger;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.AbstractLog;
import cn.hutool.log.level.Level;
/**
* <a href="http://www.slf4j.org/">SLF4J</a> log.<br>
* 同样无缝支持 <a href="http://logback.qos.ch/">LogBack</a>
*
* @author Looly
*
*/
public class Slf4jLog extends AbstractLog {
private static final long serialVersionUID = -6843151523380063975L;
private final transient Logger logger;
/** 是否为 LocationAwareLogger 用于判断是否可以传递FQCN */
private final boolean isLocationAwareLogger;
// ------------------------------------------------------------------------- Constructor
public Slf4jLog(Logger logger) {
this.logger = logger;
this.isLocationAwareLogger = (logger instanceof LocationAwareLogger);
}
public Slf4jLog(Class<?> clazz) {
this(getSlf4jLogger(clazz));
}
public Slf4jLog(String name) {
this(LoggerFactory.getLogger(name));
}
@Override
public String getName() {
return logger.getName();
}
// ------------------------------------------------------------------------- Trace
@Override
public boolean isTraceEnabled() {
return logger.isTraceEnabled();
}
@Override
public void trace(String fqcn, Throwable t, String format, Object... arguments) {
if (isTraceEnabled()) {
if(this.isLocationAwareLogger) {
locationAwareLog((LocationAwareLogger)this.logger, fqcn, LocationAwareLogger.TRACE_INT, t, format, arguments);
} else {
logger.trace(StrUtil.format(format, arguments), t);
}
}
}
// ------------------------------------------------------------------------- Debug
@Override
public boolean isDebugEnabled() {
return logger.isDebugEnabled();
}
@Override
public void debug(String fqcn, Throwable t, String format, Object... arguments) {
if (isDebugEnabled()) {
if(this.isLocationAwareLogger) {
locationAwareLog((LocationAwareLogger)this.logger, fqcn, LocationAwareLogger.DEBUG_INT, t, format, arguments);
} else {
logger.debug(StrUtil.format(format, arguments), t);
}
}
}
// ------------------------------------------------------------------------- Info
@Override
public boolean isInfoEnabled() {
return logger.isInfoEnabled();
}
@Override
public void info(String fqcn, Throwable t, String format, Object... arguments) {
if (isInfoEnabled()) {
if(this.isLocationAwareLogger) {
locationAwareLog((LocationAwareLogger)this.logger, fqcn, LocationAwareLogger.INFO_INT, t, format, arguments);
} else {
logger.info(StrUtil.format(format, arguments), t);
}
}
}
// ------------------------------------------------------------------------- Warn
@Override
public boolean isWarnEnabled() {
return logger.isWarnEnabled();
}
@Override
public void warn(String fqcn, Throwable t, String format, Object... arguments) {
if (isWarnEnabled()) {
if(this.isLocationAwareLogger) {
locationAwareLog((LocationAwareLogger)this.logger, fqcn, LocationAwareLogger.WARN_INT, t, format, arguments);
} else {
logger.warn(StrUtil.format(format, arguments), t);
}
}
}
// ------------------------------------------------------------------------- Error
@Override
public boolean isErrorEnabled() {
return logger.isErrorEnabled();
}
@Override
public void error(String fqcn, Throwable t, String format, Object... arguments) {
if (isErrorEnabled()) {
if(this.isLocationAwareLogger) {
locationAwareLog((LocationAwareLogger)this.logger, fqcn, LocationAwareLogger.ERROR_INT, t, format, arguments);
} else {
logger.error(StrUtil.format(format, arguments), t);
}
}
}
// ------------------------------------------------------------------------- Log
@Override
public void log(String fqcn, Level level, Throwable t, String format, Object... arguments) {
switch (level) {
case TRACE:
trace(fqcn, t, format, arguments);
break;
case DEBUG:
debug(fqcn, t, format, arguments);
break;
case INFO:
info(fqcn, t, format, arguments);
break;
case WARN:
warn(fqcn, t, format, arguments);
break;
case ERROR:
error(fqcn, t, format, arguments);
break;
default:
throw new Error(StrUtil.format("Can not identify level: {}", level));
}
}
// -------------------------------------------------------------------------------------------------- Private method
/**
* 打印日志<br>
* 此方法用于兼容底层日志实现,通过传入当前包装类名,以解决打印日志中行号错误问题
*
* @param logger {@link LocationAwareLogger} 实现
* @param fqcn 完全限定类名(Fully Qualified Class Name),用于纠正定位错误行号
* @param level_int 日志级别使用LocationAwareLogger中的常量
* @param t 异常
* @param msgTemplate 消息模板
* @param arguments 参数
* @return 是否支持 LocationAwareLogger对象如果不支持需要日志方法调用被包装类的相应方法
*/
private void locationAwareLog(LocationAwareLogger logger, String fqcn, int level_int, Throwable t, String msgTemplate, Object[] arguments) {
// ((LocationAwareLogger)this.logger).log(null, fqcn, level_int, msgTemplate, arguments, t);
// 由于slf4j-log4j12中此方法的实现存在bug故在此拼接参数
logger.log(null, fqcn, level_int, StrUtil.format(msgTemplate, arguments), null, t);
}
/**
* 获取Slf4j Logger对象
*
* @param clazz 打印日志所在类,当为{@code null}时使用“null”表示
* @return {@link Logger}
*/
private static Logger getSlf4jLogger(Class<?> clazz) {
return (null == clazz) ? LoggerFactory.getLogger(StrUtil.EMPTY) : LoggerFactory.getLogger(clazz);
}
}

View File

@@ -0,0 +1,75 @@
package cn.hutool.log.dialect.slf4j;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.NOPLoggerFactory;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
/**
* <a href="http://www.slf4j.org/">SLF4J</a> log.<br>
* 同样无缝支持 <a href="http://logback.qos.ch/">LogBack</a>
*
* @author Looly
*
*/
public class Slf4jLogFactory extends LogFactory {
public Slf4jLogFactory() {
this(false);
}
/**
* 构造
*
* @param failIfNOP 如果未找到桥接包是否报错
*/
public Slf4jLogFactory(boolean failIfNOP) {
super("Slf4j");
checkLogExist(LoggerFactory.class);
if(false == failIfNOP){
return;
}
// SFL4J writes it error messages to System.err. Capture them so that the user does not see such a message on
// the console during automatic detection.
final StringBuilder buf = new StringBuilder();
final PrintStream err = System.err;
try {
System.setErr(new PrintStream(new OutputStream(){
@Override
public void write(int b) {
buf.append((char) b);
}
}, true, "US-ASCII"));
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
try {
if (LoggerFactory.getILoggerFactory() instanceof NOPLoggerFactory) {
throw new NoClassDefFoundError(buf.toString());
} else {
err.print(buf);
err.flush();
}
} finally {
System.setErr(err);
}
}
@Override
public Log createLog(String name) {
return new Slf4jLog(name);
}
@Override
public Log createLog(Class<?> clazz) {
return new Slf4jLog(clazz);
}
}

View File

@@ -0,0 +1,7 @@
/**
* Slf4j的实现封装
*
* @author looly
*
*/
package cn.hutool.log.dialect.slf4j;

View File

@@ -0,0 +1,170 @@
package cn.hutool.log.dialect.tinylog;
import org.pmw.tinylog.Level;
import org.pmw.tinylog.LogEntryForwarder;
import org.pmw.tinylog.Logger;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.AbstractLog;
/**
* <a href="http://www.tinylog.org/">tinylog</a> log.<br>
*
* @author Looly
*
*/
public class TinyLog extends AbstractLog {
private static final long serialVersionUID = -4848042277045993735L;
/** 堆栈增加层数,因为封装因此多了两层,此值用于正确获取当前类名 */
private static final int DEPTH = 4;
private int level;
private String name;
// ------------------------------------------------------------------------- Constructor
public TinyLog(Class<?> clazz) {
this(null == clazz ? StrUtil.NULL : clazz.getName());
}
public TinyLog(String name) {
this.name = name;
this.level = Logger.getLevel(name).ordinal();
}
@Override
public String getName() {
return this.name;
}
// ------------------------------------------------------------------------- Trace
@Override
public boolean isTraceEnabled() {
return this.level <= Level.TRACE.ordinal();
}
@Override
public void trace(String fqcn, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, Level.TRACE, t, format, arguments);
}
// ------------------------------------------------------------------------- Debug
@Override
public boolean isDebugEnabled() {
return this.level <= Level.DEBUG.ordinal();
}
@Override
public void debug(String fqcn, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, Level.DEBUG, t, format, arguments);
}
// ------------------------------------------------------------------------- Info
@Override
public boolean isInfoEnabled() {
return this.level <= Level.INFO.ordinal();
}
@Override
public void info(String fqcn, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, Level.INFO, t, format, arguments);
}
// ------------------------------------------------------------------------- Warn
@Override
public boolean isWarnEnabled() {
return this.level <= org.pmw.tinylog.Level.WARNING.ordinal();
}
@Override
public void warn(String fqcn, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, Level.WARNING, t, format, arguments);
}
// ------------------------------------------------------------------------- Error
@Override
public boolean isErrorEnabled() {
return this.level <= Level.ERROR.ordinal();
}
@Override
public void error(String fqcn, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, Level.ERROR, t, format, arguments);
}
// ------------------------------------------------------------------------- Log
@Override
public void log(String fqcn, cn.hutool.log.level.Level level, Throwable t, String format, Object... arguments) {
logIfEnabled(fqcn, toTinyLevel(level), t, format, arguments);
}
@Override
public boolean isEnabled(cn.hutool.log.level.Level level) {
return this.level <= toTinyLevel(level).ordinal();
}
/**
* 在对应日志级别打开情况下打印日志
* @param fqcn 完全限定类名(Fully Qualified Class Name),用于定位日志位置
* @param level 日志级别
* @param t 异常null则检查最后一个参数是否为Throwable类型是则取之否则不打印堆栈
* @param format 日志消息模板
* @param arguments 日志消息参数
*/
private void logIfEnabled(String fqcn, Level level, Throwable t, String format, Object... arguments) {
// fqcn 无效
if(null == t){
t = getLastArgumentIfThrowable(arguments);
}
LogEntryForwarder.forward(DEPTH, level, t, format, arguments);
}
/**
* 将Hutool的Level等级转换为Tinylog的Level等级
*
* @param level Hutool的Level等级
* @return Tinylog的Level
* @since 4.0.3
*/
private Level toTinyLevel(cn.hutool.log.level.Level level) {
Level tinyLevel;
switch (level) {
case TRACE:
tinyLevel = Level.TRACE;
break;
case DEBUG:
tinyLevel = Level.DEBUG;
break;
case INFO:
tinyLevel = Level.INFO;
break;
case WARN:
tinyLevel = Level.WARNING;
break;
case ERROR:
tinyLevel = Level.ERROR;
break;
case OFF:
tinyLevel = Level.OFF;
break;
default:
throw new Error(StrUtil.format("Can not identify level: {}", level));
}
return tinyLevel;
}
/**
* 如果最后一个参数为异常参数则获取之否则返回null
*
* @param arguments 参数
* @return 最后一个异常参数
* @since 4.0.3
*/
private static Throwable getLastArgumentIfThrowable(Object... arguments) {
if (ArrayUtil.isNotEmpty(arguments) && arguments[arguments.length - 1] instanceof Throwable) {
return (Throwable) arguments[arguments.length - 1];
} else {
return null;
}
}
}

View File

@@ -0,0 +1,32 @@
package cn.hutool.log.dialect.tinylog;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
/**
* <a href="http://www.tinylog.org/">TinyLog</a> log.<br>
*
* @author Looly
*
*/
public class TinyLogFactory extends LogFactory {
/**
* 构造
*/
public TinyLogFactory() {
super("TinyLog");
checkLogExist(org.pmw.tinylog.Logger.class);
}
@Override
public Log createLog(String name) {
return new TinyLog(name);
}
@Override
public Log createLog(Class<?> clazz) {
return new TinyLog(clazz);
}
}

View File

@@ -0,0 +1,7 @@
/**
* TinyLog的实现封装
*
* @author looly
*
*/
package cn.hutool.log.dialect.tinylog;

View File

@@ -0,0 +1,47 @@
package cn.hutool.log.level;
/**
* DEBUG级别日志接口
* @author Looly
*
*/
public interface DebugLog {
/**
* @return DEBUG 等级是否开启
*/
boolean isDebugEnabled();
/**
* 打印 DEBUG 等级的日志
*
* @param t 错误对象
*/
void debug(Throwable t);
/**
* 打印 DEBUG 等级的日志
*
* @param format 消息模板
* @param arguments 参数
*/
void debug(String format, Object... arguments);
/**
* 打印 DEBUG 等级的日志
*
* @param t 错误对象
* @param format 消息模板
* @param arguments 参数
*/
void debug(Throwable t, String format, Object... arguments);
/**
* 打印 DEBUG 等级的日志
*
* @param fqcn 完全限定类名(Fully Qualified Class Name),用于定位日志位置
* @param t 错误对象
* @param format 消息模板
* @param arguments 参数
*/
void debug(String fqcn, Throwable t, String format, Object... arguments);
}

View File

@@ -0,0 +1,47 @@
package cn.hutool.log.level;
/**
* ERROR级别日志接口
* @author Looly
*
*/
public interface ErrorLog {
/**
* @return ERROR 等级是否开启
*/
boolean isErrorEnabled();
/**
* 打印 ERROR 等级的日志
*
* @param t 错误对象
*/
void error(Throwable t);
/**
* 打印 ERROR 等级的日志
*
* @param format 消息模板
* @param arguments 参数
*/
void error(String format, Object... arguments);
/**
* 打印 ERROR 等级的日志
*
* @param t 错误对象
* @param format 消息模板
* @param arguments 参数
*/
void error(Throwable t, String format, Object... arguments);
/**
* 打印 ERROR 等级的日志
*
* @param fqcn 完全限定类名(Fully Qualified Class Name),用于定位日志位置
* @param t 错误对象
* @param format 消息模板
* @param arguments 参数
*/
void error(String fqcn, Throwable t, String format, Object... arguments);
}

View File

@@ -0,0 +1,47 @@
package cn.hutool.log.level;
/**
* INFO级别日志接口
* @author Looly
*
*/
public interface InfoLog {
/**
* @return INFO 等级是否开启
*/
boolean isInfoEnabled();
/**
* 打印 INFO 等级的日志
*
* @param t 错误对象
*/
void info(Throwable t);
/**
* 打印 INFO 等级的日志
*
* @param format 消息模板
* @param arguments 参数
*/
void info(String format, Object... arguments);
/**
* 打印 INFO 等级的日志
*
* @param t 错误对象
* @param format 消息模板
* @param arguments 参数
*/
void info(Throwable t, String format, Object... arguments);
/**
* 打印 INFO 等级的日志
*
* @param fqcn 完全限定类名(Fully Qualified Class Name),用于定位日志位置
* @param t 错误对象
* @param format 消息模板
* @param arguments 参数
*/
void info(String fqcn, Throwable t, String format, Object... arguments);
}

View File

@@ -0,0 +1,41 @@
package cn.hutool.log.level;
/**
* 日志等级
* @author Looly
*
*/
public enum Level{
/**
* 'ALL' log level.
*/
ALL,
/**
* 'TRACE' log level.
*/
TRACE,
/**
* 'DEBUG' log level.
*/
DEBUG,
/**
* 'INFO' log level.
*/
INFO,
/**
* 'WARN' log level.
*/
WARN,
/**
* 'ERROR' log level.
*/
ERROR,
/**
* 'FATAL' log level.
*/
FATAL,
/**
* 'OFF' log.
*/
OFF
}

View File

@@ -0,0 +1,47 @@
package cn.hutool.log.level;
/**
* TRACE级别日志接口
* @author Looly
*
*/
public interface TraceLog {
/**
* @return TRACE 等级是否开启
*/
boolean isTraceEnabled();
/**
* 打印 TRACE 等级的日志
*
* @param t 错误对象
*/
void trace(Throwable t);
/**
* 打印 TRACE 等级的日志
*
* @param format 消息模板
* @param arguments 参数
*/
void trace(String format, Object... arguments);
/**
* 打印 TRACE 等级的日志
*
* @param t 错误对象
* @param format 消息模板
* @param arguments 参数
*/
void trace(Throwable t, String format, Object... arguments);
/**
* 打印 TRACE 等级的日志
*
* @param fqcn 完全限定类名(Fully Qualified Class Name),用于定位日志位置
* @param t 错误对象
* @param format 消息模板
* @param arguments 参数
*/
void trace(String fqcn, Throwable t, String format, Object... arguments);
}

View File

@@ -0,0 +1,47 @@
package cn.hutool.log.level;
/**
* WARN级别日志接口
* @author Looly
*
*/
public interface WarnLog {
/**
* @return WARN 等级是否开启
*/
boolean isWarnEnabled();
/**
* 打印 WARN 等级的日志
*
* @param t 错误对象
*/
void warn(Throwable t);
/**
* 打印 WARN 等级的日志
*
* @param format 消息模板
* @param arguments 参数
*/
void warn(String format, Object... arguments);
/**
* 打印 WARN 等级的日志
*
* @param t 错误对象
* @param format 消息模板
* @param arguments 参数
*/
void warn(Throwable t, String format, Object... arguments);
/**
* 打印 WARN 等级的日志
*
* @param fqcn 完全限定类名(Fully Qualified Class Name),用于定位日志位置
* @param t 错误对象
* @param format 消息模板
* @param arguments 参数
*/
void warn(String fqcn, Throwable t, String format, Object... arguments);
}

View File

@@ -0,0 +1,7 @@
/**
* 按照日志级别定义的日志打印接口定义
*
* @author looly
*
*/
package cn.hutool.log.level;

View File

@@ -0,0 +1,7 @@
/**
* Hutool-log只是一个日志的通用门面功能类似于Slf4j。根据加入ClassPath中的jar包动态检测日志实现的方式使日志使用个更加便利灵活。
*
* @author looly
*
*/
package cn.hutool.log;