日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
日志配置熱更新技術(shù)實(shí)踐

一 為什么需要服務(wù)日志熱更新?

成都創(chuàng)新互聯(lián)成立于2013年,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元官渡做網(wǎng)站,已為上家服務(wù),為官渡各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:13518219792

對(duì)于后端老鳥來(lái)說(shuō),一定遇到過(guò)這樣的場(chǎng)景:

為了排查線上突發(fā)的問(wèn)題,非常希望能夠全面的看到請(qǐng)求在服務(wù)鏈路上的完整日志輸出;

But,在生產(chǎn)環(huán)境中,為了避免日志打印過(guò)量造成磁盤空間浪費(fèi),通常會(huì)將日志級(jí)別設(shè)定在INFO,并關(guān)閉一般情況用不到的日志輸出;

在不重啟服務(wù)的情況下,開啟本已經(jīng)關(guān)閉的業(yè)務(wù)日志輸出,能不能搞的定呢?答案是當(dāng)然沒問(wèn)題。

二 需求分析

熟悉logback的同學(xué)此時(shí)肯定已經(jīng)想到通過(guò)掃描監(jiān)聽logback.xml文件配置變化來(lái)實(shí)現(xiàn)日志級(jí)別的調(diào)整,像如下這種方式:

 
 
 

但通常情況下,你的業(yè)務(wù)服務(wù)是分布式部署的,后端節(jié)點(diǎn)有多臺(tái),如果一臺(tái)臺(tái)的去改,且不說(shuō)運(yùn)維大哥未必就會(huì)同意給你生產(chǎn)機(jī)器文件的修改權(quán)限,即使可以,這么做未免有些過(guò)于“老實(shí)”了;有沒有一種可以集中管理日志配置,修改文件后再逐個(gè)分發(fā)給各節(jié)點(diǎn)的解決方案呢?沿著這個(gè)思路,自然而然就會(huì)聯(lián)想到配置中心,這里,我主要介紹攜程開源的apollo,同類的配置中心產(chǎn)品還有百度Disconf、阿里ACM和Spring Cloud Config,感興趣的自行研究。

三 做實(shí)驗(yàn)

熟悉apollo文件管理的同學(xué)都知道,apollo通過(guò)推拉結(jié)合的方式將服務(wù)端存儲(chǔ)的應(yīng)用配置文件緩存到本地是以properties的格式存儲(chǔ)的,如下面所示:

demo+dev+logback.xml.properties

 
 
 
  1. content=\n\n\t\n\n\t\n\t\t\n\t\t\t%d{yyyy-MM-dd HH\:mm\:ss.SSS}|%X{requestId}|[%t] %-5level %logger{50} %line - %m%n\n\t\t\n\t\n\n\t\n\t\tlogs/brm.log\n\t\t\n\t\t\t%d{yyyy-MM-dd HH\:mm\:ss.SSS}|%X{requestId}|%X{requestSeq}|[%t] %-5level %logger{50} %line - %m%n\n\t\t\n\t\t\n\t\t\tlogs/brm-%d{yyyy-MM-dd-HH}-%i.log>\n\t\t\t<\!--單個(gè)文件切割閾值,超過(guò)生成新log文件-->\n\t\t\t200MB\n\t\t\t<\!--最大保留天數(shù)-->\n\t\t\t336\n\t\t\n\t\n\n    <\!--log4jdbc -->\n    \n    \n    \n    \n    \n    \n        \n\t\n\t\t\n\t\t\n\t\n

HH\:mm\:ss.SSS}|%X{requestId}|%X{requestSeq}|[%t] %-5level %logger{50} %line - %m%n \n\t\t \n\t\t \n\t\t\t logs/brm-%d{yyyy-MM-dd-HH}-%i.log >\n\t\t\t<\!--單個(gè)文件切割閾值,超過(guò)生成新log文件-->\n\t\t\t 200MB \n\t\t\t<\!--最大保留天數(shù)-->\n\t\t\t 336 \n\t\t \n\t \n\n <\!--log4jdbc -->\n \n \n \n \n \n \n \n\t \n\t\t \n\t\t \n\t \n

而我們通常在配置logback的時(shí)候使用的是xml文件;

因此,我們要想辦法讓logback能夠加載context的內(nèi)存值信息。

閱讀logback資料發(fā)現(xiàn),JoranConfigurator支持我們以自定義的方式配置logback,

而springboot是通過(guò)LoggingSystem來(lái)加載管理日志系統(tǒng)的;如果我能在springboot啟動(dòng)的時(shí)候指定我自定義的日志加載類,問(wèn)題便迎刃而解。

這里,我們?cè)趓esources目錄下新建META-INF文件夾,添加spring.factories,內(nèi)容如下:

 
 
 
  1. org.springframework.context.ApplicationContextInitializer = com.zhoupu.zplog.refresher.LoggerRefresher
  2. org.springframework.boot.env.EnvironmentPostProcessor = com.zhoupu.zplog.refresher.LoggerRefresher

這里我們定義一個(gè)LoggerRefresher,該類重寫loadDefaults和loadConfiguration方法,通過(guò)JoranConfigurator加載logback配置,并在configureByApollo中添加一個(gè)apollo事件監(jiān)聽器,當(dāng)發(fā)現(xiàn)logback.xml文件有變化時(shí),重新執(zhí)行configureByApollo方法刷新日志配置。

核心代碼部分如下:

 
 
 
  1. package com.zhoupu.zplog.refresher;
  2. import ch.qos.logback.classic.LoggerContext;
  3. import ch.qos.logback.classic.joran.JoranConfigurator;
  4. import ch.qos.logback.core.joran.spi.JoranException;
  5. import com.ctrip.framework.apollo.Config;
  6. import com.ctrip.framework.apollo.ConfigChangeListener;
  7. import com.ctrip.framework.apollo.ConfigService;
  8. import com.ctrip.framework.apollo.model.ConfigChangeEvent;
  9. import com.ctrip.framework.apollo.spring.config.PropertySourcesConstants;
  10. import org.slf4j.ILoggerFactory;
  11. import org.slf4j.Logger;
  12. import org.slf4j.LoggerFactory;
  13. import org.springframework.boot.SpringApplication;
  14. import org.springframework.boot.env.EnvironmentPostProcessor;
  15. import org.springframework.context.ApplicationContextInitializer;
  16. import org.springframework.context.ConfigurableApplicationContext;
  17. import org.springframework.core.Ordered;
  18. import org.springframework.core.env.ConfigurableEnvironment;
  19. import org.springframework.util.StringUtils;
  20. import javax.xml.parsers.DocumentBuilder;
  21. import javax.xml.parsers.DocumentBuilderFactory;
  22. import java.io.ByteArrayInputStream;
  23. import java.io.UnsupportedEncodingException;
  24. /**
  25.  *
  26.  * @author vigor
  27.  * @date 2019/6/14 上午11:27
  28.  */
  29. public class LoggerRefresher implements ApplicationContextInitializer, EnvironmentPostProcessor, Ordered {
  30.     private static final Logger log = LoggerFactory.getLogger(LoggerRefresher.class);
  31.     private boolean loadFlag = false;
  32.     @Override
  33.     public void initialize(ConfigurableApplicationContext context) {
  34.         ConfigurableEnvironment environment = context.getEnvironment();
  35.         load(environment);
  36.     }
  37.     @Override
  38.     public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
  39.         load(environment);
  40.     }
  41.     @Override
  42.     public int getOrder() {
  43.         return 1;
  44.     }
  45.     private void load(ConfigurableEnvironment environment) {
  46.         if (!loadFlag) {
  47.             environment.getPropertySources().forEach(ps -> {
  48.                 if (PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME.equals(ps.getName())) {
  49.                     configureByApollo();
  50.                     loadFlag = true;
  51.                 }
  52.             });
  53.         }
  54.     }
  55.     private void configureByApollo() {
  56.         Config config = ConfigService.getConfig("logback.xml");
  57.         String content = config.getProperty("content", "");
  58.         if (StringUtils.isEmpty(content) || !validateXML(content)) {
  59.             return;
  60.         }
  61.         config.addChangeListener(new ConfigChangeListener() {
  62.             @Override
  63.             public void onChange(ConfigChangeEvent changeEvent) {
  64.                 configureByApollo();
  65.             }
  66.             @Override
  67.             public boolean equals(Object obj) {
  68.                 if (this == obj) {
  69.                     return true;
  70.                 }
  71.                 if (this.getClass().equals(obj.getClass())) {
  72.                     return true;
  73.                 }
  74.                 return false;
  75.             }
  76.             @Override
  77.             public int hashCode() {
  78.                 return 1;
  79.             }
  80.         });
  81.         ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
  82.         LoggerContext loggerContext = (LoggerContext) loggerFactory;
  83.         loggerContext.reset();
  84.         JoranConfigurator configurator = new JoranConfigurator();
  85.         configurator.setContext(loggerContext);
  86.         try {
  87.             configurator.doConfigure(new ByteArrayInputStream(content.getBytes("utf-8")));
  88.             log.warn("*****************************logback configureByApollo success!********************************");
  89.         } catch (JoranException e) {
  90.             e.printStackTrace();
  91.         } catch (UnsupportedEncodingException e) {
  92.             e.printStackTrace();
  93.         }
  94.     }
  95.     private boolean validateXML(String xml){
  96.         boolean isValidated = true;
  97.         try {
  98.             DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
  99.             DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
  100.             builder.parse(new ByteArrayInputStream(xml.getBytes("utf-8")));
  101.         } catch (Exception e) {
  102.             log.error("apollo logback config error = {}", e);
  103.             isValidated = false;
  104.         }
  105.         return isValidated;
  106.     }
  107. }

至此已完成所有準(zhǔn)備工作,運(yùn)行demo程序,我的項(xiàng)目使用log4jdbc輸出sql,這里我通過(guò)修改apollo配置管理后臺(tái)jdbc日志配置,將sqltiming級(jí)別改為INFO:

 
 
 
  1.     
  2.     
  3.     
  4.     
  5.     
  6.     

發(fā)起一個(gè)后端請(qǐng)求,查看控制臺(tái)日志輸出,有了!

 
 
 
  1. 2019-11-08 10:11:27.794|1fe97e7dcfeb4fc2810d8a7a706fad2a||[http-nio-8062-exec-3] INFO  jdbc.sqltiming 357 - SELECT id, row_state, created_at, updated_at, created_by, updated_by, business_id, contact_name,
  2. role, mobile, contact_type FROM t_business_contact WHERE row_state = 0 AND business_id = 1000006

驚不驚喜_,意不意外!

四 總結(jié)

一個(gè)簡(jiǎn)單的日志配置熱更新嘗試,串聯(lián)起了logback的自定義配置加載原理,apollo的配置中心使用方法和事件監(jiān)聽機(jī)制,以及springboot日志管理和自動(dòng)裝配等知識(shí)點(diǎn),希望大家能從中有所收獲!

【本文是專欄機(jī)構(gòu)“舟譜數(shù)據(jù)”的原創(chuàng)文章,微信公眾號(hào)“舟譜數(shù)據(jù)( id: zhoupudata)”】


名稱欄目:日志配置熱更新技術(shù)實(shí)踐
當(dāng)前鏈接:http://m.5511xx.com/article/coehcjc.html