Slf4j+logback实现日志打印-获取调用者类及方法行数信息

为什么要用slf4j实现日志打印,在阿里的开发规范中有这么一段:

【强制】应用中不可直接使用日志系统(Log4j、Logback)中的API,而应依赖使用日志框架
SLF4J中的API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

SLF4J,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,它只服务于各种各样的日志系统。按照官方的说法,SLF4J是一个用于日志系统的简单Facade,允许最终用户在部署其应用时使用其所希望的日志系统。
大概意思就是说 SLF4J 是一个日志抽象层,允许你使用任何一个日志系统,并且可以随时切换还不需要动到已经写好的程序。
但是我们在使用slf4j的时候一般会像下面这样:

public class MySlf4j {
     private static final Logger logger = LoggerFactory.getLogger("MySlf4j");
     public static void info(String msg) {
           logger.info(msg);
     }
}

在每个类里定义Logger,这就是重复的劳动,必须对logger进行封装,编写封装类需要注意,slf4j我们如果不做处理我们调用方法记录日志,像 类名、方法名、行数都变成Logger这个类的信息,这样就无法准确定位日志来源。这样的问题是无法忍受的。
所有我们对Mylf4j工具类做了如下修改:
1.通过Throwable获取堆栈信息。
2.通过SharedSecrets.getJavaLangAccess(),我们访问堆栈信息通过stackDepth定位到调用者类信息。
具体的代码如下:

public class MySlf4j {

	/**空数组*/
	private static final Object[] EMPTY_ARRAY = new Object[] {};
	/**全类名*/
	private static final String FQCN = MySlf4j.class.getName();

	/**
	 * 获取栈中类信息
	 * @param stackDepth 栈深(下标) 2:调用者类信息
	 * @return org.slf4j.spi.LocationAwareLogger
	 * @author wxt
	 * @date 2019/7/10 8:40
	 */
	private static LocationAwareLogger getLocationAwareLogger(final int stackDepth) {
		/**通过堆栈信息获取调用当前方法的类名和方法名*/
		JavaLangAccess access = SharedSecrets.getJavaLangAccess();
		Throwable throwable = new Throwable();
		StackTraceElement frame = access.getStackTraceElement(throwable, stackDepth);
		return (LocationAwareLogger) LoggerFactory.getLogger(frame.getClassName());
	}

	/**
	 * 封装Debug级别日志
	 * @param msg
	 * @param arguments
	 * 作者:wxt
	 * 日期:2019年3月27日下午5:38:01
	 */
	public static void textDebug(String msg, Object... arguments) {
		if (arguments != null && arguments.length > 0) {
			MessageFormat temp = new MessageFormat(msg);
			msg = temp.format(arguments);
		}
		getLocationAwareLogger(2).log(null, FQCN, LocationAwareLogger.DEBUG_INT, msg, EMPTY_ARRAY, null);
	}

	/**
	 * 封装Info级别日志
	 * @param msg
	 * @param arguments
	 * 作者:wxt
	 * 日期:2019年3月27日下午5:37:42
	 */
	public static void textInfo(String msg, Object... arguments) {
		if (arguments != null && arguments.length > 0) {
			MessageFormat temp = new MessageFormat(msg);
			msg = temp.format(arguments);
		}
		getLocationAwareLogger(2).log(null, FQCN, LocationAwareLogger.INFO_INT, msg, EMPTY_ARRAY, null);
	}

	/**
	 * 封装Warn级别日志
	 * @param msg
	 * @param arguments
	 * 作者:wxt
	 * 日期:2019年3月27日下午5:37:30
	 */
	public static void textWarn(String msg, Object... arguments) {
		if (arguments != null && arguments.length > 0) {
			MessageFormat temp = new MessageFormat(msg);
			msg = temp.format(arguments);
		}
		getLocationAwareLogger(2).log(null, FQCN, LocationAwareLogger.WARN_INT, msg, EMPTY_ARRAY, null);
	}

	/**
	 * 封装Error级别日志
	 * @param msg
	 * @param arguments
	 * 作者:wxt
	 * 日期:2019年3月27日下午5:37:14
	 */
	public static void textError(String msg, Object... arguments) {
		if (arguments != null && arguments.length > 0) {
			MessageFormat temp = new MessageFormat(msg);
			msg = temp.format(arguments);
		}
		getLocationAwareLogger(2).log(null, FQCN, LocationAwareLogger.ERROR_INT, msg, EMPTY_ARRAY, null);
	}

	/**
	 * 异常堆栈转字符串
	 * @param e
	 * @return
	 * 作者:wxt
	 * 日期:2019年3月27日下午5:37:08
	 */
	public static String ExceptionToString(Exception e) {
		StringWriter sw = null;
		PrintWriter pw = null;
		try {
			if (e == null) {
				return "无具体异常信息";
			}
			sw = new StringWriter();
			pw = new PrintWriter(sw);
			e.printStackTrace(pw);
			return sw.toString();
		} catch (Exception ex) {
			MySlf4j.textError("异常堆栈转字符串异常", ex);
			return "";
		} finally {
			sw.flush();
			pw.flush();
			pw.close();
		}

	}
}

loback.xml配置如下:




	
    
    
    
    
        
            
            %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [${APP_NAME}] [%thread] [%X{traceId}] %logger{50} - [%class : %method : %line] - %msg%n
        
    
    
    
		${LOG_HOME}/${APP_NAME}.log
		
			%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [${APP_NAME}] [%thread] [%X{traceId}] %logger{50} - [%class : %method : %line] - %msg%n
		
		
			${LOG_HOME}/${APP_NAME}.%d{yyyy-MM-dd}.log
		
	

	
		
        
	

这样我们通过调用该工具类就可以打印出调用者的类相关信息。

你可能感兴趣的:(Java)