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


    1、JAVA自带的这样:
    代码如下:

    import java.util.logging.*;
    Logger logger = Logger.getLogger(MyLogger.class.toString());
    logger.info("123");
    
    • 1
    • 2
    • 3

    显示效果:
    在这里插入图片描述
    这样的格式,看起来不太好看,比如:会默认添加一个换行,另外,想查看行号,会比较麻烦;随着开发代码量不断增加,因为一个函数代码量也比较大,如果知道行号,定位问题具体问题代码比较快,有点类似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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在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();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    这里边额外使用了获取当前线程的堆栈跟踪元素:Thread.currentThread().getStackTrace(),在程序执行过程中,可以把当前位置的调用栈打印出来;
    如果在当前的文件,由于调用栈深度不深,代码如下:

            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
            System.out.println(stackTrace.length);
            for (StackTraceElement s: stackTrace) {
                System.out.println(s.toString());
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这样打印出来是这样的:
    在这里插入图片描述
    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();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

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

    StackTraceElement[] stackTrace2 = Thread.currentThread().getStackTrace();
            System.out.println(stackTrace2.length);
            for (StackTraceElement s: stackTrace2) {
                System.out.println(s.toString());
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
            String line = stackTrace[8].toString();
            String lineNumber = line.substring(line.indexOf(":") + 1, line.length() - 1);
    
    • 1
    • 2
    • 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);
    
            //拼接方法名
            builder.append(lineNumber).append("] ");
    
            //拼接日志内容
            builder.append(arg0.getMessage());
    
            //日志换行
            builder.append("\r\n");
    
            return builder.toString();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    最终的打印效果如下图所示:
    在这里插入图片描述
    自定义日志打印完成类代码如下:

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
  • 相关阅读:
    向日葵无法连接服务器(无法登录)
    java-php-net-python-税务申报系统ssh计算机毕业设计程序
    【机器学习】算法改进——小批量和软更新
    Centos7上安装MySQL8教程
    R 语言的安装教程
    web手势库Alloyfinger
    数据库作业
    计算机图形学-算法总结
    解锁内存之谜:从C到Python、Java和Go的内存管理对比
    《计算机视觉中的多视图几何》笔记(5)
  • 原文地址:https://blog.csdn.net/r77683962/article/details/133851240