Java控制台日志打印封装

平时为了方便测试和定位错误(特别是demo工具时),又不想依赖日志框架,习惯使用System.out.println(),但这种知识简单输出文本,而且打印异常时不好定位,对打印不同级别的日志也不能满足需求。本文对System.out.println()进行简单封装,轻量级调用。

以前这样打印日志:

 public static void main(String[] args) {

        testLogPrintBefore();

    }

    private static void testLogPrintBefore() {
        System.out.println("hello world!");
        try {
            LogTest logTest = null;
            logTest.clone();
        } catch (Exception e) {
            System.out.println("发生了一个错:" + e.getMessage());
        }

    }

输出:

hello world!
发生了一个错:null

可以看出非常不直观,只是简单输出文本,定位错误不好。

使用ConsoleUtils之后:

  public static void main(String[] args) {

    testLogPrintAfter();

}

private static void testLogPrintAfter() {

    ConsoleUtils.d("hello world!");
    ConsoleUtils.i("hello world!");
    ConsoleUtils.w("hello world!");

    try {
        LogTest logTest = null;
        logTest.clone();
    } catch (Exception e) {
        ConsoleUtils.w("发生了一个错误", e);
    }

    ConsoleUtils.e("hello world!");
    ConsoleUtils.e("hello world!", new RuntimeException("发生了一个错误"));
    try {
        Class.forName("java.util.Test");
    } catch (ClassNotFoundException ignored) {
        ConsoleUtils.e("hello world!", ignored);
    }
}

输出:

2021-08-12 17:20:587/D:testLogPrintAfter(LogTest.java:24)hello world!  ---->Thread:main
2021-08-12 17:20:605/I:testLogPrintAfter(LogTest.java:25)hello world!  ---->Thread:main
2021-08-12 17:20:605/W:testLogPrintAfter(LogTest.java:26)hello world!  ---->Thread:main
2021-08-12 17:20:606/W:testLogPrintAfter(LogTest.java:32)发生了一个错误  ---->Thread:main
java.lang.NullPointerException
	at com.sjl.socket.demo.LogTest.testLogPrintAfter(LogTest.java:30)
	at com.sjl.socket.demo.LogTest.main(LogTest.java:18)

2021-08-12 17:20:606/E:testLogPrintAfter(LogTest.java:35)hello world!  ---->Thread:main
2021-08-12 17:20:606/E:testLogPrintAfter(LogTest.java:36)hello world!  ---->Thread:main
java.lang.RuntimeException: 发生了一个错误
	at com.sjl.socket.demo.LogTest.testLogPrintAfter(LogTest.java:36)
	at com.sjl.socket.demo.LogTest.main(LogTest.java:18)

2021-08-12 17:20:607/E:testLogPrintAfter(LogTest.java:40)hello world!  ---->Thread:main
java.lang.ClassNotFoundException: java.util.Test
	at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:264)
	at com.sjl.socket.demo.LogTest.testLogPrintAfter(LogTest.java:38)
	at com.sjl.socket.demo.LogTest.main(LogTest.java:18)

上面虽然信息多了,日志定位信息时非常明了,输出了日志时间、日志级别、调用方法,定位行、描述信息,非常适合平时做一些测试之类工作的日志打印

ConsoleUtils是基于System.out.println封装,不同级别日志没有特别明显的颜色区分。这里介绍一个辅助插件,Grep Console是一款和IDEA Console相关的插件(当然也适用Android)。可以通过expression表达式过滤日志、给不同级别的日志或者给不同pattern的日志加上背景色与前景色。

Grep Console可以IDEA Setting->Plugin界面,搜索Grep安装即可

上面使用Grep Console插件后,输出效果如下:
在这里插入图片描述

可见,有颜色之后,区分非常明了

Grep Console配置截图:

在这里插入图片描述

最后国际规则,贴上ConsoleUtils的完整代码:

/**
 * 控制台日志工具类
 *
 * @author Kelly
 * @version 1.0.0
 * @filename ConsoleUtils
 * @time 2021/8/11 11:24
 * @copyright(C) 2021 song
 */
public class ConsoleUtils {

    private static final int LOG_DEBUG = 1;
    private static final int LOG_INFO = 2;
    private static final int LOG_WARN = 3;
    private static final int LOG_ERROR = 4;
    private static final int PLATFORM_ANDROID = 0;
    private static final int PLATFORM_PC = 1;

    /**
     * 是否显示日志
     */
    private static boolean debug = true;


    public static void d(Object msg) {
        printLog(LOG_DEBUG, msg, null);
    }


    public static void i(Object msg) {
        printLog(LOG_INFO, msg, null);
    }


    public static void w(Object msg) {
        printLog(LOG_WARN, msg, null);
    }


    public static void w(Object msg, Throwable tr) {
        printLog(LOG_WARN, msg, tr);
    }

    public static void e(Object msg) {
        printLog(LOG_ERROR, msg, null);
    }

    public static void e(Object msg, Throwable tr) {
        printLog(LOG_ERROR, msg, tr);
    }

    /**
     * 打印日志
     *
     * @param type
     * @param msgObj
     * @param tr
     * @return
     */
    private static int printLog(int type, Object msgObj, Throwable tr) {
        if (!debug) {
            return -1;
        }
        String level = "--";
        switch (type) {
            case LOG_DEBUG:
                level = "D";
                break;
            case LOG_INFO:
                level = "I";
                break;
            case LOG_WARN:
                level = "W";
                break;
            case LOG_ERROR:
                level = "E";
                break;
        }
        int platformFlag = checkPlatform();
        String content = createLog(msgObj.toString(), platformFlag) + (tr != null ? ('\n' + getStackTraceString(tr)) : "");
        StringBuilder sb = new StringBuilder();
        String formatDate = getFormatTime();
        if (platformFlag == PLATFORM_ANDROID) {
            sb.append(content);
        } else {
            sb.append(formatDate).append("/").append(level).append(":").append(content);
        }

        System.out.println(sb.toString());
        return 0;
    }

    /**
     * 创建日志定位信息
     *
     * @param msg
     * @param platformFlag
     * @return
     */
    private static String createLog(String msg, int platformFlag) {
        StringBuilder builder = new StringBuilder();
        try {
            Thread thread = Thread.currentThread();
            int stackTraceIndex;
            if (platformFlag == PLATFORM_ANDROID) { //这里根据把ConsoleUtils所在的位置确认,可以打个断点确认
                stackTraceIndex = 5;
            } else {
                stackTraceIndex = 4;
            }
            StackTraceElement[] stackTrace = thread.getStackTrace();
            String className = stackTrace[stackTraceIndex].getFileName();
            String methodName = stackTrace[stackTraceIndex].getMethodName();
            int lineNumber = stackTrace[stackTraceIndex].getLineNumber();
            builder.append(methodName);
            builder.append("(").append(className).append(":").append(lineNumber).append(")");
            builder.append(msg);
            builder.append("  ---->").append("Thread:").append(thread.getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return builder.toString();
    }

    private static int checkPlatform() {
        try {
            Class.forName("android.os.Build");
            return PLATFORM_ANDROID;
        } catch (ClassNotFoundException ignored) {
            return PLATFORM_PC;
        }
    }

    /**
     * 获取日志异常栈信息
     *
     * @param tr
     * @return
     */
    public static String getStackTraceString(Throwable tr) {
        if (tr == null) {
            return "";
        }
        Throwable t = tr;
        while (t != null) {
            if (t instanceof UnknownHostException) {
                return "";
            }
            t = t.getCause();
        }
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw, false);
        tr.printStackTrace(pw);
        pw.flush();
        pw.close();
        return sw.toString();
    }

    private static String getFormatTime() {
        Date date = new Date();
        String strDateFormat = "yyyy-MM-dd mm:ss:SSS";
        SimpleDateFormat sdf = new SimpleDateFormat(strDateFormat);
        return sdf.format(date);
    }
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值