欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring如何實現(xiàn)輸出帶動態(tài)標簽的日志

 更新時間:2025年01月10日 14:49:43   作者:keep丶  
文章介紹了如何通過動態(tài)標簽日志實現(xiàn),解決了部分業(yè)務代碼在多個模塊中調(diào)用時日志無法直觀看出來源的問題,主要通過ThreadLocal存儲業(yè)務標簽,并在日志輸出時插入該標簽,實現(xiàn)日志的動態(tài)標簽功能,感興趣的朋友一起看看吧

版權說明: 本文由CSDN博主keep丶原創(chuàng),轉載請保留此塊內(nèi)容在文首。
原文地址: https://blog.csdn.net/qq_38688267/article/details/145022997

背景

  部分業(yè)務代碼會被多個模塊調(diào)用,此時該部分代碼輸出的日志無法直觀看出是從哪個模塊調(diào)用的,因此提出動態(tài)標簽日志需求,效果如下:

底層原理

  業(yè)務代碼起始時通過ThreadLocal存儲當前業(yè)務標簽值,后續(xù)日志輸出時,插入緩存的業(yè)務標簽到輸出的日志中。即可實現(xiàn)該需求。

實現(xiàn)方案

Tag緩存實現(xiàn)

    private static final ThreadLocal<String> logTagCache = new ThreadLocal<>();
    /**
     * 獲取緩存的標簽值
     * <b style="color:red">只有添加了@BizLog注解的方法內(nèi)才可用</b>
     */
    static String getCacheTag() {
        String temp = logTagCache.get();
        if (temp == null) {
            log.warn("[LogHelper] 緩存標簽為空, 請及時配置@BizLog注解或手動緩存標簽.");
            return DEFAULT_TAG;
        }
        return temp;
    }
    static void cacheTag(String logTag) {
        logTagCache.set(logTag);
    }
    /**
     * 清空當前線程緩存
     * <br/>
     * <b>使用set()或init()之后,請在合適的地方調(diào)用clean(),一般用try-finally語法在finally塊中調(diào)用</b>
     */
    static void cleanCache() {
        logTagCache.remove();
    }

封裝注解通過AOP實現(xiàn)日志緩存

注解定義

/**
 * 啟動業(yè)務日志注解
 *
 * @author zeng.zf
 */
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface BizLog {
    /**
     * 日志標簽值
     * <p>
     * 如果不給值則默認輸出類型方法名,給值用給的值<br/>
     * <b>會緩存標簽值,可使用{@code LogHelper.xxxWCT()}方法</b>
     * @see cn.xxx.log.util.LogHelper.WCT#catchLog(Logger, Runnable)
     * @see cn.xxx.log.util.LogHelper.WCT#log(String, Object...) 
     */
    String value();
}

AOP切面配置

/**
 * {@link BizLog} 切面,記錄業(yè)務鏈路
 *
 * @author zzf
 */
@Aspect
@Order// 日志的AOP邏輯放最后執(zhí)行
public class BizLogAspect {
    @Around("@annotation(bizLog)")
    public Object around(ProceedingJoinPoint joinPoint, BizLog bizLog) throws Throwable {
        try {
	        LogHelper.UTIL.cacheTag(bizLog.value());
            return joinPoint.proceed();
        }  finally {
            LogHelper.UTIL.cleanCache();
        }
    }

封裝行為參數(shù)通用方法實現(xiàn)

        /**
         * 緩存給定tag后執(zhí)行給定方法<br/>
         * 使用:{@code LogHelper.beginTrace("AddUser", () -> userService.addUser(user))}
         *
         * @param tag      日志標簽
         * @param runnable 執(zhí)行內(nèi)容
         */
        static void beginTrace(String tag, Runnable runnable) {
            try {
                cacheTag(tag);
                runnable.run();
            } finally {
                cleanCache();
            }
        }
        /**
         * 緩存給定tag后執(zhí)行給定方法<br/>
         * 使用:{@code return LogHelper.beginTrace("AddUser", () -> userService.addUser(user))}
         *
         * @param tag      日志標簽
         * @param supplier 有返回值的執(zhí)行內(nèi)容
         */
        static <T> T beginTrace(String tag, Supplier<T> supplier) {
            try {
                cacheTag(tag);
                return supplier.get();
            } finally {
                cleanCache();
            }
        }

手動緩存Tag值

  • 非Bean方法可通過手動調(diào)用LogHelper.UTIL.beginTrace()方法實現(xiàn)@BizLog相同功能。
  • 也可以參考方法手寫cacheTag()和cleanCache()實現(xiàn)該功能。
    • 一般不建議這么做,使用工具類方法最好。
    • 如果runnable參數(shù)會拋異常的情況下就不適合用工具方法,此時可以手寫。
    • 手寫時必須使用try-finally塊,并在finally塊中調(diào)用cleanCache()。

 整理代碼,封裝通用LogHelper類

/**
 * 日志輸出輔助類
 * <br/>
 * 注意:所有格式化參數(shù)在格式化時都是調(diào)用其toString()方法<br/>
 * 因此對象需要重寫toString()方法或者使用{@code JSONUtil.toJsonStr()}轉成JSON字符串。<br/>
 * <br/>
 * <b>如果自行輸出日志,請按照該格式: {@code "[TAG][SUB_TAG] CONTENT"}</b>
 * <p>如: 1. {@code "[AddUser] add success"}</p>
 * <p>&emsp;&emsp;2. {@code "[AddUser][GenRole] add success"}</p>
 * <p>&emsp;&emsp;2. {@code "[AddUser][BizException] 用戶名重復"}</p>
 * <p>更多請參考源文件中的LogHelperTest測試類</p>
 */
@Slf4j
public class LogHelper {
    /**
     * 緩存{@link cn.xxx.log.core.aop.log.BizLog} 注解的value值
     */
    private static final ThreadLocal<String> logTagCache = new ThreadLocal<>();
    private static final String DEFAULT_TAG = "TAG_NOT_CONFIG";
    /*===========以下為工具方法,提供Tag緩存相關方法============*/
    public interface UTIL {
        /**
         * 緩存給定tag后執(zhí)行給定方法<br/>
         * 使用:{@code LogHelper.beginTrace("AddUser", () -> userService.addUser(user))}
         *
         * @param tag      日志標簽
         * @param runnable 執(zhí)行內(nèi)容
         */
        static void beginTrace(String tag, Runnable runnable) {
            try {
                cacheTag(tag);
                runnable.run();
            } finally {
                cleanCache();
            }
        }
        /**
         * 緩存給定tag后執(zhí)行給定方法<br/>
         * 使用:{@code return LogHelper.beginTrace("AddUser", () -> userService.addUser(user))}
         *
         * @param tag      日志標簽
         * @param supplier 有返回值的執(zhí)行內(nèi)容
         */
        static <T> T beginTrace(String tag, Supplier<T> supplier) {
            try {
                cacheTag(tag);
                return supplier.get();
            } finally {
                cleanCache();
            }
        }
        /**
         * 緩存給定tag后執(zhí)行給定方法,提供默認異常處理<br/>
         * 使用:{@code LogHelper.catchBeginTrace(log, "AddUser", () -> userService.addUser(user))}
         *
         * @param tag      日志標簽
         * @param runnable 執(zhí)行內(nèi)容
         */
        static void catchBeginTrace(Logger logger, String tag, Runnable runnable) {
            try {
                cacheTag(tag);
                WCT.catchLog(logger, runnable);
            } finally {
                cleanCache();
            }
        }
        /**
         * 緩存給定tag后執(zhí)行給定方法,提供默認異常處理<br/>
         * 使用:{@code return LogHelper.catchBeginTrace(log, "AddUser", () -> userService.addUser(user))}
         *
         * @param tag      日志標簽
         * @param supplier 有返回值的執(zhí)行內(nèi)容
         */
        static <T> @Nullable T catchBeginTrace(Logger logger, String tag, Supplier<T> supplier) {
            try {
                cacheTag(tag);
                return WCT.catchLog(logger, supplier);
            } finally {
                cleanCache();
            }
        }
        /**
         * 獲取緩存的標簽值
         * <b style="color:red">只有添加了@BizLog注解的方法內(nèi)才可用</b>
         */
        static String getCacheTag() {
            String temp = logTagCache.get();
            if (temp == null) {
                log.warn("[LogHelper] 緩存標簽為空, 請及時配置@BizLog注解或手動緩存標簽.");
                return DEFAULT_TAG;
            }
            return temp;
        }
        static void cacheTag(String logTag) {
            logTagCache.set(logTag);
        }
        /**
         * 清空當前線程緩存
         * <br/>
         * <b>使用set()或init()之后,請在合適的地方調(diào)用clean(),一般用try-finally語法在finally塊中調(diào)用</b>
         */
        static void cleanCache() {
            logTagCache.remove();
        }
    }
    /*=========================以下為基礎方法,提供基礎日志輸出方法=======================*/
    public interface BASIC {
        /**
         * 標簽日志<br/>
         * 例:
         * {@code LogHelper.tag("AddUser", "GenRole", "add success, user id = {}, name = {}", 1L, "zs")}<br/>
         * 返回 {@code "[AddUser][GenRole] add success, user id = 1, name = zs"}
         *
         * @param tag     標簽
         * @param content 需要格式化內(nèi)容
         * @param arg     格式化參數(shù)
         * @return 最終日志
         */
        static String tag(String tag, String content, Object... arg) {
            return StrUtil.format("[{}] {}", tag, StrUtil.format(content, arg));
        }
        /**
         * 兩級標簽日志<br/>
         * 例:
         * {@code LogHelper.tag("AddUser", "GenRole", "add success")}<br/>
         * 返回 {@code "[AddUser][GenRole] add success"}
         *
         * @param tag     標簽
         * @param subTag  子標簽
         * @param content 內(nèi)容
         * @return 最終日志
         */
        static String doubleTag(String tag, String subTag, String content, Object... args) {
            return StrUtil.format("[{}][{}] {}", tag, subTag, StrUtil.format(content, args));
        }
        /**
         * 業(yè)務異常tag日志內(nèi)容生成
         */
        static String bizExTag(String tag, BizExceptionMark bizException) {
            return StrUtil.format("[{}][{}] code={},msg={}", tag, bizException.getClass().getSimpleName(),
                                  bizException.getCode(), bizException.getMsg());
        }
        /**
         * 業(yè)務異常tag日志內(nèi)容生成
         */
        static String bizExTag(String tag, BizExceptionMark bizException, String extraInfo, Object... args) {
            return StrUtil.format("[{}][{}] code={},msg={}, extraInfo={{}}", tag,
                                  bizException.getClass().getSimpleName(), bizException.getCode(),
                                  bizException.getMsg(), StrUtil.format(extraInfo, args));
        }
        /**
         * 業(yè)務異常tag日志內(nèi)容生成
         */
        static String bizEx(BizExceptionMark bizException) {
            return StrUtil.format("[{}] code={},msg={}", bizException.getClass().getSimpleName(),
                                  bizException.getCode(), bizException.getMsg());
        }
        /**
         * 運行時異常tag日志內(nèi)容生成
         */
        static String otherExTag(String tag, Exception e) {
            return StrUtil.format("[{}][{}] msg={}, stackTrace={}", tag, e.getClass().getSimpleName(), e.getMessage(),
                                  TraceUtils.getStackTraceStr(e.getStackTrace()));
        }
        /**
         * 運行時異常tag日志內(nèi)容生成
         */
        static String otherExTag(String tag, Exception e, String extraInfo, Object... args) {
            return StrUtil.format("[{}][{}] msg={}, extraInfo={{}}, stackTrace={}", tag, e.getClass().getSimpleName(),
                                  e.getMessage(), StrUtil.format(extraInfo, args),
                                  TraceUtils.getStackTraceStr(e.getStackTrace()));
        }
        /**
         * 其他異常tag日志內(nèi)容生成
         */
        static String otherEx(Exception e) {
            return StrUtil.format("[{}] msg={}, stackTrace={}", e.getClass().getSimpleName(), e.getMessage(),
                                  TraceUtils.getStackTraceStr(e.getStackTrace()));
        }
        /**
         * 通用標簽日志包裝<br/>
         * <p>使用案例:</p>
         * 1. {@code tagLogWrap(() -> bizMethod(param1, param2))}<br/>
         * 2.
         * <pre><code>
         * \@Slf4j
         * public class UserServiceImpl{
         *
         *     public void addUsers(List<User> users) {
         *          for(user in users) {
         *              LogHelper.tagLogWrap(log, "AddUsers", () -> addUser(user));
         *          }
         *     }
         *     public void addUser(User user) {
         *         xxx
         *         xxx
         *         ...
         *     }
         * }
         * </code></pre>
         *
         * @param tag      日志標簽
         * @param runnable 你要執(zhí)行的無返回值方法
         */
        static void catchLog(Logger logger, String tag, Runnable runnable) {
            try {
                runnable.run();
            } catch (Exception e) {
                if (e instanceof BizExceptionMark) {
                    logger.warn(bizExTag(tag, (BizExceptionMark) e));
                } else {
                    logger.error(otherExTag(tag, e));
                }
            }
        }
        /**
         * 通用標簽日志包裝<br/>
         * <p>使用案例:</p>
         * 1. {@code tagLogWrap(() -> bizMethod(param1, param2))}<br/>
         * 2.
         * <pre><code>
         * \@Slf4j
         * public class UserServiceImpl{
         *
         *     public void addUsers(List<User> users) {
         *          for(user in users) {
         *              LogHelper.tagLogWrap(
         *                  log,
         *                  "AddUsers",
         *                  () -> addUser(user),
         *                  "id = {}, name={}",
         *                  user.getId(),
         *                  user.getName()
         *                  );
         *          }
         *     }
         *     public void addUser(User user) {
         *         xxx
         *         xxx
         *         ...
         *     }
         * }
         * </code></pre>
         *
         * @param tag      日志標簽
         * @param runnable 你要執(zhí)行的無返回值方法
         */
        static void catchLog(Logger logger, String tag, Runnable runnable, String extraInfo, Object... args) {
            try {
                runnable.run();
            } catch (Exception e) {
                if (e instanceof BizExceptionMark) {
                    logger.warn(bizExTag(tag, (BizExceptionMark) e, extraInfo, args));
                } else {
                    logger.error(otherExTag(tag, e, extraInfo, args));
                }
            }
        }
        /**
         * 通用標簽日志包裝<br/>
         * <p>使用案例:</p>
         * 1. {@code return tagLogWrap(() -> bizMethod(param1, param2))}<br/>
         * 2.
         * <pre><code>
         * \@Slf4j
         * public class UserServiceImpl{
         *
         *     public List<User> getUserByIds(List<Long> ids) {
         *          return ids.map(id ->
         *              LogHelper.tagLogWrap(log, "getUserByIds", () -> getUserById(id))
         *          ).collect(Collectors.toList());
         *     }
         *     public User getUserById(Long userId) {
         *         xxx
         *         xxx
         *         ...
         *         return user;
         *     }
         * }
         * </code></pre>
         *
         * @param tag      日志標簽
         * @param supplier 你要執(zhí)行的有返回值方法
         * @return 方法執(zhí)行結果(可能為null)
         */
        static <R> @Nullable R catchLog(Logger logger, String tag, Supplier<R> supplier) {
            try {
                return supplier.get();
            } catch (Exception e) {
                if (e instanceof BizExceptionMark) {
                    logger.warn(bizExTag(tag, (BizExceptionMark) e));
                } else {
                    logger.error(otherExTag(tag, e));
                }
            }
            return null;
        }
        /**
         * 通用標簽日志包裝<br/>
         * <p>使用案例:</p>
         * 1. {@code return tagLogWrap(() -> bizMethod(param1, param2))}<br/>
         * 2.
         * <pre><code>
         * \@Slf4j
         * public class UserServiceImpl{
         *
         *     public List<User> getUserByIds(List<Long> ids) {
         *          return ids.map(id ->
         *              LogHelper.tagLogWrap(
         *                  log,
         *                  "getUserByIds",
         *                  () -> getUserById(id),
         *                  "id={}",
         *                  id
         *                  )
         *          ).collect(Collectors.toList());
         *     }
         *     public User getUserById(Long userId) {
         *         xxx
         *         xxx
         *         ...
         *         return user;
         *     }
         * }
         * </code></pre>
         *
         * @param tag      日志標簽
         * @param supplier 你要執(zhí)行的有返回值方法
         * @return 方法執(zhí)行結果(可能為null)
         */
        static <R> @Nullable R catchLog(Logger logger, String tag, Supplier<R> supplier, String extraInfo,
                                        Object... args) {
            try {
                return supplier.get();
            } catch (Exception e) {
                if (e instanceof BizExceptionMark) {
                    logger.warn(bizExTag(tag, (BizExceptionMark) e, extraInfo, args));
                } else {
                    logger.error(otherExTag(tag, e, extraInfo, args));
                }
            }
            return null;
        }
    }
    /*===================以下為基于緩存標簽的方法,理論上上方基礎方法都要在下面有對應的方法==================*/
    /* WCT = with cached tag */
    public interface WCT {
        /**
         * <b style="color:red">只有添加了@BizLog注解的方法內(nèi)才可用</b>
         */
        static String log(String content, Object... args) {
            return BASIC.tag(getCacheTag(), content, args);
        }
        /**
         * <b style="color:red">只有添加了@BizLog注解的方法內(nèi)才可用</b>
         */
        static String sub(String subTag, String content, Object... args) {
            return BASIC.doubleTag(getCacheTag(), subTag, content, args);
        }
        /**
         * 業(yè)務異常tag日志內(nèi)容生成
         * <b style="color:red">只有添加了@BizLog注解的方法內(nèi)才可用</b>
         */
        static String bizEx(BizExceptionMark bizException) {
            return BASIC.bizExTag(getCacheTag(), bizException);
        }
        /**
         * 業(yè)務異常tag日志內(nèi)容生成
         * <b style="color:red">只有添加了@BizLog注解的方法內(nèi)才可用</b>
         */
        static String bizEx(BizExceptionMark bizException, String extraInfo, Object... args) {
            return BASIC.bizExTag(getCacheTag(), bizException, extraInfo, args);
        }
        /**
         * 運行時異常tag日志內(nèi)容生成
         * <b style="color:red">只有添加了@BizLog注解的方法內(nèi)才可用</b>
         */
        static String otherEx(Exception e) {
            return BASIC.otherExTag(getCacheTag(), e);
        }
        /**
         * 運行時異常tag日志內(nèi)容生成
         * <b style="color:red">只有添加了@BizLog注解的方法內(nèi)才可用</b>
         */
        static String otherEx(String tag, Exception e, String extraInfo, Object... args) {
            return BASIC.otherExTag(tag, e, extraInfo, args);
        }
        /**
         * 通用標簽日志包裝<br/>
         * <b style="color:red">只有添加了@BizLog注解的方法內(nèi)才可用</b>
         *
         * @param runnable 你要執(zhí)行的無返回值方法
         */
        static void catchLog(Logger logger, Runnable runnable) {
            BASIC.catchLog(logger, getCacheTag(), runnable);
        }
        /**
         * 通用標簽日志包裝<br/>
         * <b style="color:red">只有添加了@BizLog注解的方法內(nèi)才可用</b>
         *
         * @param runnable 你要執(zhí)行的無返回值方法
         */
        static void catchLog(Logger logger, Runnable runnable, String extraInfo, Object... args) {
            BASIC.catchLog(logger, getCacheTag(), runnable, extraInfo, args);
        }
        /**
         * 通用標簽日志包裝<br/>
         * <b style="color:red">只有添加了@BizLog注解的方法內(nèi)才可用</b>
         *
         * @param supplier 你要執(zhí)行的有返回值方法
         * @return 方法執(zhí)行結果(可能為null)
         */
        static <R> @Nullable R catchLog(Logger logger, Supplier<R> supplier) {
            return BASIC.catchLog(logger, getCacheTag(), supplier);
        }
        /**
         * 通用標簽日志包裝<br/>
         * <b style="color:red">只有添加了@BizLog注解的方法內(nèi)才可用</b>
         *
         * @param supplier 你要執(zhí)行的有返回值方法
         * @return 方法執(zhí)行結果(可能為null)
         */
        static <R> @Nullable R catchLog(Logger logger, Supplier<R> supplier, String extraInfo, Object... args) {
            return BASIC.catchLog(logger, getCacheTag(), supplier, extraInfo, args);
        }
    }
}

相關資料

Spring實現(xiàn)Logback日志模板設置動態(tài)參數(shù)

Spring實現(xiàn)通過工具類統(tǒng)一輸出日志(不改變?nèi)罩绢愋畔?

到此這篇關于Spring實現(xiàn)輸出帶動態(tài)標簽的日志的文章就介紹到這了,更多相關Spring動態(tài)標簽的日志內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java8中對泛型目標類型推斷方法的改進

    Java8中對泛型目標類型推斷方法的改進

    這篇文章主要介紹了Java8中對泛型目標類型推斷方法的改進,需要的朋友可以參考下
    2014-06-06
  • Maven依賴管理的用法介紹

    Maven依賴管理的用法介紹

    依賴管理是項目管理中非常重要的一環(huán)。幾乎任何項目開發(fā)的時候需要都需要使用到庫。而這些庫很可能又依賴別的庫,這樣整個項目的依賴形成了一個樹狀結構,而隨著這個依賴的樹的延伸和擴大,一系列問題就會隨之產(chǎn)生
    2022-08-08
  • 關于文件上傳MultipartBody的使用方法

    關于文件上傳MultipartBody的使用方法

    這篇文章主要介紹了關于文件上傳MultipartBody的使用方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • 淺談@RequestParam(required = true)的誤區(qū)

    淺談@RequestParam(required = true)的誤區(qū)

    這篇文章主要介紹了@RequestParam(required = true)的誤區(qū),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • JAVA實現(xiàn)生成短鏈接的示例代碼

    JAVA實現(xiàn)生成短鏈接的示例代碼

    短鏈接就是將長度較長的鏈接壓縮成較短的鏈接,本文就來介紹一下JAVA實現(xiàn)生成短鏈接的示例代碼,具有一定的參考價值,感興趣的可以了解一下
    2023-08-08
  • 記錄jdk21連接SQLServer因為TLS協(xié)議報錯問題

    記錄jdk21連接SQLServer因為TLS協(xié)議報錯問題

    在使用Druid連接池連接SQL Server時,可能會遇到因TLS版本不匹配導致的連接失敗問題,具體表現(xiàn)為客戶端使用TLS1.3或TLS1.2,而SQL Server僅支持TLS1.0,導致無法建立安全連接,解決方法是修改JDK的安全配置,啟用TLS1.0
    2024-10-10
  • 從SpringMVC遷移到Springboot的方法步驟

    從SpringMVC遷移到Springboot的方法步驟

    本篇文章主要介紹了從SpringMVC遷移到Springboot的方法步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • Java編程rabbitMQ實現(xiàn)消息的收發(fā)

    Java編程rabbitMQ實現(xiàn)消息的收發(fā)

    RabbitMQ是一個在AMQP基礎上完成的,可復用的企業(yè)消息系統(tǒng),本文通過實例來給大家分享通過操作rabbitMQ實現(xiàn)消息的收發(fā),感興趣的朋友可以參考下。
    2017-09-09
  • Java模擬實現(xiàn)HTTP服務器項目實戰(zhàn)

    Java模擬實現(xiàn)HTTP服務器項目實戰(zhàn)

    本文主要介紹了Java模擬實現(xiàn)HTTP服務器項目實戰(zhàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • PowerJob的TimingStrategyHandler工作流程源碼解讀

    PowerJob的TimingStrategyHandler工作流程源碼解讀

    這篇文章主要為大家介紹了PowerJob的TimingStrategyHandler工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01

最新評論