文档章节

zookeeper实现log4j日志级别动调

 白中墨
发布于 2017/06/02 16:51
字数 756
阅读 21
收藏 1
点赞 0
评论 0
  • 动态调整日志的目的和意义
  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提供的Java API操作ZooKeeper

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

ZeroOne01 ⋅ 04/26 ⋅ 0

Dubbo分布式框架:(二)Zookeeper实战

一.Zookeeper简介 讲到Dubbo不得不说它的核心组件Zookeeper,ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它...

HaleyLiu ⋅ 05/04 ⋅ 0

Zookeeper+Kafka集群搭建

Zookeeper集群搭建 Kafka集群是把状态保存在Zookeeper中的,首先要搭建Zookeeper集群。 1、软件环境 (3台服务器-我的测试) 192.168.30.204 server1 192.168.30.205 server2 192.168.30.206...

qianghong000 ⋅ 05/04 ⋅ 0

Apache HBase 2.0.0 发布,Hadoop 数据库

Apache HBase 2.0.0 发布了,HBase 2.0.0 是 HBase 的第二个主要版本。 此次更新信息如下: 一个新的区域分配管理器(“AMv2”), 用于配置读取和/或写入路径以运行堆外的装置,以及可选的内...

雨田桑 ⋅ 05/03 ⋅ 0

java 日志框架——log4j

Log4J是JAVA下的一款日志组件 下载: http://logging.apache.org/log4j/2.x/download.html 下面的示例我使用最新版本2.7无法正常运行,最新版本使用方法可能不同。本文示例使用log4j-1.2.15测...

xundh ⋅ 05/09 ⋅ 0

Java日志框架-logback的介绍及配置使用方法(纯Java工程)(转)

说明:内容估计有些旧,2011年的,但是大体意思应该没多大变化,最新的配置可以参考官方文档。 一、logback的介绍 Logback是由log4j创始人设计的又一个开源日志组件。logback当前分成三个模块...

easonjim ⋅ 2017/11/07 ⋅ 0

Log4j 2.0在开发中的高级使用详解

log4j与slf4j、logback比较 而log4j slf4j logback就是目前主流的日志框架。但后两者效率高是第一个。推荐使用:slf4j 或者 logback(spring-boot默认日志实现) log4j是apache实现的一个开源日...

spinachgit ⋅ 04/22 ⋅ 0

Java混乱的日志体系(logback)(转)

作为一名 Java 程序员,日常开发工作中肯定会接触日志系统,但是众多的框架,包括 Log4j、Log4j2、Logback、Slf4j、Apache Common logging 等等,引用的 maven 依赖众多,到底可以去掉哪些,...

easonjim ⋅ 2017/12/27 ⋅ 0

【干货】Apache Hadoop 2.8 完全分布式集群搭建超详细过程,实现NameNode HA、ResourceManager HA高可靠性...

最近在自己的笔记本电脑上搭建了Apache Hadoop分布式集群,采用了最新的稳定版本2.8,并配置了NameNode、ResourceManager的HA高可用,方便日常对Hadoop的研究与测试工作。详细的搭建过程如下...

implok ⋅ 04/13 ⋅ 0

spring boot保存|打印日志-logback的配置和使用

【转载】(https://www.cnblogs.com/winner-0715/p/6105519.html) 1.logback介绍 logback是由log4j创始人设计的又一个开源日志组件。logback当前分成三个模块:logback-core,logback-classic和...

qq_25652949 ⋅ 04/24 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

到底会改名吗?微软GVFS 改名之争

微软去年透露了 Git Virtual File System(GVFS)项目,GVFS 是 Git 版本控制系统的一个开源插件,允许 Git 处理 TB 规模的代码库,比如 270 GB 的 Windows 代码库。该项目公布之初就引发了争...

linux-tao ⋅ 33分钟前 ⋅ 0

笔试题之Java基础部分【简】【二】

1.静态变量和实例变量的区别 在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变...

anlve ⋅ 50分钟前 ⋅ 0

Lombok简单介绍及使用

官网 通过简单注解来精简代码达到消除冗长代码的目的 优点 提高编程效率 使代码更简洁 消除冗长代码 避免修改字段名字时忘记修改方法名 4.idea中安装lombnok pom.xml引入 <dependency> <grou...

to_ln ⋅ 今天 ⋅ 0

【转】JS浮点数运算Bug的解决办法

37.5*5.5=206.08 (JS算出来是这样的一个结果,我四舍五入取两位小数) 我先怀疑是四舍五入的问题,就直接用JS算了一个结果为:206.08499999999998 怎么会这样,两个只有一位小数的数字相乘,怎...

NickSoki ⋅ 今天 ⋅ 0

table eg

user_id user_name full_name 1 zhangsan 张三 2 lisi 李四 `` ™ [========] 2018-06-18 09:42:06 星期一½ gdsgagagagdsgasgagadsgdasgagsa...

qwfys ⋅ 今天 ⋅ 0

一个有趣的Java问题

先来看看源码: public class TestDemo { public static void main(String[] args) { Integer a = 10; Integer b = 20; swap(a, b); System.out......

linxyz ⋅ 今天 ⋅ 0

十五周二次课

十五周二次课 17.1mysql主从介绍 17.2准备工作 17.3配置主 17.4配置从 17.5测试主从同步 17.1mysql主从介绍 MySQL主从介绍 MySQL主从又叫做Replication、AB复制。简单讲就是A和B两台机器做主...

河图再现 ⋅ 今天 ⋅ 0

docker安装snmp rrdtool环境

以Ubuntu16:04作为基础版本 docker pull ubuntu:16.04 启动一个容器 docker run -d -i -t --name flow_mete ubuntu:16.04 bash 进入容器 docker exec -it flow_mete bash cd ~ 安装基本软件 ......

messud4312 ⋅ 今天 ⋅ 0

OSChina 周一乱弹 —— 快别开心了,你还没有女友呢。

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @莱布妮子 :分享吴彤的单曲《好春光》 《好春光》- 吴彤 手机党少年们想听歌,请使劲儿戳(这里) @clouddyy :小萝莉街上乱跑,误把我认错成...

小小编辑 ⋅ 今天 ⋅ 9

Java 开发者不容错过的 12 种高效工具

Java 开发者常常都会想办法如何更快地编写 Java 代码,让编程变得更加轻松。目前,市面上涌现出越来越多的高效编程工具。所以,以下总结了一系列工具列表,其中包含了大多数开发人员已经使用...

jason_kiss ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部