文档章节

zookeeper实现log4j日志级别动调

 白中墨
发布于 2017/06/02 16:51
字数 756
阅读 57
收藏 1
  • 动态调整日志的目的和意义
  1. 灵活方便,对于线上遇到疑难问题需要排查时,可以灵活的对某台服务的日志做升降级,不需要重新发布
  2. 集中管理,通过日志管理组件,实现所有服务的日志级别统一控制
  • 实现方案总结

系统分为三部分组成,逻辑图如下:

  1. 日志监听组件
    1.1    业务系统注册至zookeeper
        @PostConstruct
        public void initLoggerZookeeper() {
            try {
                loggerContext = (LoggerContext) LogManager.getContext(false);
                tempZkPath = zkPath + getHostIp();
                initConnection();
                createNodeAddWatch();
               
            } catch (Exception e) {
                logger.error("init logger error: {}", e);
            }
      
        }
        @PreDestroy
        public void destroyZookeeperConn() {
            CloseableUtils.closeQuietly(node);
            CloseableUtils.closeQuietly(client);
        }
    
        /**
         * 
            * @MethodName: initLoggerConfig
            * @Description: 
            * @param 初始化zk连接
            * @return void
            * @throws
         */
        private void initConnection() {
            client = CuratorFrameworkFactory.newClient(zkConnectString, sessionTimeoutMs, connectionTimeoutMs,
                    new ExponentialBackoffRetry(1000, 3));
            client.getConnectionStateListenable().addListener(getConnectionStateListener());
            client.start();
            try {
                countDownLatch.await(3, TimeUnit.SECONDS);//不能因为zk注册影响核心业务,最长等待3秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 
            * @MethodName: getConnectionStateListener
            * @Description: 产生zookeeper的连接状态监听
            * @param @return
            * @return ConnectionStateListener
            * @throws
         */
        private ConnectionStateListener getConnectionStateListener() {
            ConnectionStateListener connListenner = new ConnectionStateListener() {
                @Override
                public void stateChanged(CuratorFramework client, ConnectionState newState) {
                    if (newState == ConnectionState.CONNECTED) {
                        countDownLatch.countDown();
                    }else if (newState == ConnectionState.LOST) {
                        CloseableUtils.closeQuietly(client);
                        countDownLatch = new CountDownLatch(1);
                        initLoggerZookeeper();
                    }else if(newState == ConnectionState.RECONNECTED) {
                        CloseableUtils.closeQuietly(client);
                        countDownLatch = new CountDownLatch(1);
                        initLoggerZookeeper();             
                    }
                }
            };
            return connListenner;
        }

    1.2    增加节点监听
        /**
         * 
            * @MethodName: createNodeAddWatch
            * @Description: 创建临时节点,增加节点监听
            * @param @throws Exception
            * @return void
            * @throws
         */
        private void createNodeAddWatch() throws Exception {
            Map<String, LoggerConfig> loggerMap = loggerContext.getConfiguration().getLoggers();
            LoggerConfig config = loggerMap.get("");
            String defaultLevel = "init";
            if(config != null) {
                Level level  = config.getLevel();
                defaultLevel = level.name();
            }
            node = new PersistentEphemeralNode(client, Mode.EPHEMERAL,
                    tempZkPath, defaultLevel.getBytes());
            node.start();
            node.waitForInitialCreate(2, TimeUnit.SECONDS);
            addWatcherForNode();
        }
        /**
         * 
            * @MethodName: addWatcherForNode
            * @Description: 增加watcher
            * @param @throws Exception
            * @return void
            * @throws
         */
        private void addWatcherForNode() throws Exception{
            client.getData().usingWatcher(getNodeWatcher()).inBackground().forPath(node.getActualPath());
        }
        /**
         * 
            * @MethodName: getNodeWatcher
            * @Description: 返回节点的监听器,监听数据变化
            * @param @param node
            * @param @return
            * @return Watcher
            * @throws
         */
        private Watcher getNodeWatcher() {
            Watcher watcher = new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    if(event.getType() == EventType.NodeDataChanged) {
                        updateLogLevel();
                        try {
                            addWatcherForNode();
                        } catch (Exception e) {
                            logger.error("add watcher error: {}", e);
                        }
                    }
                }
            };
            return watcher;
        }

    1.3    根据节点内容变化,更新loggerContext
        /**
         * 
            * @MethodName: updateLogLevel
            * @Description: 更新日志等级
            * @param 
            * @return void
            * @throws
         */
        private void updateLogLevel() {
            String newLevel = null;
            try {
                newLevel = new String(client.getData().forPath(tempZkPath), "utf-8");
                logger.info("newLevel: {}", newLevel);
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("nodeWatcher: ", e);
            }
            Map<String, LoggerConfig> loggerMap = loggerContext.getConfiguration().getLoggers();
            for(String loggerName : loggerMap.keySet() ) {
                LoggerConfig loggerConfig = loggerMap.get(loggerName);
                loggerConfig.setLevel(getMatchLevel(newLevel));
            }
            loggerContext.updateLoggers();
        }
        /**
         * 
            * @MethodName: getMatchLevel
            * @Description: 根据日志字符串获取Level,如果字符串匹配不到,则返回默认info等级
            * @param @param logLevel
            * @param @return
            * @return Level
            * @throws
         */
        private Level getMatchLevel(String logLevel) {
            Level matchLevel = Level.toLevel(logLevel, Level.INFO);
            return matchLevel;
        }
        /**
         * 
            * @MethodName: getHostIp
            * @Description: 获取服务的IP
            * @param @return
            * @param @throws Exception
            * @return String
            * @throws
         */
        private String getHostIp() throws Exception {
            InetAddress inetAddress = InetAddress.getLocalHost();
            return inetAddress.getHostAddress();
        }

     

  2. 日志管理平台
    核心代码如下:
      /**
         * 获取所有的日志服务列表
         */
        @Override
        public List<LogInfo> getLogList(String parentPath) {
            List<LogInfo> logInfoList = new ArrayList<>();
            try {
                List<String> machineList = client.getChildren().forPath(parentPath);
                for(String machine : machineList) {
                    logger.info(parentPath + "/" + machine);
                    String logLevel = new String(client.getData().forPath(parentPath + "/" + machine), "utf-8");
                    logger.info(logLevel);
                    LogInfo logInfo = new LogInfo();
                    logInfo.setIpAddress(machine);
                    logInfo.setLogLevel(logLevel);
                    logInfoList.add(logInfo);
                }
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("getLogList error", e);
            }
            return logInfoList;
        }
        @PostConstruct
        public void initZKclient() {
            client = CuratorFrameworkFactory.newClient(zkConnectString, sessionTimeoutMs, connectionTimeoutMs,
                    new ExponentialBackoffRetry(1000, 3));
            client.start();
        }
        @PreDestroy
        public void destroyZookeeperConn() {
            CloseableUtils.closeQuietly(client);
        }
        
            /*
            * 
            * 
            * @param zkPath
            * @param level
            * @see com.xiaojukeji.ad.admin.service.interfaces.LogMachineService#updateLogLevel(java.lang.String, java.lang.String)
            */
        /**
         * 更新日志    
         */
        @Override
        public void updateLogLevel(String zkPath, String level, String hostName) {
            // TODO Auto-generated method stub
            try {
                System.out.println(zkPath + "/" + hostName);
                client.setData().forPath(zkPath + "/" + hostName, level.getBytes("utf-8"));
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        }

     

  3. zookeeper服务
    大名鼎鼎的分布式服务组件,这里就不做介绍了

 

© 著作权归作者所有

共有 人打赏支持
粉丝 0
博文 13
码字总数 18422
作品 0
昌平
Zookeeper集群部署和使用

Zookeeper 由 Apache Hadoop 的 Zookeeper 子项目发展而来,Google Chubby的一个开源实现。它是一个分布式应用程序协调服务,提供的功能包括:配置管理,名字服务,提供分布式同步、队列管理...

justin_peng
06/21
0
0
MetaQ Log4j及服务器配置管理

一、使用Log4j扩展发送消息 Metaq还支持log4j发送消息,通过log4j写入的任何日志信息都将以消息的方式发送到Metaq的Broker服务器,只要通过简单的配置就可以。 如果要用到log4j扩展,你需要使...

一枚Sir
2015/11/03
0
0
kafka Failed to send messages after 3 tries.

我在网上搜了很多资料 说是zookeeper的问题,修改更改server.properties下的host.name,zookeeper.connect的localhost 为ip地址 怎么也不管用 后来就单独建了一个项目,发现没有问题。结论是j...

internetafei
2015/04/10
0
2
Dubbo详解+SpringBoot配置Dubbo 

Dubbo详解+SpringBoot配置Dubbo SpringBoot配置Dubbo 环境:spring-boot 2.0.1 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId......

DemonsI
09/06
0
0
使用ZooKeeper提供的Java API操作ZooKeeper

建立客户端与zk服务端的连接 我们先来创建一个普通的maven工程,然后在pom.xml文件中配置zookeeper依赖: 在resources目录下创建一个zk-connect.properties属性配置文件,我们在该文件中填写...

ZeroOne01
04/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

shell特殊符号、cut、sort、uniq、wc、tee、tr、split命令

10月15日任务 8.10 shell特殊符号cut命令 8.11 sort_wc_uniq命令 8.12 tee_tr_split命令 8.13 shell特殊符号下 cut 命令 cut作用:截取字符串 用法如下:cat /etc/passwd |head -2 |cut -d ...

hhpuppy
16分钟前
0
0
Springboot实现filter拦截token验证和跨域

背景 web验证授权合法的一般分为下面几种 1使用session作为验证合法用户访问的验证方式 使用自己实现的token 使用OCA标准 在使用API接口授权验证时,token是自定义的方式实现起来不需要引入其...

funnymin
51分钟前
1
0
linux使用ntfs-3g操作ntfs格式硬盘

Linux内核目前只支持对微软NTFS文件系统的读取。 NTFS-3G 是微软 NTFS 文件系统的一个开源实现,同时支持读和写。NTFS-3G 开发者使用 FUSE 文件系统来辅助开发,同时对可移植性有益。 安装 ...

linuxprobe16
今天
1
0
kubeadm部署kubernetes集群

一、环境要求 这里使用RHEL7.5 master、etcd:192.168.10.101,主机名:master node1:192.168.10.103,主机名:node1 node2:192.168.10.104,主机名:node2 所有机子能基于主机名通信,编辑...

人在艹木中
今天
13
0
Shell特殊符号总结以及cut,sort,wc,uniq,tee,tr,split命令

特殊符号总结一 * 任意个任意字符 ? 任意一个字符 # 注释字符 \ 脱义字符 | 管道符 # #号后的备注被忽略[root@centos01 ~]# ls a.txt # 备注 a.txt[root@centos01 ~]# a=1[root@centos01...

野雪球
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部