1. 程式人生 > >SpringBoot系列(十三)統一日誌處理,logback+slf4j AOP+自定義註解,走起!

SpringBoot系列(十三)統一日誌處理,logback+slf4j AOP+自定義註解,走起!

**往期精彩推薦** [SpringBoot系列(一)idea新建Springboot專案](https://www.cnblogs.com/swzx-1213/p/12345330.html) [SpringBoot系列(二)入門知識](https://www.cnblogs.com/swzx-1213/p/12637645.html) [springBoot系列(三)配置檔案詳解](https://www.cnblogs.com/swzx-1213/p/12641842.html) [SpringBoot系列(四)web靜態資源配置詳解](https://www.cnblogs.com/swzx-1213/p/12686361.html) [SpringBoot系列(五)Mybatis整合完整詳細版](https://www.cnblogs.com/swzx-1213/p/12698222.html) [SpringBoot系列(六)整合thymeleaf詳解版](https://www.cnblogs.com/swzx-1213/p/12726432.html) [Springboot系列(七) 整合介面文件swagger,使用,測試](https://www.cnblogs.com/swzx-1213/p/12736993.html) [SpringBoot系列(八)分分鐘學會Springboot多種解決跨域方式](https://www.cnblogs.com/swzx-1213/p/12745086.html) [SpringBoot系列(九)單,多檔案上傳的正確姿勢](https://www.cnblogs.com/swzx-1213/p/12756239.html) [SpringBoot系列(十)優雅的處理統一異常處理與統一結果返回](https://www.cnblogs.com/swzx-1213/p/12781836.html) [SpringBoot系列(十一)攔截器與攔截器鏈的配置與使用詳解,你知道多少?](https://www.cnblogs.com/swzx-1213/p/12788576.html) [SpringBoot系列(十二)過濾器配置詳解](https://www.cnblogs.com/swzx-1213/p/12814734.html) **本文目錄** - [一、SpringBoot中的日誌](#一springboot中的日誌) - [二、自定義日誌常用配置](#二自定義日誌常用配置) - [1. 日誌輸出級別](#1-日誌輸出級別) - [2. 日誌輸出到檔案](#2-日誌輸出到檔案) - [3. 自定義日誌輸出格式](#3-自定義日誌輸出格式) - [三、xml檔案實現日誌配置的方式](#三xml檔案實現日誌配置的方式) - [四、AOP + 自定義註解實現統一日誌處理](#四aop--自定義註解實現統一日誌處理) - [五、總結](#五、總結) ## 一、SpringBoot中的日誌 ##  在我們執行專案的時候,你會發現控制檯是有日誌列印的,這個日誌就是SpringBoot預設配置的日誌框架處理的。SpringBoot預設是運用logback+slf4j處理日誌,slf4j是抽象層,logback是實現層。  但是不同的框架可能會有不同日誌處理方式,如果我們在SpringBoot中集成了不同的框架的話,是不是日誌的輸出也會混亂呢?很顯然,如果你有一點經驗的話,你會發現,只要你不修改SpringBoot的預設日誌配置,它的日誌輸出格式是不會變得。這是因為,在SpringBoot管理日誌的時候,它都將其他框架的日誌通過一些中間包的形式將其他的日誌抽象成了slf4j介面,而統一用logback的形式實現。  本文我們來講講怎麼來配置日誌格式以及運用AOP+自定義註解簡化日誌的記錄。 ## 二、自定義日誌常用配置 ## ### 1. 日誌輸出級別  SpringBoot中預設的日誌輸出級別是info,也就是說我們平常在控制檯輸出的那些日誌都是info級別以及更高級別的日誌。我們可以自己定義日誌的輸出級別,一般有以下幾個級別: ``` trace,debug,info,warn,error //級別遞增 ```  trace 是追蹤日誌,debug是調式日誌,info一般是自定義日誌或者是資訊日誌,warn是警告日誌,error則是錯誤日誌。  可能這麼說你也不知道這個級別有什麼用,來看看這個程式碼: ```java @RestController public class TestLogController { Logger logger = LoggerFactory.getLogger(TestLogController.class); @GetMapping("/testLog") public void testLog(){ logger.trace("這是trace級別的日誌"); logger.debug("這是debug級別的日誌"); logger.info("這是正常自定義日誌"); logger.warn("這是警告日誌"); logger.error("這是錯誤日誌"); } } ``` **程式碼說明:**(上面的Logger包這裡是使用的org.slf4j.Logger)  首先我們獲取一個日誌記錄器Logger物件,然後分別在程式碼中記錄不同級別日誌的輸出。執行專案,然後訪問介面。 ![](https://img2020.cnblogs.com/blog/1728419/202005/1728419-20200507092228928-638912499.png)  你會發現前面的trace日誌和debug日誌是不會輸出的,這你就知道了吧,不同等級的日誌有不同的功效,只會在特定的情況下輸出。這時候我們也可以自定義日誌級別了,在配置檔案(yml) ```properties logging: level: com: example: demolog: debug ``` **配置說明:**  這是什麼意思呢?我的包名是com.example.demolog,所以說這個配置就是說配置日誌所在包的輸出級別,是不是很高階。這樣就能輸出debug日誌了。如果你想輸出trace日誌你就將等級設定為trace就行了。 ![](https://img2020.cnblogs.com/blog/1728419/202005/1728419-20200507092220155-778653060.png) ### 2. 日誌輸出到檔案  日誌輸出到控制檯檢視起來不是很方便,怎麼辦?沒關係,SpringBoot中還能將日誌輸出到指定的檔案中,yml,新增如下配置。 ```properties logging: file: path: /spring/test/ ```  這個配置是說將日誌輸出到指定的**目錄檔案**,並且會生成一個**spring.log**的日誌檔案用來記錄日誌(如果你自己指定了檔名,它就會按照你自己設定的名字生成檔案。),執行專案你就能直接看到生成的日誌所在,這個目錄如果你寫的和**上面一致**,那麼你的日誌檔案就會在專案的**執行根路徑**,比如D盤,然後在D盤生成你寫的檔案目錄/spring/test/,最後在檔案目錄下面生成**spring.log**的日誌檔案。這個路徑你也可以直接寫**絕對路徑**(直接指定這個檔案在那個盤,那個資料夾)。  file下面還有一個配置就是name屬性, ```properties logging: file: name: test.log ```  這個是直接指定你的日誌的檔名稱,預設生成的位置是在**專案所在的目錄**,你也可以自己寫**絕對路徑**配置日誌檔案的位置,但是**必須**要自己設定檔案的名稱。  file的name屬性和path屬性**只能**指定一個,如果**兩個同時**指定的話,只有**name**屬性會生效。 ### 3. 自定義日誌輸出格式 ###  有時候你可能會覺得這個日誌的輸出格式太難看了,想自己定義一個日誌輸出格式,完全ojbk!SpringBoot說:滿足你,自己想怎麼玩就怎麼玩! ```properties logging: pattern: console: "%d{yyyy-MM-dd HH:mm:ss}----- 這是全棧學習筆記 [%thread] %-5level %logger{50} - %msg%n" file: "%d{yyyy-MM-dd HH:mm:ss}----- 這是全棧學習筆記 [%thread] %-5level %logger{50} - %msg%n" # d表示日期時間,         # %thread表示執行緒名,         # %‐5level:級別從左顯示5個字元寬度         # %logger{50} 表示logger名字最長50個字元,否則按照句點分割。   # %msg:日誌訊息,         # %n是換行符 ```  上面的配置分別定義了控制檯的日誌輸出格式與檔案的日誌輸出格式,是不是很方便。輸出的格式大概就是這樣。 ![](https://img2020.cnblogs.com/blog/1728419/202005/1728419-20200507092206742-1588010211.png)  當然我們還有一個更好的日誌配置,利用xml檔案進行配置,一步到位就是這麼爽。 ## 三、xml檔案實現日誌配置的方式 ##  直接上xml檔案的內容,建議將檔案命名為**logback-spring.xml** ```xml ```  上面的xml配置檔案配置就不細說了,裡面都有詳細的註釋說明。配置檔案預設位置應該是直接放在**resources**下面,和**yml,properties**檔案**同級**,當然你也可以自己配置檔案位置的。 ```properties logging config: classpath:static/logback.xml ```  這樣就將xml配置檔案放在static路徑下面時能自動識別了。也可以設定為絕對路徑。  上面我們建議將日誌檔案設定為**logback-spring.xml**,如果我們的xml檔案的名稱是**logback.xml**,它就會直接被**日誌框架**識別,如果你的xml檔案是用logback-spring.xml命名,那麼他會被**SpringBoot**來識別並解析日誌配置,可以使用SpringBoot的**高階Profile功能**。這個高階功能我在xml檔案中有註釋說明。往上看。你也可以去看Spring的官網,有詳細的配置說明。 ## 四、AOP + 自定義註解實現統一日誌處理 ##  引入aop依賴: ```xml ```  自定義註解,還不會註解的,看這裡,註解詳細介紹[註解乾貨](https://www.cnblogs.com/swzx-1213/p/12606630.html) ```java @Documented @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyLog { String value() default ""; } ```  自定義切面類: ```java @Aspect @Component public class LogAspect { private Logger logger = LoggerFactory.getLogger(LogAspect.class); @Pointcut("@annotation(com.example.demolog.annotation.MyLog)") public void myPointCut(){ //簽名,可以理解成這個切入點的一個名稱 } @Before("myPointCut()") public void doBefore(JoinPoint joinPoint){ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); //獲取url,請求方法,ip地址,類名以及方法名,引數 logger.info("url={},method={},ip={},class_method={},args={}", request.getRequestURI(),request.getMethod(),request.getRemoteAddr(),joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName(),joinPoint.getArgs()); } @AfterReturning(pointcut = "myPointCut()") public void printLog(JoinPoint joinPoint){ MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); Method method = methodSignature.getMethod(); MyLog myLog = method.getAnnotation(MyLog.class); String value = null; if (myLog!=null){ value = myLog.value(); } logger.info(new Date()+"-----"+value); } } ```  上面配置完成之後再去**controller**的方法之上新增一個自定義的 **@Mylog**註解 ``` @GetMapping("/testLog") @MyLog("測試一個日誌") public void testLog(){ //和上面的一致 } ``` **程式碼說明:** * **@Aspect**:標明這是一個切面類 * **@Component**:標明這是一個bean * **@Pointcut**("@annotation(com.example.demolog.annotation.MyLog)") 定義切入點為自定義的註解,也可以是一個類或者是一個包,包的寫法如下: ``` @Pointcut("execution(public * com.example.demolog.*(..))") ```  上面的意思是切入點是 所有在com.example,demolog包下面的以public為修飾,不限制返回值(*),不限制引數不限制名稱的類。 **擴充套件知識:** * **@befor**:前置通知,在一個方法執行之前被呼叫。 * **@after**:在方法執行之後呼叫的通知,無論方法執行是否成功。 * **@after-returning**:僅當方法成功完成之後通知。 * **@after-throwing**:在方法丟擲異常退出時執行的通知。 * **@around**:在方法執行之前和之後呼叫的通知。  然後我們再來測試一下介面:localhost:8098/testLog ![](https://img2020.cnblogs.com/blog/1728419/202005/1728419-20200507092115588-270603984.png) 本期分享到此結束,總結一下下! ## 五、總結 ##  本文先講解SpringBoot的預設日誌配置,然後自己在配置檔案配置日誌的輸出等級,輸出格式,將日誌輸出到檔案中,然後通過xml檔案來配置日誌。最後我們引出了利用aop,簡化日誌的輸出,並且統一日誌的輸出格式。如果你覺得本文有用的話,點個贊吧!另外需要原始碼的看下面。 ![](https://img2020.cnblogs.com/blog/1728419/202005/1728419-20200507092106101-19548199