log4j提供了非常灵活而又强大的日志功能,java运行库中的日志功能反而被忽略了。其实也是挺好用的,最重要的是,用这个的话就不再需要log4j的jar文件。
由于java.util.logging.Logger不会自动加载配置文件,如果想用配置文件控制输出级别,需要稍微做点工作:
- 使用一个日志管理类
package logger;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LoggerManager {
private static Map<Class<?>,Logger> loggerCache = new HashMap<Class<?>,Logger>();
// 初始化LogManager
static {
// 读取配置文件
ClassLoader cl = LoggerManager.class.getClassLoader();
InputStream inputStream = null;
if (cl != null) {
inputStream = cl.getResourceAsStream("log.properties");
} else {
inputStream = ClassLoader
.getSystemResourceAsStream("log.properties");
}
java.util.logging.LogManager logManager = java.util.logging.LogManager
.getLogManager();
if (inputStream == null){
System.err.println("LoggerManager: Log configuration NOT found!");
}else try {
// 重新初始化日志属性并重新读取日志配置。
logManager.readConfiguration(inputStream);
System.out.println("LoggerManager: Log configuration loaded.");
} catch (Exception e) {
System.err.println(e);
} finally{
try {inputStream.close();}
catch(Exception ex){
ex.printStackTrace();
}
}
}
/**
* 获取日志对象
* @param clazz
* @return
*/
public static Logger getLogger(Class<?> clazz) {
Logger logger = loggerCache.get(clazz);
if (logger==null){
logger = Logger.getLogger(clazz.getCanonicalName());
loggerCache.put(clazz, logger);
}
return logger;
}
/**
* 获取指定Logger的有效Level
* @param logger
* @return
*/
public static Level getEffectiveLevel(Logger logger)
{
Level level = null;
Logger parent = logger;
while (level==null){
if (parent==null)
break;
level = parent.getLevel();
parent = parent.getParent();
}
return level;
}
}
- 然后,这样使用日志:
//启动类,或者最先加载的类用此方法,可以先读取配置文件,再生成Logger实例
private static Logger logger = LoggerManager.getLogger(DocFillerDemo.class);
//一般的类可以这样
// private static Logger logger =Logger.getLogger(DocFillerDemo.class.getCanonicalName());
用法举例:
logger.severe("错误信息");
logger.warn("警告信息");
logger.info("一般性信息,例如登录情况,业务逻辑信息输出等");
logger.fine("调试信息");
logger.finer("更细的调试信息");
ogger.finest("最细的调试信息");
- 另外需要注意的问题是配置文件
log.properties:
#Levels: SEVERE, WARNING ,INFO,CONFIG,FINE ,FINER,FINEST
#Global level
#LOGGER.level=FINEST
.level=INFO
# Example to customize the SimpleFormatter output format
# to print one-line log message like this:
# <level>: <log message> [<date/time>]
#
#java.util.logging.SimpleFormatter.format="%4$s: %3$s %5$s [%1$tc] %n"
# handlers= java.util.logging.ConsoleHandler,java.util.logging.FileHandler
handlers= java.util.logging.ConsoleHandler
#set default level for ConsoleHandler
java.util.logging.ConsoleHandler.level=ALL
# set formatter
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.level=INFO
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
# lof file size limit
java.util.logging.FileHandler.limit=1024000
# log file roll over count
java.util.logging.FileHandler.count=3
# log file name pattern,default: "%h/java%u.log"
java.util.logging.FileHandler.pattern=C:/SSLog%u.log
#
java.util.logging.FileHandler.append=true
############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################
#set level of com.ordinov.
#mandatory if logger got by: logger = Logger.getLogger(DocDataBySqlDAO.class.getCanonicalName());
com.ordinov.level=ALL
这个文件可以放在当前目录,classpath目录(LoggerManager能读到)。
尤其注意其中几个leve的设置:
.level=INFO
这是全局默认设置,所有的logger实例的默认值;
com.xxx.level=FINE
设置某一级别的默认值。这个设置覆盖全局设置,并且可以被更细的级别继承。也就是说,如果没有别的设置,com.xxx.aaa 的有效level就是 com.xxx.level的值了;
如果设置了 com.xxx.bbb=FINER,那么这个设置会影响com.xxx.bbb包以及子包的level。
另外不可忽略的是handler设置:
handlers= java.util.logging.ConsoleHandler
这一行确保所有级别的日志可以在控制台输出
java.util.logging.ConsoleHandler.level=ALL
这一行确保控制台会输出所有级别。如果ConsoleHandler.level设置为INFO,那么即使com.xxx.level=FINE,属于这个包的logger的fine级别信息也不会被输出到控制台。
当然,还可以加入FileHandler,同时输出到控制台和文件,并分别控制输出级别。本文不做讨论,请自行搜索。