1、JAVA自带的这样:
代码如下:
import java.util.logging.*;
Logger logger = Logger.getLogger(MyLogger.class.toString());
logger.info("123");
显示效果:
这样的格式,看起来不太好看,比如:会默认添加一个换行,另外,想查看行号,会比较麻烦;随着开发代码量不断增加,因为一个函数代码量也比较大,如果知道行号,定位问题具体问题代码比较快,有点类似C语言的__LINE__宏,使用起来比较方便。
2、基于这个问题,我们需要自已实现可以显示行号的日志打印格式,通过网上查资料,知道要用到自定义日志格式设置:
logger = Logger.getLogger(MyLogger.class.getName());
logger.setUseParentHandlers(false);
//如果需要将日志文件写到文件系统中,需要创建一个FileHandler对象
Handler consoleHandler = new ConsoleHandler();
//创建日志格式文件:本次采用自定义的Formatter
consoleHandler.setFormatter(new MyFormatter());
//将FileHandler对象添加到Logger对象中
logger.addHandler(consoleHandler);
在MyFormatter中实现对格式的自定义:
@Override
public String format(LogRecord arg0)
{
//创建StringBuilder对象来存放后续需要打印的日志内容
StringBuilder builder = new StringBuilder();
//获取时间
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
Date now = new Date();
String dateStr = simpleDateFormat.format(now);
builder.append("[");
builder.append(dateStr);
builder.append(" ");
//拼接日志级别
builder.append(arg0.getLevel()).append(" ");
builder.append(arg0.getSourceClassName()).append(" ");
//拼接方法名
builder.append(arg0.getSourceMethodName()).append(" ");
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
String line = stackTrace[8].toString();
String lineNumber = line.substring(line.indexOf(":") + 1, line.length() - 1);
//System.out.println("stackTrace[0].toString(): " + stackTrace[0].toString());
//拼接方法名
builder.append(lineNumber).append("] ");
//拼接日志内容
builder.append(arg0.getMessage());
//日志换行
builder.append("\r\n");
return builder.toString();
}
这里边额外使用了获取当前线程的堆栈跟踪元素:Thread.currentThread().getStackTrace(),在程序执行过程中,可以把当前位置的调用栈打印出来;
如果在当前的文件,由于调用栈深度不深,代码如下:
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
System.out.println(stackTrace.length);
for (StackTraceElement s: stackTrace) {
System.out.println(s.toString());
}
这样打印出来是这样的:
3、在实际运行的代码涉及跨类的调用,代码:
/**
* 可以自已定义日志打印格式,这样看起来比较方便些
*
*/
class MyFormatter extends Formatter
{
@Override
public String format(LogRecord arg0)
{
//创建StringBuilder对象来存放后续需要打印的日志内容
StringBuilder builder = new StringBuilder();
//获取时间
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
Date now = new Date();
String dateStr = simpleDateFormat.format(now);
builder.append("[");
builder.append(dateStr);
builder.append(" ");
//拼接日志级别
builder.append(arg0.getLevel()).append(" ");
builder.append(arg0.getSourceClassName()).append(" ");
//拼接方法名
builder.append(arg0.getSourceMethodName()).append(" ");
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
String line = stackTrace[8].toString();
String lineNumber = line.substring(line.indexOf(":") + 1, line.length() - 1);
//System.out.println("stackTrace[0].toString(): " + stackTrace[0].toString());
StackTraceElement[] stackTrace2 = Thread.currentThread().getStackTrace();
System.out.println(stackTrace2.length);
for (StackTraceElement s: stackTrace2) {
System.out.println(s.toString());
}
//拼接方法名
builder.append(lineNumber).append("] ");
//拼接日志内容
builder.append(arg0.getMessage());
//日志换行
builder.append("\r\n");
return builder.toString();
}
}
这样看到的调用栈较深些:
这样在取我们自已代码的入口的时候,就需要从这上边往下边数,因为这里边代码是一个数组,从上图中打印也可看出来,前几个是日志打印的栈
StackTraceElement[] stackTrace2 = Thread.currentThread().getStackTrace();
System.out.println(stackTrace2.length);
for (StackTraceElement s: stackTrace2) {
System.out.println(s.toString());
}
从上图可以看出,我们代码在调用日志打印的时候,实际上使用的是stackTrace2数组里边第9个成员,由于我们需要取出行号,那么使用的是JAVA对字符串操作的搜索和截取操作,这样就可以达到目的:
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
String line = stackTrace[8].toString();
String lineNumber = line.substring(line.indexOf(":") + 1, line.length() - 1);
由于我们可以自定义打印日志的格式,那么我们整体按照自已的要求自定义后,代码是这样子的:
class MyFormatter extends Formatter
{
@Override
public String format(LogRecord arg0)
{
//创建StringBuilder对象来存放后续需要打印的日志内容
StringBuilder builder = new StringBuilder();
//获取时间
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
Date now = new Date();
String dateStr = simpleDateFormat.format(now);
builder.append("[");
builder.append(dateStr);
builder.append(" ");
//拼接日志级别
builder.append(arg0.getLevel()).append(" ");
builder.append(arg0.getSourceClassName()).append(" ");
//拼接方法名
builder.append(arg0.getSourceMethodName()).append(" ");
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
String line = stackTrace[8].toString();
String lineNumber = line.substring(line.indexOf(":") + 1, line.length() - 1);
//拼接方法名
builder.append(lineNumber).append("] ");
//拼接日志内容
builder.append(arg0.getMessage());
//日志换行
builder.append("\r\n");
return builder.toString();
}
}
最终的打印效果如下图所示:
自定义日志打印完成类代码如下:
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.*;
/**
* 可以自已定义日志打印格式,这样看起来比较方便些
*
*/
class MyFormatter extends Formatter
{
@Override
public String format(LogRecord arg0)
{
//创建StringBuilder对象来存放后续需要打印的日志内容
StringBuilder builder = new StringBuilder();
//获取时间
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
Date now = new Date();
String dateStr = simpleDateFormat.format(now);
builder.append("[");
builder.append(dateStr);
builder.append(" ");
//拼接日志级别
builder.append(arg0.getLevel()).append(" ");
builder.append(arg0.getSourceClassName()).append(" ");
//拼接方法名
builder.append(arg0.getSourceMethodName()).append(" ");
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
String line = stackTrace[8].toString();
String lineNumber = line.substring(line.indexOf(":") + 1, line.length() - 1);
//拼接方法名
builder.append(lineNumber).append("] ");
//拼接日志内容
builder.append(arg0.getMessage());
//日志换行
builder.append("\r\n");
return builder.toString();
}
}
public class MyLogger {
static Logger logger;
static {
logger = Logger.getLogger(MyLogger.class.getName());
logger.setUseParentHandlers(false);
//如果需要将日志文件写到文件系统中,需要创建一个FileHandler对象
Handler consoleHandler = new ConsoleHandler();
//创建日志格式文件:本次采用自定义的Formatter
consoleHandler.setFormatter(new MyFormatter());
//将FileHandler对象添加到Logger对象中
logger.addHandler(consoleHandler);
}
public static Logger getLogger() {
return logger;
}
}