You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by or...@apache.org on 2016/02/05 23:58:00 UTC
svn commit: r1728772 - in
/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server:
logging/messages/ model/ model/adapter/
Author: orudyy
Date: Fri Feb 5 22:58:00 2016
New Revision: 1728772
URL: http://svn.apache.org/viewvc?rev=1728772&view=rev
Log:
QPID-6932: Enhance model object to expose key JVM statistics such as heap memory, garbage collection, etc. Add security checks and operational logs for broker operations
Added:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/BrokerMessages.java
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/BrokerMessages.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/BrokerMessages.java?rev=1728772&r1=1728771&r2=1728772&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/BrokerMessages.java (original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/BrokerMessages.java Fri Feb 5 22:58:00 2016
@@ -54,6 +54,7 @@ public class BrokerMessages
public static final String FLOW_TO_DISK_ACTIVE_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "broker.flow_to_disk_active";
public static final String MAX_MEMORY_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "broker.max_memory";
public static final String PLATFORM_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "broker.platform";
+ public static final String OPERATION_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "broker.operation";
public static final String PROCESS_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "broker.process";
public static final String SHUTTING_DOWN_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "broker.shutting_down";
public static final String MANAGEMENT_MODE_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "broker.management_mode";
@@ -73,6 +74,7 @@ public class BrokerMessages
LoggerFactory.getLogger(FLOW_TO_DISK_ACTIVE_LOG_HIERARCHY);
LoggerFactory.getLogger(MAX_MEMORY_LOG_HIERARCHY);
LoggerFactory.getLogger(PLATFORM_LOG_HIERARCHY);
+ LoggerFactory.getLogger(OPERATION_LOG_HIERARCHY);
LoggerFactory.getLogger(PROCESS_LOG_HIERARCHY);
LoggerFactory.getLogger(SHUTTING_DOWN_LOG_HIERARCHY);
LoggerFactory.getLogger(MANAGEMENT_MODE_LOG_HIERARCHY);
@@ -573,6 +575,64 @@ public class BrokerMessages
}
@Override
+ public boolean equals(final Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass())
+ {
+ return false;
+ }
+
+ final LogMessage that = (LogMessage) o;
+
+ return getLogHierarchy().equals(that.getLogHierarchy()) && toString().equals(that.toString());
+
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = toString().hashCode();
+ result = 31 * result + getLogHierarchy().hashCode();
+ return result;
+ }
+ };
+ }
+
+ /**
+ * Log a Broker message of the Format:
+ * <pre>BRK-1018 : Operation : {0}</pre>
+ * Optional values are contained in [square brackets] and are numbered
+ * sequentially in the method call.
+ *
+ */
+ public static LogMessage OPERATION(String param1)
+ {
+ String rawMessage = _messages.getString("OPERATION");
+
+ final Object[] messageArguments = {param1};
+ // Create a new MessageFormat to ensure thread safety.
+ // Sharing a MessageFormat and using applyPattern is not thread safe
+ MessageFormat formatter = new MessageFormat(rawMessage, _currentLocale);
+
+ final String message = formatter.format(messageArguments);
+
+ return new LogMessage()
+ {
+ public String toString()
+ {
+ return message;
+ }
+
+ public String getLogHierarchy()
+ {
+ return OPERATION_LOG_HIERARCHY;
+ }
+
+ @Override
public boolean equals(final Object o)
{
if (this == o)
Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties?rev=1728772&r1=1728771&r2=1728772&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties (original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties Fri Feb 5 22:58:00 2016
@@ -58,3 +58,6 @@ FATAL_ERROR = BRK-1016 : Fatal error : {
# 0 - pid
PROCESS = BRK-1017 : Process : PID : {0}
+
+# 0 - operation name
+OPERATION = BRK-1018 : Operation : {0}
Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java?rev=1728772&r1=1728771&r2=1728772&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java (original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java Fri Feb 5 22:58:00 2016
@@ -177,6 +177,7 @@ public abstract class AbstractConfigured
private boolean _openComplete;
private boolean _openFailed;
private volatile State _state = State.UNINITIALIZED;
+ private volatile long _lastOpenedTime;
protected static Map<Class<? extends ConfiguredObject>, ConfiguredObject<?>> parentsMap(ConfiguredObject<?>... parents)
{
@@ -946,6 +947,7 @@ public abstract class AbstractConfigured
}
});
_openComplete = true;
+ _lastOpenedTime = System.currentTimeMillis();
}
}
@@ -2758,6 +2760,11 @@ public abstract class AbstractConfigured
}
}
+ @Override
+ public final long getLastOpenedTime()
+ {
+ return _lastOpenedTime;
+ }
//=========================================================================================
static String interpolate(ConfiguredObject<?> object, String value)
Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java?rev=1728772&r1=1728771&r2=1728772&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java (original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java Fri Feb 5 22:58:00 2016
@@ -21,6 +21,7 @@
package org.apache.qpid.server.model;
import java.util.Collection;
+import java.util.List;
import org.apache.qpid.server.logging.EventLogger;
import org.apache.qpid.server.logging.EventLoggerProvider;
@@ -160,6 +161,61 @@ public interface Broker<X extends Broker
@ManagedOperation(nonModifying = true, description = "Initiates an orderly shutdown of the Broker.")
void initiateShutdown();
+ @DerivedAttribute(description = "Maximum heap memory size")
+ long getMaximumHeapMemorySize();
+
+ @DerivedAttribute(description = "Maximum direct memory size which can be consumed by broker")
+ long getMaximumDirectMemorySize();
+
+ @DerivedAttribute(description = "JVM arguments specified on startup")
+ List<String> getJVMArguments();
+
+ @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
+ units = StatisticUnit.COUNT,
+ label = "Live threads",
+ description = "Number of live threads")
+ int getNumberOfLiveThreads();
+
+ @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
+ units = StatisticUnit.BYTES,
+ label = "Used Heap Memory Size",
+ description = "Size of used heap memory")
+ long getUsedHeapMemorySize();
+
+ @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
+ units = StatisticUnit.BYTES,
+ label = "Used Direct Memory Size",
+ description = "Size of used direct memory")
+ long getUsedDirectMemorySize();
+
+ @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
+ units = StatisticUnit.BYTES,
+ label = "Direct Memory Total Capacity",
+ description = "Total capacity of direct memory allocated for the Broker process")
+ long getDirectMemoryTotalCapacity();
+
+ @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
+ units = StatisticUnit.COUNT,
+ label = "Number Of Object Pending Finalization",
+ description = "Number of objects pending finalization")
+ int getNumberOfObjectsPendingFinalization();
+
+ @ManagedOperation(nonModifying = true, description = "Initiates garbage collection")
+ void performGC();
+
+ @ManagedOperation(nonModifying = true,
+ description = "Collects thread stack traces and dead locks. Dumps stack traces into logs if requested")
+ Content getThreadStackTraces(@Param(name="appendToLog",
+ defaultValue = "false",
+ description = "If true, appends stack traces into logs")
+ boolean appendToLog);
+
+ @ManagedOperation(nonModifying = true,
+ description = "Collects thread stack traces for the threads with names containing matching characters for given regular expression")
+ Content findThreadStackTraces(@Param(name="threadNameFindExpression",
+ description = "Regular expression to find threads with names containing matching characters")
+ String threadNameFindExpression);
+
//children
Collection<VirtualHostNode<?>> getVirtualHostNodes();
Added: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java?rev=1728772&view=auto
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java (added)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java Fri Feb 5 22:58:00 2016
@@ -0,0 +1,398 @@
+/*
+ *
+ * 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.security.access.Operation;
+import org.apache.qpid.server.util.ParameterizedTypeImpl;
+
+@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);
+ }
+ };
+
+
+ @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",
+ _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",
+ _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 by GC to perform collections",
+ _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 GC collections",
+ _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<>();
+
+ try
+ {
+ ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
+ final Class<?> hotSpotDiagnosticMXBeanClass =
+ Class.forName("com.sun.management.HotSpotDiagnosticMXBean", true, systemClassLoader);
+ final PlatformManagedObject hotSpotDiagnosticMXBean =
+ ManagementFactory.getPlatformMXBean((Class<? extends PlatformManagedObject>) hotSpotDiagnosticMXBeanClass);
+
+ ConfiguredObjectInjectedOperation<?> setJVMOptions =
+ injectSetJVMOptions(hotSpotDiagnosticMXBeanClass, hotSpotDiagnosticMXBean);
+ if (setJVMOptions != null)
+ {
+ operations.add(setJVMOptions);
+ }
+
+ ConfiguredObjectInjectedOperation<?> heapDump =
+ injectDumpHeap(hotSpotDiagnosticMXBeanClass, hotSpotDiagnosticMXBean);
+ if (heapDump != null)
+ {
+ operations.add(heapDump);
+ }
+ }
+ catch (ClassNotFoundException e)
+ {
+ LOGGER.warn("Cannot find com.sun.management.HotSpotDiagnosticMXBean MXBean: " + e.getMessage());
+ }
+
+
+ return operations;
+ }
+
+ private ConfiguredObjectInjectedOperation<?> injectDumpHeap(
+ final Class<?> hotSpotDiagnosticMXBeanClass,
+ final PlatformManagedObject hotSpotDiagnosticMXBean)
+ {
+ try
+ {
+ 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]);
+ 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()});
+ ConfiguredObjectInjectedOperation<?> setVMOptionOperation = new ConfiguredObjectInjectedOperation(
+ "dumpHeap",
+ "Dumps the heap to the outputFile file in the same format as the hprof heap dump.",
+ true,
+ params,
+ method,
+ new Object[]{hotSpotDiagnosticMXBean, heapDumpMethod},
+ _typeValidator);
+ return setVMOptionOperation;
+ }
+ catch (NoSuchMethodException e)
+ {
+ LOGGER.warn("Failed to inject operation dumpHeap", e);
+ }
+ return null;
+ }
+
+ private ConfiguredObjectInjectedOperation<?> injectSetJVMOptions(
+ final Class<?> hotSpotDiagnosticMXBeanClass,
+ final PlatformManagedObject hotSpotDiagnosticMXBean)
+ {
+ try
+ {
+ 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,
+ new ParameterizedTypeImpl(
+ Map.class,
+ String.class,
+ String.class),
+ "",
+ "JVM options map",
+ new String[0])};
+ ConfiguredObjectInjectedOperation<?> setVMOptionOperation = new ConfiguredObjectInjectedOperation(
+ "setJVMOptions",
+ "Sets given JVM options",
+ true,
+ params,
+ method,
+ new Object[]{hotSpotDiagnosticMXBean, setVMOptionMethod},
+ _typeValidator);
+ return setVMOptionOperation;
+ }
+ catch (NoSuchMethodException e)
+ {
+ LOGGER.warn("Failed to inject operation setJVMOptions", e);
+ }
+ return null;
+ }
+
+ @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.getSecurityManager().authorise(Operation.CONFIGURE, broker);
+ 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.getSecurityManager().authorise(Operation.CONFIGURE, broker);
+ 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());
+ }
+ }
+}
Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java?rev=1728772&r1=1728771&r2=1728772&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java (original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java Fri Feb 5 22:58:00 2016
@@ -125,6 +125,8 @@ public interface ConfiguredObject<X exte
@DerivedAttribute
State getState();
+ @DerivedAttribute
+ long getLastOpenedTime();
/**
* Add a listener which will be informed of all changes to this configuration object
Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java?rev=1728772&r1=1728771&r2=1728772&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java (original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java Fri Feb 5 22:58:00 2016
@@ -20,11 +20,19 @@
*/
package org.apache.qpid.server.model.adapter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.management.BufferPoolMXBean;
+import java.lang.management.LockInfo;
import java.lang.management.ManagementFactory;
+import java.lang.management.MonitorInfo;
import java.lang.management.PlatformManagedObject;
import java.lang.management.RuntimeMXBean;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.nio.charset.Charset;
import java.security.AccessControlException;
import java.security.PrivilegedAction;
import java.util.ArrayList;
@@ -117,6 +125,10 @@ public class BrokerAdapter extends Abstr
private final boolean _virtualHostPropertiesNodeEnabled;
private Collection<BrokerLogger> _brokerLoggersToClose;
private int _networkBufferSize = DEFAULT_NETWORK_BUFFER_SIZE;
+ private final long _maximumHeapHize = Runtime.getRuntime().maxMemory();
+ private final long _maximumDirectMemorySize = getMaxDirectMemorySize();
+ private final BufferPoolMXBean _bufferPoolMXBean;
+ private final List<String> _inputArguments;
@ManagedObjectFactoryConstructor
public BrokerAdapter(Map<String, Object> attributes,
@@ -149,6 +161,19 @@ public class BrokerAdapter extends Abstr
_dataDelivered = new StatisticsCounter("bytes-delivered");
_messagesReceived = new StatisticsCounter("messages-received");
_dataReceived = new StatisticsCounter("bytes-received");
+
+ BufferPoolMXBean bufferPoolMXBean = null;
+ List<BufferPoolMXBean> bufferPoolMXBeans = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);
+ for(BufferPoolMXBean mBean : bufferPoolMXBeans)
+ {
+ if (mBean.getName().equals("direct"))
+ {
+ bufferPoolMXBean = mBean;
+ break;
+ }
+ }
+ _bufferPoolMXBean = bufferPoolMXBean;
+ _inputArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
}
private void updateEncrypter(final String encryptionProviderType)
@@ -307,6 +332,7 @@ public class BrokerAdapter extends Abstr
public void initiateShutdown()
{
_securityManager.authorise(Operation.SHUTDOWN, this);
+ getEventLogger().message(BrokerMessages.OPERATION("initiateShutdown"));
_parent.closeAsync();
}
@@ -982,4 +1008,228 @@ public class BrokerAdapter extends Abstr
{
return _networkBufferSize;
}
+
+ @Override
+ public int getNumberOfLiveThreads()
+ {
+ return ManagementFactory.getThreadMXBean().getThreadCount();
+ }
+
+ @Override
+ public long getMaximumHeapMemorySize()
+ {
+ return _maximumHeapHize;
+ }
+
+ @Override
+ public long getUsedHeapMemorySize()
+ {
+ return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+ }
+
+ @Override
+ public long getMaximumDirectMemorySize()
+ {
+ return _maximumDirectMemorySize;
+ }
+
+ @Override
+ public long getUsedDirectMemorySize()
+ {
+ if (_bufferPoolMXBean == null)
+ {
+ return -1;
+ }
+ return _bufferPoolMXBean.getMemoryUsed();
+ }
+
+ @Override
+ public long getDirectMemoryTotalCapacity()
+ {
+ if (_bufferPoolMXBean == null)
+ {
+ return -1;
+ }
+ return _bufferPoolMXBean.getTotalCapacity();
+ }
+
+ @Override
+ public int getNumberOfObjectsPendingFinalization()
+ {
+ return ManagementFactory.getMemoryMXBean().getObjectPendingFinalizationCount();
+ }
+
+ @Override
+ public List<String> getJVMArguments()
+ {
+ return _inputArguments;
+ }
+
+ @Override
+ public void performGC()
+ {
+ _securityManager.authorise(Operation.CONFIGURE, this);
+ getEventLogger().message(BrokerMessages.OPERATION("performGC"));
+ System.gc();
+ }
+
+ @Override
+ public Content getThreadStackTraces(boolean appendToLog)
+ {
+ _securityManager.authorise(Operation.CONFIGURE, this);
+ getEventLogger().message(BrokerMessages.OPERATION("getThreadStackTraces"));
+ ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
+ ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(true, true);
+ StringBuilder threadDump = new StringBuilder();
+ for (ThreadInfo threadInfo : threadInfos)
+ {
+ threadDump.append(getThreadStackTraces(threadInfo));
+ }
+ long[] deadLocks = threadMXBean.findDeadlockedThreads();
+ if (deadLocks != null && deadLocks.length > 0)
+ {
+ ThreadInfo[] deadlockedThreads = threadMXBean.getThreadInfo(deadLocks);
+ threadDump.append(System.lineSeparator()).append("Deadlock is detected!").append(System.lineSeparator());
+ for (ThreadInfo threadInfo : deadlockedThreads)
+ {
+ threadDump.append(getThreadStackTraces(threadInfo));
+ }
+ }
+ String threadStackTraces = threadDump.toString();
+ if (appendToLog)
+ {
+ LOGGER.warn("Thread dump:{} {}", System.lineSeparator(), threadStackTraces);
+ }
+ return new ThreadStackContent(threadStackTraces);
+ }
+
+ @Override
+ public Content findThreadStackTraces(String threadNameFindExpression)
+ {
+ _securityManager.authorise(Operation.CONFIGURE, this);
+ getEventLogger().message(BrokerMessages.OPERATION("findThreadStackTraces"));
+ ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
+ ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(true, true);
+ StringBuilder threadDump = new StringBuilder();
+ Pattern pattern = threadNameFindExpression == null || threadNameFindExpression.equals("") ? null : Pattern.compile(
+ threadNameFindExpression);
+ for (ThreadInfo threadInfo : threadInfos)
+ {
+ if (pattern== null || pattern.matcher(threadInfo.getThreadName()).find())
+ {
+ threadDump.append(getThreadStackTraces(threadInfo));
+ }
+ }
+ return new ThreadStackContent(threadDump.toString());
+ }
+
+ private String getThreadStackTraces(final ThreadInfo threadInfo)
+ {
+ String lineSeparator = System.lineSeparator();
+ StringBuilder dump = new StringBuilder();
+ dump.append("\"").append(threadInfo.getThreadName()).append("\"").append(" Id=")
+ .append(threadInfo.getThreadId()).append( " ").append(threadInfo.getThreadState());
+ if (threadInfo.getLockName() != null)
+ {
+ dump.append(" on ").append(threadInfo.getLockName());
+ }
+ if (threadInfo.getLockOwnerName() != null)
+ {
+ dump.append(" owned by \"").append(threadInfo.getLockOwnerName())
+ .append("\" Id=").append(threadInfo.getLockOwnerId());
+ }
+ if (threadInfo.isSuspended())
+ {
+ dump.append(" (suspended)");
+ }
+ if (threadInfo.isInNative())
+ {
+ dump.append(" (in native)");
+ }
+ dump.append(lineSeparator);
+ StackTraceElement[] stackTrace = threadInfo.getStackTrace();
+ for (int i = 0; i < stackTrace.length; i++)
+ {
+ StackTraceElement stackTraceElement = stackTrace[i];
+ dump.append(" at ").append(stackTraceElement.toString()).append(lineSeparator);
+
+ LockInfo lockInfo = threadInfo.getLockInfo();
+ if (i == 0 && lockInfo != null)
+ {
+ Thread.State threadState = threadInfo.getThreadState();
+ switch (threadState)
+ {
+ case BLOCKED:
+ dump.append(" - blocked on ").append(lockInfo).append(lineSeparator);
+ break;
+ case WAITING:
+ dump.append(" - waiting on ").append(lockInfo).append(lineSeparator);
+ break;
+ case TIMED_WAITING:
+ dump.append(" - waiting on ").append(lockInfo).append(lineSeparator);
+ break;
+ default:
+ }
+ }
+
+ for (MonitorInfo mi : threadInfo.getLockedMonitors())
+ {
+ if (mi.getLockedStackDepth() == i)
+ {
+ dump.append(" - locked ").append(mi).append(lineSeparator);
+ }
+ }
+ }
+
+ LockInfo[] locks = threadInfo.getLockedSynchronizers();
+ if (locks.length > 0)
+ {
+ dump.append(lineSeparator).append(" Number of locked synchronizers = ").append(locks.length);
+ dump.append(lineSeparator);
+ for (LockInfo li : locks)
+ {
+ dump.append(" - " + li);
+ dump.append(lineSeparator);
+ }
+ }
+ dump.append(lineSeparator);
+ return dump.toString();
+ }
+
+ public static class ThreadStackContent implements Content, CustomRestHeaders
+ {
+ private final String _threadStackTraces;
+
+ public ThreadStackContent(final String threadStackTraces)
+ {
+ _threadStackTraces = threadStackTraces;
+ }
+
+ @Override
+ public void write(final OutputStream outputStream) throws IOException
+ {
+ if (_threadStackTraces != null)
+ {
+ outputStream.write(_threadStackTraces.getBytes(Charset.forName("UTF-8")));
+ }
+ }
+
+ @Override
+ public void release()
+ {
+ // noop; nothing to release
+ }
+
+ @RestContentHeader("Content-Type")
+ public String getContentType()
+ {
+ return "text/plain;charset=utf-8";
+ }
+
+ @RestContentHeader("Content-Length")
+ public long getSize()
+ {
+ return _threadStackTraces == null ? 0 : _threadStackTraces.length();
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org