1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.zookeeper.server.embedded; 19 20 import java.lang.management.ManagementFactory; 21 import java.lang.reflect.UndeclaredThrowableException; 22 import java.util.ArrayList; 23 import java.util.Arrays; 24 import java.util.Collections; 25 import java.util.List; 26 import java.util.Set; 27 import javax.management.InstanceNotFoundException; 28 import javax.management.MBeanServer; 29 import javax.management.MBeanServerInvocationHandler; 30 import javax.management.ObjectInstance; 31 import javax.management.ObjectName; 32 import org.apache.zookeeper.common.StringUtils; 33 import org.apache.zookeeper.server.ConnectionMXBean; 34 import org.apache.zookeeper.server.ZooKeeperServerBean; 35 import org.apache.zookeeper.server.quorum.LocalPeerMXBean; 36 import org.apache.zookeeper.server.quorum.QuorumBean; 37 import org.apache.zookeeper.server.quorum.QuorumMXBean; 38 import org.apache.zookeeper.server.quorum.RemotePeerMXBean; 39 40 public final class ZookeeperServeInfo { 41 42 private static final MBeanServer localServer = ManagementFactory.getPlatformMBeanServer(); 43 ZookeeperServeInfo()44 private ZookeeperServeInfo() { 45 } 46 47 public static class PeerInfo { 48 49 private final String name; 50 private final String quorumAddress; 51 private final String state; 52 private final boolean leader; 53 PeerInfo(String name, String quorumAddress, String state, boolean leader)54 public PeerInfo(String name, String quorumAddress, String state, boolean leader) { 55 this.name = name; 56 this.quorumAddress = quorumAddress; 57 this.state = state; 58 this.leader = leader; 59 } 60 getName()61 public String getName() { 62 return name; 63 } 64 getQuorumAddress()65 public String getQuorumAddress() { 66 return quorumAddress; 67 } 68 getState()69 public String getState() { 70 return state; 71 } 72 isLeader()73 public boolean isLeader() { 74 return leader; 75 } 76 77 @Override toString()78 public String toString() { 79 return "PeerInfo{" + "name=" + name + ", leader=" + leader + ", quorumAddress=" + quorumAddress 80 + ", state=" + state + '}'; 81 } 82 } 83 84 public static class ConnectionInfo { 85 86 private final String sourceip; 87 private final String sessionid; 88 private final String lastoperation; 89 private final String lastResponseTime; 90 private final String avgLatency; 91 private final String lastLatency; 92 private final String nodes; 93 ConnectionInfo(String sourceip, String sessionid, String lastoperation, String lastResponseTime, String avgLatency, String lastLatency, String nodes)94 public ConnectionInfo(String sourceip, String sessionid, String lastoperation, String lastResponseTime, 95 String avgLatency, String lastLatency, String nodes) { 96 this.sourceip = sourceip; 97 this.sessionid = sessionid; 98 this.lastoperation = lastoperation; 99 this.lastResponseTime = lastResponseTime; 100 this.avgLatency = avgLatency; 101 this.lastLatency = lastLatency; 102 this.nodes = nodes; 103 } 104 getLastLatency()105 public String getLastLatency() { 106 return lastLatency; 107 } 108 getSourceip()109 public String getSourceip() { 110 return sourceip; 111 } 112 getSessionid()113 public String getSessionid() { 114 return sessionid; 115 } 116 getLastoperation()117 public String getLastoperation() { 118 return lastoperation; 119 } 120 getLastResponseTime()121 public String getLastResponseTime() { 122 return lastResponseTime; 123 } 124 getAvgLatency()125 public String getAvgLatency() { 126 return avgLatency; 127 } 128 getNodes()129 public String getNodes() { 130 return nodes; 131 } 132 133 @Override toString()134 public String toString() { 135 return "ConnectionInfo{" + "sourceip=" + sourceip + ", sessionid=" + sessionid + ", lastoperation=" 136 + lastoperation + ", lastResponseTime=" + lastResponseTime + ", avgLatency=" + avgLatency 137 + ", nodes=" + nodes + '}'; 138 } 139 } 140 141 public static class ServerInfo { 142 143 private final List<ConnectionInfo> connections = new ArrayList<>(); 144 private boolean leader; 145 private boolean standaloneMode; 146 public List<PeerInfo> peers = new ArrayList<>(); 147 isStandaloneMode()148 public boolean isStandaloneMode() { 149 return standaloneMode; 150 } 151 getConnections()152 public List<ConnectionInfo> getConnections() { 153 return connections; 154 } 155 isLeader()156 public boolean isLeader() { 157 return leader; 158 } 159 getPeers()160 public List<PeerInfo> getPeers() { 161 return Collections.unmodifiableList(peers); 162 } 163 addPeer(PeerInfo peer)164 public void addPeer(PeerInfo peer) { 165 peers.add(peer); 166 } 167 168 @Override toString()169 public String toString() { 170 return "ServerInfo{" + "connections=" + connections + ", leader=" + leader + ", standaloneMode=" 171 + standaloneMode + ", peers=" + peers + '}'; 172 } 173 174 } 175 getStatus()176 public static ServerInfo getStatus() throws Exception { 177 return getStatus("*"); 178 } 179 getStatus(String beanName)180 public static ServerInfo getStatus(String beanName) throws Exception { 181 182 ServerInfo info = new ServerInfo(); 183 boolean standalonemode = false; 184 // org.apache.ZooKeeperService:name0=ReplicatedServer_id1,name1=replica.1,name2=Follower,name3=Connections, 185 // name4=10.168.10.119,name5=0x13e83353764005a 186 // org.apache.ZooKeeperService:name0=ReplicatedServer_id2,name1=replica.2,name2=Leader 187 if (StringUtils.isBlank(beanName)) { 188 beanName = "*"; 189 } 190 ObjectName objectName = new ObjectName("org.apache.ZooKeeperService:name0=" + beanName); 191 Set<ObjectInstance> first_level_beans = localServer.queryMBeans(objectName, null); 192 if (first_level_beans.isEmpty()) { 193 throw new IllegalStateException("No ZooKeeper server found in this JVM with name " + objectName); 194 } 195 String myName = ""; 196 for (ObjectInstance o : first_level_beans) { 197 if (o.getClassName().equalsIgnoreCase(ZooKeeperServerBean.class.getName())) { 198 standalonemode = true; 199 info.leader = true; 200 info.addPeer(new PeerInfo("local", "local", "STANDALONE", true)); 201 } else if (o.getClassName().equalsIgnoreCase(QuorumBean.class.getName())) { 202 standalonemode = false; 203 try { 204 QuorumMXBean quorum = MBeanServerInvocationHandler.newProxyInstance(localServer, o.getObjectName(), 205 QuorumMXBean.class, false); 206 myName = quorum.getName(); 207 } catch (UndeclaredThrowableException err) { 208 if (err.getCause() instanceof javax.management.InstanceNotFoundException) { 209 // maybe server not yet started or already stopped ? 210 } else { 211 throw err; 212 } 213 } 214 } 215 } 216 info.standaloneMode = standalonemode; 217 if (standalonemode) { 218 Set<ObjectInstance> connectionsbeans = localServer.queryMBeans(new ObjectName( 219 "org.apache.ZooKeeperService:name0=*,name1=Connections,name2=*,name3=*"), null); 220 for (ObjectInstance conbean : connectionsbeans) { 221 ConnectionMXBean cc = MBeanServerInvocationHandler. 222 newProxyInstance(localServer, conbean.getObjectName(), ConnectionMXBean.class, false); 223 try { 224 String nodes = ""; 225 if (cc.getEphemeralNodes() != null) { 226 nodes = Arrays.asList(cc.getEphemeralNodes()) + ""; 227 } 228 info.connections.add(new ConnectionInfo(cc.getSourceIP(), cc.getSessionId(), cc.getLastOperation(), 229 cc.getLastResponseTime(), cc.getAvgLatency() + "", cc.getLastLatency() + "", nodes)); 230 } catch (Exception ex) { 231 if (ex instanceof InstanceNotFoundException && ex.getCause() instanceof InstanceNotFoundException) { 232 // SKIP 233 } else { 234 throw ex; 235 } 236 } 237 } 238 } else { 239 if (myName.isEmpty()) { 240 throw new IllegalStateException( 241 "Cannot find local JMX name for current node, in quorum mode, scanned " + first_level_beans); 242 } 243 boolean leader = false; 244 Set<ObjectInstance> replicas = localServer.queryMBeans(new ObjectName( 245 "org.apache.ZooKeeperService:name0=" + myName + ",name1=*"), null); 246 for (ObjectInstance o : replicas) { 247 if (o.getClassName().toLowerCase().contains("local")) { 248 LocalPeerMXBean local = MBeanServerInvocationHandler. 249 newProxyInstance(localServer, o.getObjectName(), LocalPeerMXBean.class, false); 250 info.addPeer(new PeerInfo(local.getName(), local.getQuorumAddress(), local.getState() + "", 251 local.isLeader())); 252 253 ObjectName asfollowername = new ObjectName(o.getObjectName() + ",name2=Follower"); 254 ObjectName asleadername = new ObjectName(o.getObjectName() + ",name2=Leader"); 255 boolean isleader = localServer.isRegistered(asleadername); 256 Set<ObjectInstance> connectionsbeans = null; 257 if (isleader) { 258 leader = true; 259 ObjectName asleaderconnections = new ObjectName( 260 asleadername + ",name3=Connections,name4=*,name5=*"); 261 connectionsbeans = localServer.queryMBeans(asleaderconnections, null); 262 } else { 263 leader = false; 264 ObjectName asfollowernameconnections = new ObjectName( 265 asfollowername + ",name3=Connections,name4=*,name5=*"); 266 connectionsbeans = localServer.queryMBeans(asfollowernameconnections, null); 267 } 268 269 for (ObjectInstance conbean : connectionsbeans) { 270 ConnectionMXBean cc = MBeanServerInvocationHandler.newProxyInstance(localServer, 271 conbean.getObjectName(), ConnectionMXBean.class, false); 272 try { 273 String nodes = ""; 274 if (cc.getEphemeralNodes() != null) { 275 nodes = Arrays.asList(cc.getEphemeralNodes()) + ""; 276 } 277 info.connections.add(new ConnectionInfo(cc.getSourceIP(), cc.getSessionId(), cc. 278 getLastOperation(), cc.getLastResponseTime(), cc.getAvgLatency() + "", cc. 279 getLastLatency() + "", nodes)); 280 } catch (Exception ex) { 281 if (ex instanceof InstanceNotFoundException && ex.getCause() instanceof InstanceNotFoundException) { 282 // SKIP 283 } else { 284 throw ex; 285 } 286 } 287 } 288 } else { 289 RemotePeerMXBean remote = MBeanServerInvocationHandler.newProxyInstance(localServer, o. 290 getObjectName(), RemotePeerMXBean.class, false); 291 info.addPeer(new PeerInfo(remote.getName(), remote.getQuorumAddress(), 292 "REMOTE", remote.isLeader())); 293 } 294 295 } 296 info.leader = leader; 297 } 298 return info; 299 } 300 } 301