【JAVA】日志打印java.util.logging.*函数自定义格式,并且显示调用时行号

1、JAVA自带的这样:

代码如下:

java 复制代码
import java.util.logging.*;
Logger logger = Logger.getLogger(MyLogger.class.toString());
logger.info("123");

显示效果:

这样的格式,看起来不太好看,比如:会默认添加一个换行,另外,想查看行号,会比较麻烦;随着开发代码量不断增加,因为一个函数代码量也比较大,如果知道行号,定位问题具体问题代码比较快,有点类似C语言的__LINE__宏,使用起来比较方便。

2、基于这个问题,我们需要自已实现可以显示行号的日志打印格式,通过网上查资料,知道要用到自定义日志格式设置:

java 复制代码
        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中实现对格式的自定义:

java 复制代码
 @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(),在程序执行过程中,可以把当前位置的调用栈打印出来;

如果在当前的文件,由于调用栈深度不深,代码如下:

java 复制代码
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        System.out.println(stackTrace.length);
        for (StackTraceElement s: stackTrace) {
            System.out.println(s.toString());
        }

这样打印出来是这样的:

3、在实际运行的代码涉及跨类的调用,代码:

java 复制代码
/**
 * 可以自已定义日志打印格式,这样看起来比较方便些
 *
 */
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();
    }
}

这样看到的调用栈较深些:

这样在取我们自已代码的入口的时候,就需要从这上边往下边数,因为这里边代码是一个数组,从上图中打印也可看出来,前几个是日志打印的栈

java 复制代码
StackTraceElement[] stackTrace2 = Thread.currentThread().getStackTrace();
        System.out.println(stackTrace2.length);
        for (StackTraceElement s: stackTrace2) {
            System.out.println(s.toString());
        }

从上图可以看出,我们代码在调用日志打印的时候,实际上使用的是stackTrace2数组里边第9个成员,由于我们需要取出行号,那么使用的是JAVA对字符串操作的搜索和截取操作,这样就可以达到目的:

java 复制代码
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        String line = stackTrace[8].toString();
        String lineNumber = line.substring(line.indexOf(":") + 1, line.length() - 1);

由于我们可以自定义打印日志的格式,那么我们整体按照自已的要求自定义后,代码是这样子的:

java 复制代码
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();
    }
}

最终的打印效果如下图所示:

自定义日志打印完成类代码如下:

java 复制代码
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;
    }
}
相关推荐
djarmy20 分钟前
MAIN.c(1): warning C318: can’t open file ‘STC8G.H’ 报错 解决 分析
c语言·开发语言·mongodb
HEJOO91 小时前
深入理解 Java volatile 关键字:原理、用法与常见误区
java·开发语言·spring
曹牧1 小时前
Java:no content to map due to end of input
java·开发语言
阿维的博客日记1 小时前
Example 类全场景实战指南
java·mybatis
梦梦代码精1 小时前
《回收租赁系统技术选型避坑指南:业务闭环与二开自由度详解》
开发语言·低代码·docker·开源·代码规范
两点王爷1 小时前
SpringBoot 项目集成 GeoServer 源码,实现地图服务发布
java·spring boot·后端
隔窗听雨眠1 小时前
记一次SQL Server数据库性能分析:从CPU100%到单配置修复的完整诊断
开发语言·数据库·php
David猪大卫1 小时前
【C++修炼】智能指针使用及原理
开发语言·c++·经验分享·笔记·学习·考研·面试
charlie1145141911 小时前
现代Qt开发之图像处理进阶:像素操作与格式转换
开发语言·图像处理·qt
李永奉1 小时前
中科蓝讯SDK开发-BT893x 面条耳机连接vivo手机后连接APP端,最后手机端设置页面手动断开蓝牙连接,此时耳机端假断开
c语言·开发语言·嵌入式硬件·物联网·智能手机·电脑