java:反射封装Slf4j日志工具类
创始人
2024-04-30 17:27:13
0

java:反射封装Slf4j日志工具类

1 前言

使用Slf4j时,针对日志打印进行工具类封装使用。

依赖如下:

org.springframework.boot2.5.4spring-boot-starter-parent
org.springframework.bootspring-boot-starter-weborg.slf4jslf4j-api1.7.32ch.qos.logbacklogback-classic1.2.5org.springframework.bootspring-boot-configuration-processortrueorg.apache.commonscommons-lang3

2 使用

Slf4j日志工具类,反射封装:

LogUtils:

package com.xiaoxu.crawler.utils;import com.xiaoxu.crawler.base.constant.PlaceholderConstant;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Date;/*** @author xiaoxu* @date 2022-11-21 10:52* crawlerJ:com.xiaoxu.crawler.utils.LogUtil*/
public class LogUtils implements PlaceholderConstant {/* log日志时间pattern */private static final String logPattern = "yyyy-MM-dd HH:mm:ss.SSS";/* 日志方法stack层级 */private static final int logStackHierarchy = 6;public static  void logDetailInfo(Logger logger, String methodName, R requestPayload,long timeConsuming){String msg = logDetailCheck(methodName, timeConsuming);info(logger, msg, methodName, requestPayload, timeConsuming);}public static  void logDetailWarn(Logger logger, String methodName, R requestPayload,long timeConsuming){String msg = logDetailCheck(methodName, timeConsuming);warn(logger, msg, methodName, requestPayload, timeConsuming);}public static  void logDetailError(Logger logger, String methodName, R requestPayload,long timeConsuming){String msg = logDetailCheck(methodName, timeConsuming);error(logger, msg, methodName, requestPayload, timeConsuming);}private static String logDetailCheck(String methodName, long timeConsuming) {AssertUtils.assertTrue(timeConsuming >= 0, "日志耗时参数有误, 请检查");AssertUtils.assertNonEmpty(methodName, "日志请求方法参数有误, 请检查");return "调用"+squarePrefix+"{}"+squareSuffix+"方法, 请求参数:"+squarePrefix+"{}"+squareSuffix+", 耗时:"+squarePrefix+"{}"+squareSuffix+"ms.";}public static void info(Logger logger, String formatMsg, Object... objects){commLogExecute(logger, formatMsg, objects);}public static void warn(Logger logger, String formatMsg, Object... objects){commLogExecute(logger, formatMsg, objects);}public static void error(Logger logger, String formatMsg, Object... objects){commLogExecute(logger, formatMsg, objects);}private static void commLogExecute(Logger logger, String formatMsg, Object[] objects) {logCheck(logger, formatMsg, objects);ReflectExecuteLog(logger, formatMsg, objects);}private static void ReflectExecuteLog(Logger logger, String formatMsg, Object[] objects) {IfElseUtils.executeBothSide(ArrayUtils.isNotEmpty(objects), new IfElseUtils.ActionCallBack() {@Overridepublic void actionTrue() {/* logger.info(buildWrapMessage(formatMsg), objects); */Method logMethodByName = getReflectLogMethod("执行actionTrue失败,日志方法未匹配到!{0}");try {if(null != logMethodByName){logMethodByName.invoke(logger, buildWrapMessage(formatMsg, logMethodByName.getName()), objects);}} catch (IllegalAccessException | InvocationTargetException e) {ExcpUtils.throwExp(MessageFormat.format("反射执行logger方法失败!{0}",e.getMessage()));}}@Overridepublic void actionFalse() {/* logger.info(buildWrapMessage(formatMsg)); */Method logMethodByName = getReflectLogMethod("执行actionFalse失败,日志方法未匹配到!{0}");try {if(null != logMethodByName){logMethodByName.invoke(logger,buildWrapMessage(formatMsg, logMethodByName.getName()), null);}} catch (IllegalAccessException | InvocationTargetException e) {ExcpUtils.throwExp(MessageFormat.format("反射执行logger方法失败!{0}",e.getMessage()));}}private Method getReflectLogMethod(String msg) {Method logMethodByName = LogMethods.getLogMethodByName(Thread.currentThread().getStackTrace()[logStackHierarchy].getMethodName());AssertUtils.assertNonNull(logMethodByName, MessageFormat.format(msg,Thread.currentThread().getStackTrace()[logStackHierarchy].getMethodName()));return logMethodByName;}});}/* 日志方法映射枚举 */enum LogMethods implements LogConstant{/* 日志方法枚举映射 */INFO(LogConstant.INFO,handleEnumerationExp(LogConstant.INFO)),WARN(LogConstant.WARN,handleEnumerationExp(LogConstant.WARN)),ERROR(LogConstant.ERROR,handleEnumerationExp(LogConstant.ERROR));private String logMethodName;private Method logMethod;LogMethods(String logMethodName, Method logMethod){this.logMethodName = logMethodName;this.logMethod = logMethod;AssertUtils.assertTrue(null != logMethodName && logMethodName.equals(logMethod.getName()), "初始化日志名与日志方法失败!!不匹配.");}private static Method handleEnumerationExp(String logMethodName){Method method = null;try {method = Logger.class.getMethod(logMethodName, String.class, Object[].class);} catch (NoSuchMethodException e) {ExcpUtils.throwExp(MessageFormat.format("NoSuchMethod:日志枚举方法初始化异常!!!{0},日志枚举方法名称:{1}.",e.getMessage(), logMethodName));} catch (Throwable tx){ExcpUtils.throwExp(MessageFormat.format("Throwable:日志枚举方法初始化未知异常!!!{0},日志枚举方法名称:{1}.",tx.getMessage(), logMethodName));}return method;}public String getLogMethodName() {return logMethodName;}public void setLogMethodName(String logMethodName) {this.logMethodName = logMethodName;}public Method getLogMethod() {return logMethod;}public void setLogMethod(Method logMethod) {this.logMethod = logMethod;}public static Method getLogMethodByName(String logMethodName){if(!StringUtils.hasLength(logMethodName)){ExcpUtils.throwExp("请求日志枚举方法getLogMethodByName的logMethodName不能为空");}for (LogMethods value : LogMethods.values()) {if(value.getLogMethodName().equals(logMethodName)){return value.getLogMethod();}}return null;}}interface LogConstant{/* 日志级别  */String INFO = "info";String WARN = "warn";String ERROR = "error";}@SuppressWarnings(value = "all")private static String buildWrapMessage(final String msg, final String methodName){/* 日志打印补充公共信息 */StringBuffer sb = new StringBuffer();final String concat = " " + horizontalLineConcat + " ";sb.append(squarePrefix);sb.append(DateUtils.formatDate(new Date(), logPattern));sb.append(concat).append(methodName);sb.append(squareSuffix).append(" ");sb.append(msg);return sb.toString();}private static void logCheck(Logger logger, String formatMsg, Object... objects){AssertUtils.assertNonNull(logger, "log should not be null");AssertUtils.assertNonEmpty(formatMsg, "log's format message should not be null or empty");if(matchCount(formatMsg, placeholderPrefix, formatMsg, placeholderSuffix)){if(StrUtils.getMatchCount(formatMsg, placeholderPrefix) > 0){/* slf4j占位符打印日志 */AssertUtils.assertTrue(countAndObjLenMatch(StrUtils.getMatchCount(formatMsg, placeholderPrefix), objects),"log's objects should match placeholders.");}else{AssertUtils.assertTrue(ArrayUtils.isEmpty(objects), "when no placeholders, objects should be null or empty array.");}}else{ExcpUtils.throwExp("please check placeholder's left should match right.");}}private static boolean countAndObjLenMatch(int counts, Object... objects){AssertUtils.assertTrue(counts > 0, "countAndObjLenMatch's counts may be wrong.");return ArrayUtils.isNotEmpty(objects) && objects.length == counts;}private static boolean matchCount(final String str1, final String subStr1, final String str2, final String subStr2){AssertUtils.assertNonEmpty(str1, "matchCount's str1 should not be null or empty.");AssertUtils.assertNonEmpty(str1, "matchCount's subStr1 should not be null or empty.");AssertUtils.assertNonEmpty(str1, "matchCount's str2 should not be null or empty.");AssertUtils.assertNonEmpty(str1, "matchCount's subStr2 should not be null or empty.");return StrUtils.getMatchCount(str1, subStr1) == StrUtils.getMatchCount(str2, subStr2);}public static void main(String[] args) {
//        info(LoggerFactory.getLogger(LogUtils.class),"今天星期是","1","2");
//        info(LoggerFactory.getLogger(LogUtils.class),"今天星期是{}","1","2");
//        info(LoggerFactory.getLogger(LogUtils.class),"今天星期是{}{","1","2");info(LoggerFactory.getLogger(LogUtils.class),"今天星期是{}{}","1","2");info(LoggerFactory.getLogger(LogUtils.class),"今天星期是",  new Array[]{});warn(LoggerFactory.getLogger(LogUtils.class),"空指针异常!{}",  "please check");error(LoggerFactory.getLogger(LogUtils.class),"严重错误!!!{},{}",  "参数:","123");logDetailInfo(LoggerFactory.getLogger(LogUtils.class), "getYou", 123,2121);logDetailWarn(LoggerFactory.getLogger(LogUtils.class), "getYou", 123,2121);logDetailError(LoggerFactory.getLogger(LogUtils.class), "getYou", 123,2121);info(LoggerFactory.getLogger(LogUtils.class), "成功!!");}}

PlaceholderConstant:

package com.xiaoxu.crawler.base.constant;/*** @author xiaoxu* @date 2022-11-21 12:04* crawlerJ:com.xiaoxu.crawler.base.constant.PlaceholderConstant*/
public interface PlaceholderConstant {String placeholderPrefix = "{";String placeholderSuffix = "}";String squarePrefix = "[";String squareSuffix = "]";String horizontalLineConcat = "-";}

DateUtils:

package com.xiaoxu.crawler.utils;import org.springframework.util.StringUtils;import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;/*** @author xiaoxu* @date 2022-11-22 0:00* crawlerJ:com.xiaoxu.crawler.utils.DateUtils*/
public class DateUtils {private static final Object lockObj = new Object();private static volatile Map> timeLocalMaps = new HashMap<>();public static String formatDate(Date date, String pattern){AssertUtils.assertNonNull(date, "日期不能为null");String format = null;try {format = getSDF(pattern).format(date);} catch (IllegalArgumentException ie) {ExcpUtils.throwExp(MessageFormat.format("日期格式化出现无效参数异常!{0}",ie.getMessage()));} catch (Throwable th) {ExcpUtils.throwExp(MessageFormat.format("日期格式化出现未知异常!{0}",th.getMessage()));}return format;}public static Date getDateByStr(String dateStr, String pattern){AssertUtils.assertNonEmpty(dateStr, "dateStr should not be null or empty.");AssertUtils.assertNonEmpty(pattern, "pattern should not be null or empty.");AssertUtils.assertTrue(judgeStrLength(dateStr, pattern), "日期格式或者pattern格式有误!" );Date parse = null;try {parse = getSDF(pattern).parse(dateStr);} catch (ParseException th) {ExcpUtils.throwExp(MessageFormat.format("日期解析有误!{0}",th.getMessage()));} catch (Throwable th) {ExcpUtils.throwExp(MessageFormat.format("日期解析未知异常!{0}",th.getMessage()));}return parse;}private static boolean judgeStrLength(String str1, String str2){if(StringUtils.hasLength(str1) && StringUtils.hasLength(str2)){return str1.trim().length() > 0&& str1.trim().length() == str2.trim().length();}return false;}private static SimpleDateFormat getSDF(String pattern){AssertUtils.assertNonEmpty(pattern, "time pattern should not be null or empty.");ThreadLocal local = timeLocalMaps.get(pattern);/* 双重检测锁,为timeLocalMaps增加volatile标识,* 禁止指令重排 */if(null == local){synchronized (lockObj){local = timeLocalMaps.get(pattern);if(null == local){local = ThreadLocal.withInitial(()->new SimpleDateFormat(pattern));timeLocalMaps.put(pattern, local);}}}return local.get();}private void testDate(){long start  = System.currentTimeMillis();CountDownLatch countDownLatch = new CountDownLatch(100000);for (int i = 0; i < 1000; i++) {for(int j = 0; j<100; j++) {new Thread(() -> {try {// 每个子线程单独创建sdf变量SimpleDateFormat sdf = DateUtils.getSDF("yyyy-MM-dd");Date parse = null;try {parse = sdf.parse("2022-11-10");} catch (Exception e) {System.out.println("错误!!!!");throw new RuntimeException(e);}System.out.println("日期是" + parse);} finally {countDownLatch.countDown();}}, "thread-" + j).start();}}try {countDownLatch.await();} catch (InterruptedException e) {throw new RuntimeException(e);}long end = System.currentTimeMillis();System.out.println("总耗时:"+(end - start)+"ms");}public static void main(String[] args) {Date dateByStr = getDateByStr("2022-11-20", "yyyy-MM-dd");System.out.println(dateByStr);String s = formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS");System.out.println(s);String s1 = formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.fff");System.out.println(s1);}
}

IfElseUtils:

package com.xiaoxu.crawler.utils;/*** @author xiaoxu* @date 2022-11-24 0:51* crawlerJ:com.xiaoxu.crawler.utils.IfElseUtils*/
public class IfElseUtils {/* if-else void-template */public static void executeBothSide(boolean flag, ActionCallBack callBack){if(flag){callBack.actionTrue();}else{callBack.actionFalse();}}/* if-else T-value-template */public static  T executeBothSideWithValue(boolean flag, ActionCallBackWithValue callBack){if(flag){return callBack.actionTrue();}else{return callBack.actionFalse();}}public interface ActionCallBackWithValue{/* 为真时 */T actionTrue();/* 为假时 */T actionFalse();}public interface ActionCallBack{/* 为真时 */void actionTrue();/* 为假时 */void actionFalse();}
}

ExcpUtils:

package com.xiaoxu.crawler.utils;import com.xiaoxu.crawler.excp.AccessParamException;
import com.xiaoxu.crawler.excp.CrawlerForJException;
import org.springframework.util.StringUtils;/*** @author xiaoxu* @date 2022-11-06 16:04* crawlerJ:com.xiaoxu.crawler.utils.ExcpUtils*/
public class ExcpUtils {/* 不为true则抛出异常 */public static void throwExpIfFalse(boolean result,String msg){if(StringUtils.hasLength(msg)&&!result){throw new CrawlerForJException(msg);}else if(!StringUtils.hasLength(msg)){throw new AccessParamException(String.format("调用throwExpIfFalse方法的msg不能为空:%s",msg));}}/* 抛出异常的工具方法 */public static void throwExp(String message){if(StringUtils.hasLength(message)){throw new CrawlerForJException(message);}else{throw new AccessParamException(String.format("方法%s的参数不能为空:%s",ExcpUtils.class.getSimpleName()+Thread.currentThread().getStackTrace()[1].getMethodName(),message));}}
}

StrUtils:

package com.xiaoxu.crawler.utils;import org.springframework.util.StringUtils;import java.text.MessageFormat;/*** @author xiaoxu* @date 2022-11-19 21:52* crawlerJ:com.xiaoxu.crawler.utils.StringUtils*/
public class StrUtils {public static boolean equals(String a, String b){if(null == a){return null == b;}return a.equals(b);}public static int getMatchCount(String str, String subStr){if(!StringUtils.hasLength(str) || !StringUtils.hasLength(subStr)){ExcpUtils.throwExp(MessageFormat.format("getMatchCount's str and subStr should not be null or empty:{0},{1}.",str, subStr));}return StringUtils.countOccurrencesOf(str, subStr);}}

AssertUtils:

package com.xiaoxu.crawler.utils;import com.xiaoxu.crawler.excp.CrawlerForJException;
import org.apache.commons.lang3.ArrayUtils;/*** @author xiaoxu* @date 2022-11-06 15:50* crawlerJ:com.xiaoxu.crawler.utils.AssertUtils*/
public class AssertUtils {/* 校验为真 */public static void assertTrue(boolean res, String errorMsg){handlerError(res, errorMsg);}/* 校验非空 */public static  void assertNonNull(T obj, String errorMsg){handlerError(null != obj, errorMsg);}/* 校验非null非empty字符串 */public static  void assertNonEmpty(String str, String errorMsg){handlerError(null != str && !str.isEmpty(), errorMsg);}/* 校验非空Array */public static  void assertNonEmptyArray(T[] array, String errorMsg){handlerError(!ArrayUtils.isEmpty(array), errorMsg);}/* 统一异常处理 */private static void handlerError(boolean flag, String message){if(!flag){/* 使用公共异常处理 */throw new CrawlerForJException(message);}}
}

执行结果如下:

12:46:16.779 [main] INFO com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.744 - info] 今天星期是12
12:46:16.782 [main] INFO com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.782 - info] 今天星期是
12:46:16.782 [main] WARN com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.782 - warn] 空指针异常!please check
12:46:16.782 [main] ERROR com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.782 - error] 严重错误!!!参数:,123
12:46:16.782 [main] INFO com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.782 - info] 调用[getYou]方法, 请求参数:[123], 耗时:[2121]ms.
12:46:16.782 [main] WARN com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.782 - warn] 调用[getYou]方法, 请求参数:[123], 耗时:[2121]ms.
12:46:16.782 [main] ERROR com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.782 - error] 调用[getYou]方法, 请求参数:[123], 耗时:[2121]ms.
12:46:16.782 [main] INFO com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.782 - info] 成功!!

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...