原创一个微型的日志工具类

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhangxin09/article/details/73196188

JDK 自带的 java.util.logging 非常简陋,于是在此基础上新建 LogHelper 类,封装一些实用的功能。
完整源码在:https://gitee.com/sp42/ajaxjs-base/tree/master/src/main/com/ajaxjs/util/logger

  • 封装了三种最常用的方法,分别是 config、info 和 warning 方法,均支持带有多个日志消息的对象参数,warning 支持传入 Throwable 异常的参数。
  • 可以定位日志所发生的行数及类 java 源文件的超链接,大大便于调试;
  • 通过 FileHandler 实现 WARNING 级别的或以上的日记磁盘记录,按照当前日期命名

一般情况下通过工厂模式创建 LogHelper,执行 LogHelper.getLog() 并传入目标类的 class 引用。

public class TestLogHelper {
    // 创建类成员为日志服务
    private static final LogHelper log = LogHelper.getLog(TestLogHelper.class);

    public void testGetLog() {
      // …… 其他代码
      log.warning("发生异常!……");
              log.info("bar");
              log.warning("fooo");
              // 带有多个日志消息的对象参数,用 {0},{1},{2} 预留消息位置
              log.warning("脚本引擎 {0} 没有 {1}() 这个方法", "js", "foo");
              log.warning(new Exception("致命错误!"), "脚本引擎 {0} 没有 {1}() 这个方法", "js", "foo");
    }
    .......
}

控制台现实结果如下所示。
这里写图片描述

LogHelper 更多方法的签名,参数 msg_tpl 为信息模版,用 {0},{1},{2} 预留消息位置

public void config(String msg);
public void config(String msg_tpl, Object... params);
public void info(String msg);
public void info(String msg_tpl, Object... params);
public void warning(String msg);
public void warning(String msg_tpl, Object... params);
public void warning(Throwable ex, String msg);
public void warning(Throwable ex, String msg_tpl, Object... params);

为什么 LogHelper 可以打印日志从哪个类的哪个方法来,知道是在哪一行代码上发生的?首先观察 API 原生调用 logger.logp(Level.WARNING, className, getMethodName(), msg),其中 className 是发出日志记录请求的类名,对此 LogHelper 已经把 className 作为属性保存起来了,直接传入即可;而 getMethodName() 是发出日志记录请求的方法名,这是个中的关键。下面是 getMethodName() 的源码。

public class LogHelper {
    private String className;               // 所在的类名

    ......

    /**
     * 获取所在的方法,调用时候
     * 
     * @return 方法名称
     */
    private String getMethodName() {
        StackTraceElement ste = null;

        // Thread.getCurrentThread().getStackTrace() 暴露了当前线程的运行栈信息
        for (StackTraceElement _ste : Thread.currentThread().getStackTrace()) {
            String clzName = _ste.getClassName();

            if (_ste.isNativeMethod() || clzName.equals(Thread.class.getName()) || clzName.equals(getClass().getName()))
                 continue;  // 过滤不要的类

            if (clzName.equals(className)) {
                ste = _ste;
                break;
            }
        }


        if(ste != null) {// 超链接,跳到源码所在行数
            return String.format(".%s(%s:%s)", ste.getMethodName(), ste.getFileName(), ste.getLineNumber());
        }else{
            return null;
        }
    }
    .....
}

Thread.getCurrentThread().getStackTrace() 返回当前线程的运行栈信息,结果是 StackTraceElement[] 数组。java.lang.StackTraceElement 专门用于跟踪堆栈元素的信息,通过其源码可见:

public final class StackTraceElement implements java.io.Serializable {
  // Normally initialized by VM (public constructor added in 1.5)

  private String declaringClass;     // 类名

  private String methodName;           // 方法名

  private String fileName;             // 文件名

  private int lineNumber;             // 行号
       ……
}

这正好是为当前类名、方法名、文件名、行号等信息准备的。
最后,String.format(“.%s(%s:%s)”, …) 的格式是固定的,只要符合这种格式,控制台就可以输出类的超链接。

猜你喜欢

转载自blog.csdn.net/zhangxin09/article/details/73196188