程序开发中,我们不可避免的要使用日志,它对我们的开发和调试,修改都具有重要作用。
我们可以使用专业的日志工具,框架来记录日志,对于小项目,也可以使用JDK自带的日志记录工具,使用简单,效率高。
这里只介绍简单的使用方法,便于快速使用,JDK的日志系统相当复杂,有兴趣的可以参阅API帮助文档。
建议单独编写一个类来配置日志工具,避免和其他业务代码相互干扰。
1:获取日志工具对象
public static final Logger logger = Logger.getLogger("system");
调用Logger类的静态方法getLogger,传入一个名字,名字可以任意取,对程序无影响。
2:指定日志级别
日志分为多个级别,存储在Level类中,有
SEVERE,WARNING,INFO,CONFIG,FINE,FINER,FINEST,ALL(所有级别)9种级别,调用setLevel(Level level)方法为日志对象设置级别
如果是小项目,可以不考虑级别,指定INFO即可,需要注意的是,指定级别和使用日志时的级别不同有可能会导致日志消息不被记录。
3:指定日志输出方式
日志工具使用Handler输出日志,常用的有ConsoleHandler(控制台输出),FileHandler(文件输出)。
创建一个控制台Handler
ConsoleHandler consoleHandler = new ConsoleHandler();
//Handler也要设置等级,和日志对象保持一致即可
consoleHandler.setLevel(Level.ALL);
//设置格式化对象,请见下文
consoleHandler.setFormatter(mmf);
//将该Handler添加到日志对象中,一个日志对象可以有多个Handler
logger.addHandler(consoleHandler);
创建一个文件Handler
try {
//需要指定输出文件路径
FileHandler fileHandler = new FileHandler(Content.LOG_FILE_CONTENT,false);
fileHandler.setLevel(Level.ALL);
fileHandler.setFormatter(mmf);
logger.addHandler(fileHandler);
} catch (IOException e) {
e.printStackTrace();
}
FileHandler需要指定一个输出路径,有关文件路径处理,可以参照我的文章:Java开发-制作一个可随意移植的文件路径获取类
可以将以上内容打包为一个方法:
/**
* 初始化日志工具的方法
*/
private static void initializeLogger(){
//设置记录级别
logger.setLevel(Level.ALL);
//不使用自带的父Handler,新建ConsoleHandler
logger.setUseParentHandlers(false);
//创建Handler对象,指定输出方式,设置Handler的级别
ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.ALL);
consoleHandler.setFormatter(mmf);
logger.addHandler(consoleHandler);
try {
FileHandler fileHandler = new FileHandler(Content.LOG_FILE_CONTENT,false);
fileHandler.setLevel(Level.ALL);
fileHandler.setFormatter(mmf);
logger.addHandler(fileHandler);
} catch (IOException e) {
e.printStackTrace();
}
}
然后在日志类的静态代码块中调用此方法即可。
这些工作完成后,日志对象就可以使用了,但是如果我们直接使用,在输出时就会按照默认的格式输出,可读性较差,故我们可以自定义一个格式化类,指定输出格式。
4:自定义格式化类
格式化类需要继承Formatter类,并且重写public String format(LogRecord record)方法,推荐使用内部类完成
/**
* 格式化输出文本的类
*/
private static class MyMathFormatter extends Formatter {
//日期格式化工具对象
private static final SimpleDateFormat dateFormat =
new SimpleDateFormat("HH:mm:ss:SSS");
//添加日志信息是日志对象会自动调用该方法
@Override
public String format(LogRecord record) {
//日期 {类名} [方法名] 日志内容+参数 换行符
StringBuilder s = new StringBuilder(100);
//日期
s.append(dateFormat.format(new Date()));
//类名
s.append("{");
try {
s.append(Class.forName(record.getSourceClassName()).getSimpleName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
s.append("}");
//方法名
s.append(" [");
s.append(record.getSourceMethodName());
//日志内容
s.append(",");
s.append(record.getMessage());
Object[] params = record.getParameters();
if (params != null) {
s.append("-");
//参数
s.append(Arrays.toString(record.getParameters()));
}
s.append("] ");
s.append("\n");
return s.toString();
}
}
在这个方法中,可以对原始的日志信息进行加工,例如打印时间,类名,方法名,参数等。
日志的类名,方法名这些信息被封装在LogRecord对象中,调用此对象的getxxx方法即可获取到相关信息
***此方法为日志工具对象自动调用,不需要程序员手动调用
5:使用日志工具
这样,日志工具就完全可以使用了,在程序中,调用日志工具对象的info(String message)等方法,传入日志信息,这些日志信息会被送到格式化类中加工,最后通过Handler输出到文件中或控制台。
日志输出示例,格式化类的作用非常明显
最后附上完成的类供各位参考,内容就是前文已经提到过的:
/**
* 日志工具类,使用者直接使用常量logger进行日志记录
*/
public final class CoordinateLogger {
private CoordinateLogger() {
throw new IllegalAccessError("不能创建CoordinateLogger对象!");
}
/**
* 读取文件的配置
*/
private static final ResourceBundle bundle = ResourceBundle.getBundle("com.mymath.lib.SystemConfig");
/**
* 是否使用控制台输出
*/
private static final boolean isConsole = Boolean.parseBoolean(bundle.getString("isUseConsoleHandler"));
/**
* 是否使用文件输出
*/
private static final boolean isFile = Boolean.parseBoolean(bundle.getString("isUseFileHandler"));
/**
* 格式化对象
*/
private static final MyMathFormatter mmf = new MyMathFormatter();
/**
* 可供使用的日志工具对象
*/
public static final Logger logger = Logger.getLogger("system");
static {
initializeLogger();
}
/**
* 初始化日志工具的方法
*/
private static void initializeLogger(){
//设置记录级别
logger.setLevel(Level.ALL);
//不使用自带的父Handler,新建ConsoleHandler
logger.setUseParentHandlers(false);
if (!isConsole && !isFile){
throw new ExceptionInInitializerError("没有指定日志输出方式,无法输出日志!");
}
//创建Handler对象,指定输出方式,设置Handler的级别
if (isConsole){
ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.ALL);
consoleHandler.setFormatter(mmf);
logger.addHandler(consoleHandler);
}
if (isFile){
try {
FileHandler fileHandler = new FileHandler(Content.LOG_FILE_CONTENT,false);
fileHandler.setLevel(Level.ALL);
fileHandler.setFormatter(mmf);
logger.addHandler(fileHandler);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 格式化输出文本的类
*/
private static class MyMathFormatter extends Formatter {
//日期格式化工具对象
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss:SSS");
//添加日志信息是日志对象会自动调用该方法
@Override
public String format(LogRecord record) {
//日期 {类名} [方法名] 日志内容+参数 换行符
StringBuilder s = new StringBuilder(100);
//日期
s.append(dateFormat.format(new Date()));
//类名
s.append("{");
try {
s.append(Class.forName(record.getSourceClassName()).getSimpleName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
s.append("}");
//方法名
s.append(" [");
s.append(record.getSourceMethodName());
//日志内容
s.append(",");
s.append(record.getMessage());
Object[] params = record.getParameters();
if (params != null) {
s.append("-");
//参数
s.append(Arrays.toString(record.getParameters()));
}
s.append("] ");
s.append("\n");
return s.toString();
}
}
}