方法層級的java日誌輸出控制(二)叢集

來源:互聯網
上載者:User

標籤:

在方法層級的java日誌輸出控制(一)這篇文章中主要討論了通過properties設定檔以及AOP技術批量控制方法層級的日誌輸出。

用properties設定檔的好處是不用更改程式即可控制日誌的輸出,然而大型的應用通常是分布式的,會有很多的伺服器,需要更改全部伺服器上的設定檔,然後再重啟應用。這將會是一件非常麻煩的事情。事實上在大型叢集應用中有更好的方法實現他。zookeeper的特性決定著它有一個應用情境就是叢集配置中心。本文不介紹zookeeper原理以及搭建,將直接使用zookeeper實現即時更改配置。本文表面上是做方法層級的日誌輸出控制在叢集中的實現,但實際上完全是一個zookeeper叢集配置中心的簡單實現。

先看ZkHelper工具類:

package com.lf.testLog4j.Util;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.concurrent.CountDownLatch;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.apache.zookeeper.*;import org.apache.zookeeper.data.Stat;/** * Created by lufei3 on 2015/7/29. */public class ZkHelper {    private static final Logger logger = LogManager.getLogger(ZkHelper.class);    Stat stat = null;    private static ZooKeeper zk;    static private ZkHelper instance;    //本機搭建的zk偽叢集    public static String hostports = "127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183";    //存放所有的log方法配置索引值對,系統系統時會首先從zk上拿到所有的節點資料放在map裡,只有當節點發生改變的時候    // 才會更新map,這樣避免每取一個節點就去zk裡面讀資料,從而節省了io時間。    public static Map<String, String> nodeList;    //等待zk串連的方法,若沒有串連時會報錯    public static void waitUntilConnected(ZooKeeper zooKeeper, CountDownLatch connectedLatch) {        if (ZooKeeper.States.CONNECTING == zooKeeper.getState()) {            try {                connectedLatch.await();            } catch (InterruptedException e) {                throw new IllegalStateException(e);            }        }    }    //watcher類,該watcher可以watch到zk串連以及每個節點的變化    static class ConnectedWatcher implements Watcher {        private CountDownLatch connectedLatch;        ConnectedWatcher(CountDownLatch connectedLatch) {            this.connectedLatch = connectedLatch;        }        @Override        public void process(WatchedEvent event) {            if (event.getState() == Event.KeeperState.SyncConnected) {                connectedLatch.countDown();            }            logger.info("process : " + event.getType() + " " + event.getPath());            //當節點發生變化時更新map            nodeListMapRefresh(String.valueOf(event.getType()), event.getPath());        }    }    public static void nodeListMapRefresh(String eventType, String path) {        if (eventType.equals("NodeDeleted")) {            nodeList.remove(path.substring(path.lastIndexOf("/") + 1));        } else if (eventType.equals("NodeCreated") || eventType.equals("NodeDataChanged")) {            nodeList.put(path.substring(path.lastIndexOf("/") + 1), getNode(path));        }    }    //單例    public static ZkHelper Instance() {        if (instance == null) {            instance = new ZkHelper(hostports, 1000);        }        return instance;    }    //初始化串連並裝載節點列表    public boolean Init(String hostports, int times) {        try {            CountDownLatch connectedLatch = new CountDownLatch(1);            Watcher watcher = new ConnectedWatcher(connectedLatch);            zk = new ZooKeeper(hostports, times, watcher);            waitUntilConnected(zk, connectedLatch);            nodeList = getNodeList("/root/log");        } catch (Exception e) {            System.out.println(e);            return false;        }        return true;    }    //構造方法,構造時完成初始化    ZkHelper(String hostports, int times) {        Init(hostports, times);    }    //擷取節點資訊    public static String getNode(String keys) {        String re = "";        String ppath = keys;        Stat stat = new Stat();        try {            byte[] b = zk.getData(ppath, false, stat);    //擷取節點的資訊及儲存的資料            re = new String(b);        } catch (Exception e) {            System.out.println(e);        }        return re;    }    //建立節點或更新節點資料    public void create(String key, String value) {        try {            stat = null;            stat = zk.exists("/root", false);            if (stat == null) {                zk.create("/root", "rootData".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);            }            stat = null;            stat = zk.exists("/root/log", false);            if (stat == null) {                zk.create("/root/log", "logData".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);            }            stat = null;            stat = zk.exists("/root/log/" + key, true);            if (stat == null) {                zk.create("/root/log/" + key, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);            } else {                zk.setData("/root/log/" + key, value.getBytes(), -1);            }        } catch (KeeperException e) {            e.printStackTrace();        } catch (InterruptedException e) {            e.printStackTrace();        }    }    //刪除節點    public void delete(String key) {        stat = null;        try {            stat = zk.exists("/root/log/" + key, true);            if (stat != null) {                zk.delete("/root/log/" + key, -1);            }        } catch (InterruptedException e) {            e.printStackTrace();        } catch (KeeperException e) {            e.printStackTrace();        }    }    //擷取節點列表    public Map getNodeList(String path) {        Map<String, String> map = new HashMap<String, String>();        List<String> nodeList = null;        try {            nodeList = zk.getChildren(path, true);            for (String s : nodeList) {                byte[] bytes = zk.getData(path + "/" + s, true, null);                map.put(s, new String(bytes));            }        } catch (KeeperException e) {            e.printStackTrace();        } catch (InterruptedException e) {            e.printStackTrace();        }        return map;    }}

  

LogConfig類:

package com.lf.zookeeperConfigCenter;import com.lf.testLog4j.Util.ZkHelper;public class LogConfig {public static void main(String args[]) {ZkHelper conf = ZkHelper.Instance();// conf.delete("TestLogAOP.test2");// conf.delete("TestLogAOP.test");conf.create("TestLogAOP.test2", "{\"level\":\"TRACE\",\"on\":1}");String str = conf.getNode("/root/log/TestLogAOP.test2");conf.create("TestLogAOP.test", "{\"level\":\"TRACE\",\"on\":0}");}}

  

  這個類主要完成了zk的節點建立兩個節點的路徑和值分別為

/root/log/TestLogAOP.test,{"level":"TRACE","on":0}

/root/log/TestLogAOP.test2,{"level":"TRACE","on":1}與上篇的properties檔案配置一致。完善的配置中心應當有一個圖形介面。

LogActiveZK類:

package com.lf.testLog4j.aop;import com.google.gson.Gson;import com.lf.testLog4j.Util.ZkHelper;import com.lf.testLog4j.common.CommonLogUtil;import com.lf.testLog4j.domain.ConfigLog;import org.apache.commons.lang.StringUtils;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.aspectj.lang.JoinPoint;import java.util.Map;/** * Created by lufei3 on 2015/7/29. */public class LogActiveZK {    private static final Logger logger = LogManager.getLogger(LogActive.class);    public void before(JoinPoint jp){        ZkHelper zkHelper = ZkHelper.Instance();        Map map = zkHelper.nodeList;        Gson gson = new Gson();        ConfigLog configLog = null;        String cName = jp.getThis().toString();        Object[] args = jp.getArgs();  //獲得參數列表        String className = cName.substring(cName.lastIndexOf(".")+1,cName.lastIndexOf("@"));        String methodName = jp.getSignature().getName();   //獲得方法名        String key = className + "." + methodName;        String configValue = (String) map.get(key);        try {            configLog = gson.fromJson(configValue,ConfigLog.class);        } catch (Exception e) {            logger.error("Gson Format Exception!! logLevel:{}",configValue);            e.printStackTrace();            return;        }        if(configLog == null) {            return;        }        String logLevel = configLog.getLevel();        int offset = configLog.getOn();        if(StringUtils.isBlank(logLevel)){            logger.warn("method:{} log not config", key);            return;        }        if(CommonLogUtil.isInfoEnable(logLevel, offset)) {            logger.info("====Method:{};", key);            if(args.length <=0){                logger.info("===={}方法沒有參數", methodName);            } else{                for(int i=0; i<args.length; i++){                    logger.info("====參數 {}:{} ", (i + 1), args[i]);                }            }        }    }    public void after(){        logger.info("調用完畢!!");    }}

  Spring配置:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"       default-autowire="byName">    <bean id="LogActiveZK" class="com.lf.testLog4j.aop.LogActiveZK"></bean> <!--將日誌類注入到bean中。-->    <bean id="testLogAOP" class="com.lf.testLog4j.service.TestLogAOP"></bean>    <aop:aspectj-autoproxy proxy-target-class="true"/>    <aop:config>        <!--攔截service層的所有方法-->        <aop:pointcut id="service" expression="execution(* com.lf.testLog4j.service.*.*(..))"/>        <aop:aspect id="log" ref="LogActiveZK">            <aop:before pointcut-ref="service" method="before"/>            <aop:after pointcut-ref="service" method="after"/>        </aop:aspect>    </aop:config></beans>

  TestLogAOP類:

package com.lf.testLog4j.service;import org.springframework.stereotype.Component;/** * Created by lufei3 on 2015/7/14. */@Componentpublic class TestLogAOP {    public void test(){        System.out.println("測試類別的test方法被調用");    }    public void test2() {        System.out.println("測試2的方法被調用!");    }}

  測試:

package com.lf.testLog4j;import com.lf.testLog4j.service.TestLogAOP;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * Created by lufei3 on 2015/7/14. */public class LogAOPMain {    public static void main(String... args) {        ApplicationContext act = new ClassPathXmlApplicationContext("spring/spring-config.xml");        TestLogAOP testLogAOP = (TestLogAOP) act.getBean("testLogAOP");        testLogAOP.test();        testLogAOP.test2();    }}

結果: 

 

可見成功用zk作為log配置中心並通過Spring AOP攔截了方法層級的log輸出。

方法層級的java日誌輸出控制(二)叢集

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.