All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glowroot.agent.live.LiveJvmServiceImpl Maven / Gradle / Ivy

There is a newer version: 0.14.0-beta.3
Show newest version
/*
 * Copyright 2015-2019 the original author or authors.
 *
 * Licensed 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.glowroot.agent.live;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import javax.management.InstanceNotFoundException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.QueryExp;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.TabularData;

import org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.annotations.VisibleForTesting;
import org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.base.Joiner;
import org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.collect.ImmutableList;
import org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.collect.ImmutableSet;
import org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.collect.Lists;
import org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.collect.Ordering;
import org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.collect.Sets;
import org.glowroot.agent.shaded.org.checkerframework.checker.nullness.qual.Nullable;
import org.glowroot.agent.shaded.org.glowroot.agent.shaded.org.slf4j.Logger;
import org.glowroot.agent.shaded.org.glowroot.agent.shaded.org.slf4j.LoggerFactory;

import org.glowroot.agent.config.ConfigService;
import org.glowroot.agent.impl.TraceCollector;
import org.glowroot.agent.impl.TransactionRegistry;
import org.glowroot.agent.util.JavaVersion;
import org.glowroot.agent.util.LazyPlatformMBeanServer;
import org.glowroot.agent.shaded.org.glowroot.common.live.LiveJvmService;
import org.glowroot.agent.shaded.org.glowroot.common.util.Clock;
import org.glowroot.agent.shaded.org.glowroot.common.util.Masking;
import org.glowroot.agent.shaded.org.glowroot.common.util.Throwables;
import org.glowroot.agent.shaded.org.glowroot.wire.api.model.DownstreamServiceOuterClass.Availability;
import org.glowroot.agent.shaded.org.glowroot.wire.api.model.DownstreamServiceOuterClass.Capabilities;
import org.glowroot.agent.shaded.org.glowroot.wire.api.model.DownstreamServiceOuterClass.HeapDumpFileInfo;
import org.glowroot.agent.shaded.org.glowroot.wire.api.model.DownstreamServiceOuterClass.HeapHistogram;
import org.glowroot.agent.shaded.org.glowroot.wire.api.model.DownstreamServiceOuterClass.MBeanDump;
import org.glowroot.agent.shaded.org.glowroot.wire.api.model.DownstreamServiceOuterClass.MBeanDumpRequest.MBeanDumpKind;
import org.glowroot.agent.shaded.org.glowroot.wire.api.model.DownstreamServiceOuterClass.MBeanMeta;
import org.glowroot.agent.shaded.org.glowroot.wire.api.model.DownstreamServiceOuterClass.ThreadDump;

import static org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.base.Preconditions.checkNotNull;

public class LiveJvmServiceImpl implements LiveJvmService {

    private static final Logger logger = LoggerFactory.getLogger(LiveJvmServiceImpl.class);

    private static final String HOT_SPOT_DIAGNOSTIC_MBEAN_NAME =
            "com.sun.management:type=HotSpotDiagnostic";

    private static final @Nullable Long PROCESS_ID =
            parseProcessId(ManagementFactory.getRuntimeMXBean().getName());

    private static final ImmutableSet numericAttributeTypes =
            ImmutableSet.of("long", "int", "double", "float", "java.lang.Long", "java.lang.Integer",
                    "java.lang.Double", "java.lang.Float");

    private final LazyPlatformMBeanServer lazyPlatformMBeanServer;
    private final ThreadDumpService threadDumpService;
    private final Availability threadAllocatedBytesAvailability;
    private final ConfigService configService;
    private final @Nullable File glowrootJarFile;
    private final Clock clock;

    public LiveJvmServiceImpl(LazyPlatformMBeanServer lazyPlatformMBeanServer,
            TransactionRegistry transactionRegistry, TraceCollector traceCollector,
            Availability threadAllocatedBytesAvailability, ConfigService configService,
            @Nullable File glowrootJarFile, Clock clock) {
        this.lazyPlatformMBeanServer = lazyPlatformMBeanServer;
        threadDumpService = new ThreadDumpService(transactionRegistry, traceCollector);
        this.threadAllocatedBytesAvailability = threadAllocatedBytesAvailability;
        this.configService = configService;
        this.glowrootJarFile = glowrootJarFile;
        this.clock = clock;
    }

    @Override
    public boolean isAvailable(String agentId) {
        return true;
    }

    @Override
    public ThreadDump getThreadDump(String agentId) {
        return threadDumpService.getThreadDump();
    }

    @Override
    public String getJstack(String agentId) throws Exception {
        if (JavaVersion.isJ9Jvm()) {
            throw new UnavailableDueToRunningInJ9JvmException();
        }
        if (JavaVersion.isGreaterThanOrEqualToJava8()) {
            return JStackTool.run(lazyPlatformMBeanServer);
        } else {
            long pid = checkNotNull(LiveJvmServiceImpl.getProcessId());
            return JStackTool.runPriorToJava8(pid, allowAttachSelf(), glowrootJarFile);
        }
    }

    @Override
    public long getAvailableDiskSpace(String agentId, String directory)
            throws DirectoryDoesNotExistException {
        File dir = new File(directory);
        if (!dir.exists() || !dir.isDirectory()) {
            throw new DirectoryDoesNotExistException();
        }
        return dir.getFreeSpace();
    }

    @Override
    public HeapDumpFileInfo heapDump(String agentId, String directory) throws Exception {
        File dir = new File(directory);
        if (!dir.exists() || !dir.isDirectory()) {
            throw new DirectoryDoesNotExistException();
        }
        File file;
        if (JavaVersion.isJ9Jvm()) {
            file = j9HeapDump(dir);
        } else {
            file = heapDump(dir);
        }
        return HeapDumpFileInfo.newBuilder()
                .setFilePath(file.getAbsolutePath())
                .setFileSizeBytes(file.length())
                .build();
    }

    @Override
    public HeapHistogram heapHistogram(String agentId) throws Exception {
        if (JavaVersion.isJ9Jvm()) {
            throw new UnavailableDueToRunningInJ9JvmException();
        }
        if (JavaVersion.isGreaterThanOrEqualToJava8()) {
            return HeapHistogramTool.run(lazyPlatformMBeanServer);
        } else {
            long pid = checkNotNull(LiveJvmServiceImpl.getProcessId());
            return HeapHistogramTool.runPriorToJava8(pid, allowAttachSelf(), glowrootJarFile);
        }
    }

    @Override
    public boolean isExplicitGcDisabled(String agentId) throws Exception {
        if (JavaVersion.isGreaterThanOrEqualToJava10()) {
            // in Java 10+, no longer restricted by DisableExplicitGC due to
            // https://bugs.openjdk.java.net/browse/JDK-8186902
            return false;
        }
        boolean disabled = false;
        for (String jvmArg : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
            if (jvmArg.equals("-XX:+DisableExplicitGC")) {
                disabled = true;
            } else if (jvmArg.equals("-XX:-DisableExplicitGC")) {
                disabled = false;
            }
        }
        // last one wins
        return disabled;
    }

    @Override
    public void forceGC(String agentId) throws Exception {
        if (JavaVersion.isGreaterThanOrEqualToJava8()) {
            // this is a new way to force GC in Java 8+, which has benefit that in Java 10+, this is
            // longer restricted by DisableExplicitGC due to
            // https://bugs.openjdk.java.net/browse/JDK-8186902
            ObjectName objectName =
                    ObjectName.getInstance("com.sun.management:type=DiagnosticCommand");
            lazyPlatformMBeanServer.invoke(objectName, "gcRun", new Object[] {null},
                    new String[] {"[Ljava.lang.String;"});
        } else {
            System.gc();
        }
    }

    @Override
    public MBeanDump getMBeanDump(String agentId, MBeanDumpKind mbeanDumpKind,
            List objectNames) throws Exception {
        switch (mbeanDumpKind) {
            case ALL_MBEANS_INCLUDE_ATTRIBUTES:
                throw new UnsupportedOperationException("Not implemented yet");
            case ALL_MBEANS_INCLUDE_ATTRIBUTES_FOR_SOME:
                return MBeanDump.newBuilder()
                        .addAllMbeanInfo(getAllMBeanInfos(objectNames))
                        .build();
            case SOME_MBEANS_INCLUDE_ATTRIBUTES:
                return MBeanDump.newBuilder()
                        .addAllMbeanInfo(getSomeMBeanInfos(objectNames))
                        .build();
            default:
                throw new IllegalStateException("Unexpected mbean dump kind: " + mbeanDumpKind);
        }
    }

    private File heapDump(File directory) throws Exception {
        File file = generateHeapDumpFileName(directory, ".hprof");
        ObjectName objectName = ObjectName.getInstance(HOT_SPOT_DIAGNOSTIC_MBEAN_NAME);
        lazyPlatformMBeanServer.invoke(objectName, "dumpHeap",
                new Object[] {file.getAbsolutePath(), false},
                new String[] {"java.lang.String", "boolean"});
        return file;
    }

    private List getAllMBeanInfos(List includeAttrsForObjectNames)
            throws Exception {
        List mbeanServers = lazyPlatformMBeanServer.findAllMBeanServers();
        Set objectNames = lazyPlatformMBeanServer.queryNames(null, null, mbeanServers);
        List mbeanInfos = Lists.newArrayList();
        for (ObjectName objectName : objectNames) {
            String name = objectName.toString();
            if (includeAttrsForObjectNames.contains(name)) {
                mbeanInfos.add(MBeanDump.MBeanInfo.newBuilder()
                        .setObjectName(name)
                        .addAllAttribute(getMBeanAttributes(objectName))
                        .build());
            } else {
                mbeanInfos.add(MBeanDump.MBeanInfo.newBuilder()
                        .setObjectName(name)
                        .build());
            }
        }
        return mbeanInfos;
    }

    private List getSomeMBeanInfos(List includeObjectNames)
            throws Exception {
        List mbeanInfos = Lists.newArrayList();
        for (String objectName : includeObjectNames) {
            mbeanInfos.add(MBeanDump.MBeanInfo.newBuilder()
                    .setObjectName(objectName)
                    .addAllAttribute(getMBeanAttributes(new ObjectName(objectName)))
                    .build());
        }
        return mbeanInfos;
    }

    @Override
    public List getMatchingMBeanObjectNames(String agentId, String partialObjectName,
            int limit) throws Exception {
        ObjectNameQueryExp queryExp = new ObjectNameQueryExp(partialObjectName);
        List mbeanServers = lazyPlatformMBeanServer.findAllMBeanServers();
        Set objectNames =
                lazyPlatformMBeanServer.queryNames(null, queryExp, mbeanServers);
        // unfortunately Wildfly returns lots of mbean object names without checking them against
        // the query (see TODO comment in org.jboss.as.jmx.model.ModelControllerMBeanHelper)
        // so must re-filter
        List names = Lists.newArrayList();
        for (ObjectName objectName : objectNames) {
            String objectNameStr = objectName.toString();
            if (queryExp.apply(objectNameStr)) {
                names.add(objectNameStr);
            }
        }
        ImmutableList sortedNames = Ordering.natural().immutableSortedCopy(names);
        if (sortedNames.size() > limit) {
            sortedNames = sortedNames.subList(0, limit);
        }
        return sortedNames;
    }

    @Override
    public MBeanMeta getMBeanMeta(String agentId, String mbeanObjectName) throws Exception {
        Set objectNames = getObjectNames(mbeanObjectName);
        ImmutableList attributeNames =
                Ordering.natural().immutableSortedCopy(getAttributeNames(objectNames));
        return MBeanMeta.newBuilder()
                .setNoMatchFound(objectNames.isEmpty())
                .addAllAttributeName(attributeNames)
                .build();
    }

    @Override
    public Map getSystemProperties(String agentId) {
        Map systemProperties =
                ManagementFactory.getRuntimeMXBean().getSystemProperties();
        List maskSystemProperties = configService.getJvmConfig().maskSystemProperties();
        return Masking.maskSystemProperties(systemProperties, maskSystemProperties);
    }

    @Override
    public long getCurrentTime(String agentId) {
        return clock.currentTimeMillis();
    }

    @Override
    public Capabilities getCapabilities(String agentId) {
        return Capabilities.newBuilder()
                .setThreadCpuTime(getThreadCpuTimeAvailability())
                .setThreadContentionTime(getThreadContentionAvailability())
                .setThreadAllocatedBytes(threadAllocatedBytesAvailability)
                .build();
    }

    private List getMBeanAttributes(ObjectName objectName)
            throws Exception {
        List mbeanServers = lazyPlatformMBeanServer.findAllMBeanServers();
        MBeanInfo mBeanInfo = lazyPlatformMBeanServer.getMBeanInfo(objectName, mbeanServers);
        List maskPatterns =
                Masking.buildPatternList(configService.getJvmConfig().maskMBeanAttributes());
        List attributes = Lists.newArrayList();
        for (MBeanAttributeInfo attribute : mBeanInfo.getAttributes()) {
            Object value;
            String attributeName = attribute.getName();
            String fullAttributeName = objectName.toString() + ":" + attribute.getName();
            if (Masking.matchesAny(fullAttributeName, maskPatterns)) {
                value = Masking.MASKED_VALUE;
            } else {
                try {
                    value = lazyPlatformMBeanServer.getAttribute(objectName, attributeName,
                            mbeanServers);
                } catch (Exception e) {
                    // log exception at debug level
                    logger.debug(e.getMessage(), e);
                    value = "<" + Throwables.getBestMessage(e) + ">";
                }
            }
            attributes.add(MBeanDump.MBeanAttribute.newBuilder()
                    .setName(attributeName)
                    .setValue(getMBeanAttributeValue(value))
                    .build());
        }
        return attributes;
    }

    public static @Nullable Long getProcessId() {
        return PROCESS_ID;
    }

    @VisibleForTesting
    static @Nullable Long parseProcessId(String runtimeName) {
        int index = runtimeName.indexOf('@');
        if (index > 0) {
            String pid = runtimeName.substring(0, index);
            try {
                return Long.parseLong(pid);
            } catch (NumberFormatException e) {
                logger.debug(e.getMessage(), e);
                return null;
            }
        } else {
            return null;
        }
    }

    private static boolean allowAttachSelf() {
        if (JavaVersion.isJRockitJvm()) {
            // self attach sporadically logs annoying:
            // [ERROR][attach ] Failed to flush the destination file
            // [ERROR][attach ] OS message: The pipe has been ended (109)
            return false;
        }
        if (JavaVersion.isOSX()) {
            // self attach starts throwing IOException at some point
            // see https://github.com/glowroot/glowroot/issues/424
            return false;
        }
        return !JavaVersion.isGreaterThanOrEqualToJava9()
                || Boolean.getBoolean("jdk.attach.allowAttachSelf");
    }

    private static File j9HeapDump(File directory) throws Exception {
        File file = generateHeapDumpFileName(directory, ".phd");
        Class clazz = Class.forName("com.ibm.jvm.Dump");
        Method method = clazz.getMethod("heapDumpToFile", String.class);
        String actualHeapDumpPath =
                (String) checkNotNull(method.invoke(null, file.getAbsolutePath()));
        return new File(actualHeapDumpPath);
    }

    private static File generateHeapDumpFileName(File dir, String extension) {
        String timestamp = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date());
        File file = new File(dir, "heap-dump-" + timestamp + extension);
        int i = 1;
        while (file.exists()) {
            // this seems unlikely now that timestamp is included in file name
            i++;
            file = new File(dir, "heap-dump-" + timestamp + "-" + i + extension);
        }
        return file;
    }

    // see list of allowed attribute value types:
    // http://docs.oracle.com/javase/7/docs/api/javax/management/openmbean/OpenType.html
    // #ALLOWED_CLASSNAMES_LIST
    private static MBeanDump.MBeanValue getMBeanAttributeValue(@Nullable Object value) {
        if (value == null) {
            return MBeanDump.MBeanValue.newBuilder()
                    .setNull(true)
                    .build();
        } else if (value instanceof CompositeData) {
            return getCompositeDataValue((CompositeData) value);
        } else if (value instanceof TabularData) {
            return getTabularDataValue((TabularData) value);
        } else if (value.getClass().isArray()) {
            return getArrayValue(value);
        } else if (value instanceof Boolean) {
            return MBeanDump.MBeanValue.newBuilder()
                    .setBoolean((Boolean) value)
                    .build();
        } else if (value instanceof Long) {
            return MBeanDump.MBeanValue.newBuilder()
                    .setLong((Long) value)
                    .build();
        } else if (value instanceof Integer) {
            return MBeanDump.MBeanValue.newBuilder()
                    .setLong((Integer) value)
                    .build();
        } else if (value instanceof Number) {
            return MBeanDump.MBeanValue.newBuilder()
                    .setDouble(((Number) value).doubleValue())
                    .build();
        } else {
            return MBeanDump.MBeanValue.newBuilder()
                    .setString(checkNotNull(value.toString()))
                    .build();
        }
    }

    private static MBeanDump.MBeanValue getCompositeDataValue(CompositeData compositeData) {
        // linked hash map used to preserve attribute ordering
        List entries = Lists.newArrayList();
        for (String key : compositeData.getCompositeType().keySet()) {
            entries.add(MBeanDump.MBeanValueMapEntry.newBuilder()
                    .setKey(key)
                    .setValue(getMBeanAttributeValue(compositeData.get(key)))
                    .build());
        }
        return MBeanDump.MBeanValue.newBuilder()
                .setMap(MBeanDump.MBeanValueMap.newBuilder()
                        .addAllEntry(entries))
                .build();
    }

    private static MBeanDump.MBeanValue getTabularDataValue(TabularData tabularData) {
        // linked hash map used to preserve row ordering
        List outerEntries = Lists.newArrayList();
        Set attributeNames = tabularData.getTabularType().getRowType().keySet();
        for (Object key : tabularData.keySet()) {
            // TabularData.keySet() returns "Set> but is declared Set for
            // compatibility reasons" (see javadocs) so safe to cast to List
            List keyList = (List) key;
            @SuppressWarnings("argument.type.incompatible")
            String keyString = Joiner.on(", ").join(keyList);
            @SuppressWarnings("argument.type.incompatible")
            CompositeData compositeData = tabularData.get(keyList.toArray());
            // linked hash map used to preserve attribute ordering
            List innerEntries = Lists.newArrayList();
            for (String attributeName : attributeNames) {
                innerEntries.add(MBeanDump.MBeanValueMapEntry.newBuilder()
                        .setKey(attributeName)
                        .setValue(getMBeanAttributeValue(compositeData.get(attributeName)))
                        .build());
            }
            outerEntries.add(MBeanDump.MBeanValueMapEntry.newBuilder()
                    .setKey(keyString)
                    .setValue(MBeanDump.MBeanValue.newBuilder()
                            .setMap(MBeanDump.MBeanValueMap.newBuilder()
                                    .addAllEntry(innerEntries))
                            .build())
                    .build());
        }
        return MBeanDump.MBeanValue.newBuilder()
                .setMap(MBeanDump.MBeanValueMap.newBuilder()
                        .addAllEntry(outerEntries))
                .build();
    }

    private static MBeanDump.MBeanValue getArrayValue(Object value) {
        int length = Array.getLength(value);
        List values = Lists.newArrayListWithCapacity(length);
        for (int i = 0; i < length; i++) {
            Object val = Array.get(value, i);
            values.add(getMBeanAttributeValue(val));
        }
        return MBeanDump.MBeanValue.newBuilder()
                .setList(MBeanDump.MBeanValueList.newBuilder()
                        .addAllValue(values))
                .build();
    }

    private Set getObjectNames(String mbeanObjectName) throws Exception {
        ObjectName objectName = ObjectName.getInstance(mbeanObjectName);
        List mbeanServers = lazyPlatformMBeanServer.findAllMBeanServers();
        if (objectName.isPattern()) {
            return lazyPlatformMBeanServer.queryNames(objectName, null, mbeanServers);
        } else {
            try {
                lazyPlatformMBeanServer.getMBeanInfo(objectName, mbeanServers);
            } catch (InstanceNotFoundException e) {
                return ImmutableSet.of();
            }
            return ImmutableSet.of(objectName);
        }
    }

    private Set getAttributeNames(Set objectNames) throws Exception {
        List mbeanServers = lazyPlatformMBeanServer.findAllMBeanServers();
        Set attributeNames = Sets.newHashSet();
        for (ObjectName objectName : objectNames) {
            try {
                MBeanInfo mbeanInfo =
                        lazyPlatformMBeanServer.getMBeanInfo(objectName, mbeanServers);
                attributeNames.addAll(getAttributeNames(mbeanInfo, objectName));
            } catch (Exception e) {
                // log exception at debug level
                logger.debug(e.getMessage(), e);
            }
        }
        return attributeNames;
    }

    private Set getAttributeNames(MBeanInfo mbeanInfo, ObjectName objectName)
            throws Exception {
        List mbeanServers = lazyPlatformMBeanServer.findAllMBeanServers();
        Set attributeNames = Sets.newHashSet();
        for (MBeanAttributeInfo attribute : mbeanInfo.getAttributes()) {
            if (attribute.isReadable()) {
                try {
                    Object value = lazyPlatformMBeanServer.getAttribute(objectName,
                            attribute.getName(), mbeanServers);
                    addNumericAttributes(attribute, value, attributeNames);
                } catch (Exception e) {
                    // log exception at debug level
                    logger.debug(e.getMessage(), e);
                }
            }
        }
        return attributeNames;
    }

    private static void addNumericAttributes(MBeanAttributeInfo attribute, Object value,
            Set attributeNames) {
        String attributeType = attribute.getType();
        if (numericAttributeTypes.contains(attributeType)
                || attributeType.equals("java.lang.Object") && value instanceof Number) {
            attributeNames.add(attribute.getName());
        } else if (attributeType.equals("java.lang.String") && value instanceof String) {
            try {
                Double.parseDouble((String) value);
                attributeNames.add(attribute.getName());
            } catch (NumberFormatException e) {
                // log exception at debug level
                logger.debug(e.getMessage(), e);
            }
        } else if (attributeType.equals(CompositeData.class.getName())) {
            Object openType = attribute.getDescriptor().getFieldValue("openType");
            CompositeType compositeType = null;
            if (openType instanceof CompositeType) {
                compositeType = (CompositeType) openType;
            } else if (openType == null && value instanceof CompositeDataSupport) {
                compositeType = ((CompositeDataSupport) value).getCompositeType();
            }
            if (compositeType != null) {
                attributeNames
                        .addAll(getCompositeTypeAttributeNames(attribute, value, compositeType));
            }
        }
    }

    private static List getCompositeTypeAttributeNames(MBeanAttributeInfo attribute,
            Object compositeData, CompositeType compositeType) {
        List attributeNames = Lists.newArrayList();
        for (String itemName : compositeType.keySet()) {
            OpenType itemType = compositeType.getType(itemName);
            if (itemType == null) {
                continue;
            }
            String className = itemType.getClassName();
            Class clazz;
            try {
                clazz = Class.forName(className);
            } catch (ClassNotFoundException e) {
                logger.warn(e.getMessage(), e);
                continue;
            }
            if (Number.class.isAssignableFrom(clazz)) {
                attributeNames.add(attribute.getName() + '.' + itemName);
            } else if (clazz == String.class && compositeData instanceof CompositeData) {
                Object val = ((CompositeData) compositeData).get(itemName);
                if (val instanceof String) {
                    try {
                        Double.parseDouble((String) val);
                        attributeNames.add(attribute.getName() + '.' + itemName);
                    } catch (NumberFormatException e) {
                        // log exception at debug level
                        logger.debug(e.getMessage(), e);
                    }
                }
            }
        }
        return attributeNames;
    }

    private static Availability getThreadCpuTimeAvailability() {
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        if (!threadMXBean.isThreadCpuTimeSupported()) {
            return Availability.newBuilder()
                    .setAvailable(false)
                    .setReason("java.lang.management.ThreadMXBean"
                            + ".isThreadCpuTimeSupported() returned false")
                    .build();
        }
        if (!threadMXBean.isThreadCpuTimeEnabled()) {
            return Availability.newBuilder()
                    .setAvailable(false)
                    .setReason("java.lang.management.ThreadMXBean"
                            + ".isThreadCpuTimeEnabled() returned false")
                    .build();
        }
        return Availability.newBuilder().setAvailable(true).build();
    }

    private static Availability getThreadContentionAvailability() {
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        if (!threadMXBean.isThreadContentionMonitoringSupported()) {
            return Availability.newBuilder()
                    .setAvailable(false)
                    .setReason("java.lang.management.ThreadMXBean"
                            + ".isThreadContentionMonitoringSupported() returned false")
                    .build();
        }
        if (!threadMXBean.isThreadContentionMonitoringEnabled()) {
            return Availability.newBuilder()
                    .setAvailable(false)
                    .setReason("java.lang.management.ThreadMXBean"
                            + ".isThreadContentionMonitoringEnabled() returned false")
                    .build();
        }
        return Availability.newBuilder().setAvailable(true).build();
    }

    @SuppressWarnings("serial")
    private static class ObjectNameQueryExp implements QueryExp {

        private final String textUpper;

        private ObjectNameQueryExp(String text) {
            this.textUpper = text.toUpperCase(Locale.ENGLISH);
        }

        @Override
        public boolean apply(ObjectName name) {
            return apply(name.toString());
        }

        private boolean apply(String nameStr) {
            return nameStr.toUpperCase(Locale.ENGLISH).contains(textUpper);
        }

        @Override
        public void setMBeanServer(MBeanServer s) {}
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy