| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| package org.apache.qpid.server.model; |
| |
| import java.lang.management.GarbageCollectorMXBean; |
| import java.lang.management.ManagementFactory; |
| import java.lang.management.MemoryPoolMXBean; |
| import java.lang.management.PlatformManagedObject; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import org.apache.qpid.server.configuration.IllegalConfigurationException; |
| import org.apache.qpid.server.logging.messages.BrokerMessages; |
| import org.apache.qpid.server.plugin.ConfiguredObjectAttributeInjector; |
| import org.apache.qpid.server.plugin.PluggableService; |
| import org.apache.qpid.server.util.ParameterizedTypes; |
| |
| @PluggableService |
| public class BrokerAttributeInjector implements ConfiguredObjectAttributeInjector |
| { |
| private static final Logger LOGGER = LoggerFactory.getLogger(BrokerAttributeInjector.class); |
| |
| private final InjectedAttributeOrStatistic.TypeValidator _typeValidator = |
| new InjectedAttributeOrStatistic.TypeValidator() |
| { |
| @Override |
| public boolean appliesToType(final Class<? extends ConfiguredObject<?>> type) |
| { |
| return Broker.class.isAssignableFrom(type); |
| } |
| }; |
| |
| private final Class<?> _hotSpotDiagnosticMXBeanClass; |
| private final PlatformManagedObject _hotSpotDiagnosticMXBean; |
| |
| public BrokerAttributeInjector() |
| { |
| Class<?> hotSpotDiagnosticMXBeanClass = null; |
| PlatformManagedObject hotSpotDiagnosticMXBean = null; |
| try |
| { |
| ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); |
| hotSpotDiagnosticMXBeanClass = |
| Class.forName("com.sun.management.HotSpotDiagnosticMXBean", true, systemClassLoader); |
| hotSpotDiagnosticMXBean = |
| ManagementFactory.getPlatformMXBean((Class<? extends PlatformManagedObject>) hotSpotDiagnosticMXBeanClass); |
| |
| } |
| catch (ClassNotFoundException e) |
| { |
| LOGGER.debug("Cannot find com.sun.management.HotSpotDiagnosticMXBean MXBean: " + e); |
| } |
| |
| _hotSpotDiagnosticMXBeanClass = hotSpotDiagnosticMXBeanClass; |
| _hotSpotDiagnosticMXBean = hotSpotDiagnosticMXBean; |
| } |
| |
| @Override |
| public Collection<ConfiguredObjectInjectedAttribute<?, ?>> getInjectedAttributes() |
| { |
| List<ConfiguredObjectInjectedAttribute<?, ?>> attributes = new ArrayList<>(); |
| List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans(); |
| for (MemoryPoolMXBean memoryPoolMXBean : memoryPoolMXBeans) |
| { |
| |
| String poolName = memoryPoolMXBean.getName().replace(" ", ""); |
| String attributeName = "jvmMemoryMaximum" + poolName; |
| try |
| { |
| Method getMemoryPoolMaximum = BrokerAttributeInjector.class.getDeclaredMethod("getMemoryPoolMaximum", |
| Broker.class, |
| MemoryPoolMXBean.class); |
| |
| final ConfiguredObjectInjectedAttribute<?, ?> injectedStatistic = |
| new ConfiguredDerivedInjectedAttribute<>(attributeName, |
| getMemoryPoolMaximum, |
| new Object[]{memoryPoolMXBean}, |
| false, |
| false, |
| "", |
| false, |
| "", |
| "Maximum size of memory pool " + memoryPoolMXBean.getName(), |
| _typeValidator); |
| attributes.add(injectedStatistic); |
| } |
| catch (NoSuchMethodException e) |
| { |
| LOGGER.warn("Failed to inject attribute '{}'", attributeName, e); |
| } |
| } |
| return attributes; |
| } |
| |
| @Override |
| public Collection<ConfiguredObjectInjectedStatistic<?, ?>> getInjectedStatistics() |
| { |
| List<ConfiguredObjectInjectedStatistic<?, ?>> statistics = new ArrayList<>(); |
| List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans(); |
| for (MemoryPoolMXBean memoryPoolMXBean : memoryPoolMXBeans) |
| { |
| String poolName = memoryPoolMXBean.getName().replace(" ", ""); |
| String statisticName = "jvmMemoryUsed" + poolName; |
| try |
| { |
| Method getMemoryPoolUsed = BrokerAttributeInjector.class.getDeclaredMethod("getMemoryPoolUsed", |
| Broker.class, |
| MemoryPoolMXBean.class); |
| |
| final ConfiguredObjectInjectedStatistic<?, ?> injectedStatistic = |
| new ConfiguredObjectInjectedStatistic<>(statisticName, |
| getMemoryPoolUsed, |
| new Object[]{memoryPoolMXBean}, |
| "Usage of memory in pool " + memoryPoolMXBean.getName(), |
| _typeValidator, |
| StatisticUnit.BYTES, |
| StatisticType.POINT_IN_TIME, |
| memoryPoolMXBean.getName() + " Memory Used"); |
| statistics.add(injectedStatistic); |
| } |
| catch (NoSuchMethodException e) |
| { |
| LOGGER.warn("Failed to inject statistic '{}'", statisticName, e); |
| } |
| } |
| |
| for (GarbageCollectorMXBean garbageCollectorMXBean : ManagementFactory.getGarbageCollectorMXBeans()) |
| { |
| String gcName = garbageCollectorMXBean.getName().replace(" ", ""); |
| String jvmGCCollectionTimeStatisticName = "jvmGCCollectionTime" + gcName; |
| try |
| { |
| Method getGCCollectionTime = BrokerAttributeInjector.class.getDeclaredMethod("getGCCollectionTime", |
| Broker.class, |
| GarbageCollectorMXBean.class); |
| final ConfiguredObjectInjectedStatistic<?, ?> injectedStatistic = |
| new ConfiguredObjectInjectedStatistic<>(jvmGCCollectionTimeStatisticName, |
| getGCCollectionTime, |
| new Object[]{garbageCollectorMXBean}, |
| "Cumulative time in ms taken to perform collections for GC " + garbageCollectorMXBean.getName(), |
| _typeValidator, |
| StatisticUnit.COUNT, |
| StatisticType.CUMULATIVE, |
| garbageCollectorMXBean.getName() |
| + " GC Collection Time"); |
| statistics.add(injectedStatistic); |
| } |
| catch (NoSuchMethodException e) |
| { |
| LOGGER.warn("Failed to inject statistic '{}'", jvmGCCollectionTimeStatisticName, e); |
| } |
| String jvmGCCollectionCountStatisticName = "jvmGCCollectionCount" + gcName; |
| try |
| { |
| Method getGCCollectionCount = BrokerAttributeInjector.class.getDeclaredMethod("getGCCollectionCount", |
| Broker.class, |
| GarbageCollectorMXBean.class); |
| final ConfiguredObjectInjectedStatistic<?, ?> injectedStatistic = |
| new ConfiguredObjectInjectedStatistic<>(jvmGCCollectionCountStatisticName, |
| getGCCollectionCount, |
| new Object[]{garbageCollectorMXBean}, |
| "Cumulative number of collections for GC " + garbageCollectorMXBean.getName(), |
| _typeValidator, |
| StatisticUnit.COUNT, |
| StatisticType.CUMULATIVE, |
| garbageCollectorMXBean.getName() |
| + " GC Collection Count"); |
| statistics.add(injectedStatistic); |
| } |
| catch (NoSuchMethodException e) |
| { |
| LOGGER.warn("Failed to inject statistic '{}'", jvmGCCollectionCountStatisticName, e); |
| } |
| } |
| return statistics; |
| } |
| |
| @Override |
| public Collection<ConfiguredObjectInjectedOperation<?>> getInjectedOperations() |
| { |
| List<ConfiguredObjectInjectedOperation<?>> operations = new ArrayList<>(); |
| |
| if (_hotSpotDiagnosticMXBean != null) |
| { |
| try |
| { |
| operations.add(injectSetJVMOptions()); |
| } |
| catch (NoSuchMethodException e) |
| { |
| LOGGER.warn("Failed to inject operation setJVMOptions", e); |
| } |
| |
| try |
| { |
| operations.add(injectDumpHeap()); |
| } |
| catch (NoSuchMethodException e) |
| { |
| LOGGER.warn("Failed to inject operation dumpHeap", e); |
| } |
| } |
| |
| return operations; |
| } |
| |
| private ConfiguredObjectInjectedOperation<?> injectDumpHeap() throws NoSuchMethodException |
| { |
| Method heapDumpMethod = |
| _hotSpotDiagnosticMXBeanClass.getDeclaredMethod("dumpHeap", String.class, boolean.class); |
| |
| Method method = BrokerAttributeInjector.class.getDeclaredMethod("dumpHeap", |
| Broker.class, |
| PlatformManagedObject.class, |
| Method.class, |
| String.class, |
| boolean.class); |
| |
| final OperationParameter[] params = new OperationParameter[2]; |
| |
| params[0] = new OperationParameterFromInjection("outputFile", |
| String.class, |
| String.class, |
| "", |
| "the system-dependent filename", |
| new String[0], true); |
| params[1] = new OperationParameterFromInjection("live", |
| boolean.class, |
| boolean.class, |
| "true", |
| "if true dump only live objects i.e. objects that are reachable from others", |
| new String[]{Boolean.TRUE.toString(), Boolean.FALSE.toString()}, |
| false); |
| ConfiguredObjectInjectedOperation<?> setVMOptionOperation = new ConfiguredObjectInjectedOperation( |
| "dumpHeap", |
| "Dumps the heap to the outputFile file in the same format as the hprof heap dump.", |
| true, |
| false, |
| "", |
| params, |
| method, |
| new Object[]{_hotSpotDiagnosticMXBean, heapDumpMethod}, |
| _typeValidator); |
| return setVMOptionOperation; |
| } |
| |
| private ConfiguredObjectInjectedOperation<?> injectSetJVMOptions() throws NoSuchMethodException |
| { |
| |
| Method setVMOptionMethod = |
| _hotSpotDiagnosticMXBeanClass.getDeclaredMethod("setVMOption", String.class, String.class); |
| |
| Method method = BrokerAttributeInjector.class.getDeclaredMethod("setJVMOptions", |
| Broker.class, |
| PlatformManagedObject.class, |
| Method.class, |
| Map.class); |
| |
| final OperationParameter[] params = |
| new OperationParameter[]{new OperationParameterFromInjection("options", |
| Map.class, |
| ParameterizedTypes.MAP_OF_STRING_STRING, |
| "", |
| "JVM options map", |
| new String[0], true)}; |
| ConfiguredObjectInjectedOperation<?> setVMOptionOperation = new ConfiguredObjectInjectedOperation( |
| "setJVMOptions", |
| "Sets given JVM options", |
| true, |
| false, |
| "", |
| params, |
| method, |
| new Object[]{_hotSpotDiagnosticMXBean, setVMOptionMethod}, |
| _typeValidator); |
| return setVMOptionOperation; |
| } |
| |
| @Override |
| public String getType() |
| { |
| return "Broker"; |
| } |
| |
| public static long getMemoryPoolUsed(Broker<?> broker, MemoryPoolMXBean memoryPoolMXBean) |
| { |
| return memoryPoolMXBean.getUsage().getUsed(); |
| } |
| |
| public static long getMemoryPoolMaximum(Broker<?> broker, MemoryPoolMXBean memoryPoolMXBean) |
| { |
| return memoryPoolMXBean.getUsage().getMax(); |
| } |
| |
| public static long getGCCollectionTime(Broker<?> broker, GarbageCollectorMXBean garbageCollectorMXBean) |
| { |
| return garbageCollectorMXBean.getCollectionTime(); |
| } |
| |
| public static long getGCCollectionCount(Broker<?> broker, GarbageCollectorMXBean garbageCollectorMXBean) |
| { |
| return garbageCollectorMXBean.getCollectionCount(); |
| } |
| |
| public static void setJVMOptions(Broker<?> broker, |
| PlatformManagedObject hotSpotDiagnosticMXBean, |
| Method setVMOption, |
| Map<String, String> options) |
| { |
| broker.getEventLogger().message(BrokerMessages.OPERATION("setJVMOptions")); |
| StringBuilder exceptionMessages = new StringBuilder(); |
| for (Map.Entry<String, String> entry : options.entrySet()) |
| { |
| try |
| { |
| setVMOption.invoke(hotSpotDiagnosticMXBean, entry.getKey(), entry.getValue()); |
| } |
| catch (IllegalAccessException e) |
| { |
| LOGGER.warn("Cannot access setVMOption " + setVMOption); |
| } |
| catch (InvocationTargetException e) |
| { |
| if (exceptionMessages.length() > 0) |
| { |
| exceptionMessages.append(";"); |
| } |
| exceptionMessages.append(e.getTargetException().toString()); |
| LOGGER.warn("Cannot set option {} to {} due to {}", |
| entry.getKey(), |
| entry.getValue(), |
| e.getTargetException().toString()); |
| } |
| |
| if (exceptionMessages.length() > 0) |
| { |
| throw new IllegalConfigurationException("Exception(s) occurred whilst setting JVM options : " + |
| exceptionMessages.toString()); |
| } |
| } |
| } |
| |
| public static void dumpHeap(Broker<?> broker, |
| PlatformManagedObject hotSpotDiagnosticMXBean, |
| Method dumpHeapMethod, |
| String outputFile, |
| boolean live) |
| { |
| broker.getEventLogger().message(BrokerMessages.OPERATION("dumpHeap")); |
| try |
| { |
| dumpHeapMethod.invoke(hotSpotDiagnosticMXBean, outputFile, live); |
| } |
| catch (IllegalAccessException e) |
| { |
| LOGGER.warn("Cannot access dumpHeap " + dumpHeapMethod); |
| } |
| catch (InvocationTargetException e) |
| { |
| String causeAsString = e.getTargetException().toString(); |
| LOGGER.warn("Cannot collect heap dump into {} (with parameter 'live' set to '{}') due to {}", |
| outputFile, |
| live, |
| causeAsString); |
| throw new IllegalConfigurationException("Unexpected exception on collecting heap dump : " |
| + causeAsString, |
| e.getTargetException()); |
| } |
| } |
| } |