blob: 9656878f05ca2ef59efbc7b9ffeb554104add24c [file] [log] [blame]
/*
* 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.brooklyn.entity.java;
import static org.apache.brooklyn.util.JavaGroovyEquivalents.groovyTruth;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryUsage;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.management.openmbean.CompositeData;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.entity.EntityLocal;
import org.apache.brooklyn.core.config.render.RendererHints;
import org.apache.brooklyn.feed.http.HttpValueFunctions;
import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
import org.apache.brooklyn.feed.jmx.JmxFeed;
import org.apache.brooklyn.policy.enricher.RollingTimeWindowMeanEnricher;
import org.apache.brooklyn.policy.enricher.TimeFractionDeltaEnricher;
import org.apache.brooklyn.util.math.MathFunctions;
import org.apache.brooklyn.util.text.ByteSizeStrings;
import org.apache.brooklyn.util.time.Duration;
import org.apache.brooklyn.util.time.Time;
import com.google.common.base.Function;
public class JavaAppUtils {
public static boolean isEntityMxBeanStatsEnabled(Entity entity) {
return groovyTruth(entity.getConfig(UsesJavaMXBeans.MXBEAN_STATS_ENABLED));
}
/**
* @see #connectJavaAppServerPolicies(EntityLocal, Duration)
* @see #getMxBeanSensorsBuilder(EntityLocal)
*/
@Nullable
public static JmxFeed connectMXBeanSensors(EntityLocal entity) {
if (isEntityMxBeanStatsEnabled(entity)) {
return getMxBeanSensorsBuilder(entity).build();
} else {
return null;
}
}
/** @see #connectJavaAppServerPolicies(EntityLocal, Duration) */
@Nullable
public static JmxFeed connectMXBeanSensors(EntityLocal entity, long jmxPollPeriodMs) {
if (isEntityMxBeanStatsEnabled(entity)) {
return getMxBeanSensorsBuilder(entity, jmxPollPeriodMs).build();
} else {
return null;
}
}
/**
* @param entity The entity at which to poll
* @param jmxPollPeriod How often to poll
* @return A {@link JmxFeed} configured to poll the given entity at the given period,
* or null if the entity is not configured for MXBEAN_STATS
* @see org.apache.brooklyn.entity.java.UsesJavaMXBeans#MXBEAN_STATS_ENABLED
*/
@Nullable
public static JmxFeed connectMXBeanSensors(EntityLocal entity, Duration jmxPollPeriod) {
if (isEntityMxBeanStatsEnabled(entity)) {
return getMxBeanSensorsBuilder(entity, jmxPollPeriod).build();
} else {
return null;
}
}
public static void connectJavaAppServerPolicies(EntityLocal entity) {
connectJavaAppServerPolicies(entity, Duration.TEN_SECONDS);
}
public static void connectJavaAppServerPolicies(EntityLocal entity, Duration windowPeriod) {
entity.addEnricher(new TimeFractionDeltaEnricher<Double>(entity, UsesJavaMXBeans.PROCESS_CPU_TIME,
UsesJavaMXBeans.PROCESS_CPU_TIME_FRACTION_LAST, TimeUnit.MILLISECONDS));
entity.addEnricher(new RollingTimeWindowMeanEnricher<Double>(entity,
UsesJavaMXBeans.PROCESS_CPU_TIME_FRACTION_LAST, UsesJavaMXBeans.PROCESS_CPU_TIME_FRACTION_IN_WINDOW,
windowPeriod));
}
/**
* @param entity The entity at which to poll
* @return A {@link JmxFeed.Builder} configured to poll entity every ten seconds
* @see #getMxBeanSensorsBuilder(EntityLocal, Duration)
*/
@Nonnull
public static JmxFeed.Builder getMxBeanSensorsBuilder(EntityLocal entity) {
return getMxBeanSensorsBuilder(entity, Duration.TEN_SECONDS);
}
/** @see #getMxBeanSensorsBuilder(EntityLocal, Duration) */
@Nonnull
public static JmxFeed.Builder getMxBeanSensorsBuilder(EntityLocal entity, long jmxPollPeriod) {
return getMxBeanSensorsBuilder(entity, Duration.millis(jmxPollPeriod));
}
/**
* @param entity The entity at which to poll
* @param jmxPollPeriod How often to poll
* @return A {@link JmxFeed.Builder} configured to poll many interesting MXBeans
* at the given entity and to repeat according to the given poll period.
* <p/>
* If an entity does not have MXBean stats enabled (i.e. {@link UsesJavaMXBeans#MXBEAN_STATS_ENABLED} is
* configured to false) then returns a builder configured with entity and duration but no polls.
* <p/>
* Use {@link #connectMXBeanSensors(EntityLocal, Duration)} to create and build in one step.
*/
@Nonnull
@SuppressWarnings({"unchecked"})
public static JmxFeed.Builder getMxBeanSensorsBuilder(EntityLocal entity, Duration jmxPollPeriod) {
JmxFeed.Builder builder = JmxFeed.builder()
.entity(entity)
.period(jmxPollPeriod);
if (isEntityMxBeanStatsEnabled(entity)) {
// TODO Could we reuse the result of compositeDataToMemoryUsage?
builder
.pollAttribute(new JmxAttributePollConfig<Long>(UsesJavaMXBeans.USED_HEAP_MEMORY)
.objectName(ManagementFactory.MEMORY_MXBEAN_NAME)
.attributeName("HeapMemoryUsage")
.onSuccess((Function) HttpValueFunctions.chain(compositeDataToMemoryUsage(), new Function<MemoryUsage, Long>() {
@Override public Long apply(MemoryUsage input) {
return (input == null) ? null : input.getUsed();
}})))
.pollAttribute(new JmxAttributePollConfig<Long>(UsesJavaMXBeans.INIT_HEAP_MEMORY)
.objectName(ManagementFactory.MEMORY_MXBEAN_NAME)
.attributeName("HeapMemoryUsage")
.onSuccess((Function) HttpValueFunctions.chain(compositeDataToMemoryUsage(), new Function<MemoryUsage, Long>() {
@Override public Long apply(MemoryUsage input) {
return (input == null) ? null : input.getInit();
}})))
.pollAttribute(new JmxAttributePollConfig<Long>(UsesJavaMXBeans.COMMITTED_HEAP_MEMORY)
.objectName(ManagementFactory.MEMORY_MXBEAN_NAME)
.attributeName("HeapMemoryUsage")
.onSuccess((Function) HttpValueFunctions.chain(compositeDataToMemoryUsage(), new Function<MemoryUsage, Long>() {
@Override public Long apply(MemoryUsage input) {
return (input == null) ? null : input.getCommitted();
}})))
.pollAttribute(new JmxAttributePollConfig<Long>(UsesJavaMXBeans.MAX_HEAP_MEMORY)
.objectName(ManagementFactory.MEMORY_MXBEAN_NAME)
.attributeName("HeapMemoryUsage")
.onSuccess((Function) HttpValueFunctions.chain(compositeDataToMemoryUsage(), new Function<MemoryUsage, Long>() {
@Override public Long apply(MemoryUsage input) {
return (input == null) ? null : input.getMax();
}})))
.pollAttribute(new JmxAttributePollConfig<Long>(UsesJavaMXBeans.NON_HEAP_MEMORY_USAGE)
.objectName(ManagementFactory.MEMORY_MXBEAN_NAME)
.attributeName("NonHeapMemoryUsage")
.onSuccess((Function) HttpValueFunctions.chain(compositeDataToMemoryUsage(), new Function<MemoryUsage, Long>() {
@Override public Long apply(MemoryUsage input) {
return (input == null) ? null : input.getUsed();
}})))
.pollAttribute(new JmxAttributePollConfig<Integer>(UsesJavaMXBeans.CURRENT_THREAD_COUNT)
.objectName(ManagementFactory.THREAD_MXBEAN_NAME)
.attributeName("ThreadCount"))
.pollAttribute(new JmxAttributePollConfig<Integer>(UsesJavaMXBeans.PEAK_THREAD_COUNT)
.objectName(ManagementFactory.THREAD_MXBEAN_NAME)
.attributeName("PeakThreadCount"))
.pollAttribute(new JmxAttributePollConfig<Long>(UsesJavaMXBeans.START_TIME)
.objectName(ManagementFactory.RUNTIME_MXBEAN_NAME)
.period(60, TimeUnit.SECONDS)
.attributeName("StartTime"))
.pollAttribute(new JmxAttributePollConfig<Long>(UsesJavaMXBeans.UP_TIME)
.objectName(ManagementFactory.RUNTIME_MXBEAN_NAME)
.period(60, TimeUnit.SECONDS)
.attributeName("Uptime"))
.pollAttribute(new JmxAttributePollConfig<Double>(UsesJavaMXBeans.PROCESS_CPU_TIME)
.objectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME)
.attributeName("ProcessCpuTime")
.onSuccess((Function) MathFunctions.times(0.001*0.001))) // nanos to millis
.pollAttribute(new JmxAttributePollConfig<Double>(UsesJavaMXBeans.SYSTEM_LOAD_AVERAGE)
.objectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME)
.attributeName("SystemLoadAverage"))
.pollAttribute(new JmxAttributePollConfig<Integer>(UsesJavaMXBeans.AVAILABLE_PROCESSORS)
.objectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME)
.period(60, TimeUnit.SECONDS)
.attributeName("AvailableProcessors"))
.pollAttribute(new JmxAttributePollConfig<Long>(UsesJavaMXBeans.TOTAL_PHYSICAL_MEMORY_SIZE)
.objectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME)
.period(60, TimeUnit.SECONDS)
.attributeName("TotalPhysicalMemorySize"))
.pollAttribute(new JmxAttributePollConfig<Long>(UsesJavaMXBeans.FREE_PHYSICAL_MEMORY_SIZE)
.objectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME)
.period(60, TimeUnit.SECONDS)
.attributeName("FreePhysicalMemorySize"));
//FIXME: need a new type of adapter that maps multiple objectNames to a mapping
// jmxAdapter.objectName(ManagementFactory.GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",*").with {
// attribute("SystemLoadAverage").subscribe(UsesJavaMXBeans.GARBAGE_COLLECTION_TIME, { def m -> log.info("XXXXXXX $m") });
// }
}
return builder;
}
/** @deprecated Since 0.7.0. Use {@link org.apache.brooklyn.util.math.MathFunctions#times(double)} instead */
@Deprecated
public static Function<Number, Double> times(final double x) {
return MathFunctions.times(x);
}
public static Function<CompositeData, MemoryUsage> compositeDataToMemoryUsage() {
return new Function<CompositeData, MemoryUsage>() {
@Override public MemoryUsage apply(CompositeData input) {
return (input == null) ? null : MemoryUsage.from(input);
}
};
}
private static final AtomicBoolean initialized = new AtomicBoolean(false);
/** Setup renderer hints for the MXBean attributes. */
public static void init() {
if (initialized.get()) return;
synchronized (initialized) {
if (initialized.get()) return;
RendererHints.register(UsesJavaMXBeans.USED_HEAP_MEMORY, RendererHints.displayValue(ByteSizeStrings.metric()));
RendererHints.register(UsesJavaMXBeans.INIT_HEAP_MEMORY, RendererHints.displayValue(ByteSizeStrings.metric()));
RendererHints.register(UsesJavaMXBeans.MAX_HEAP_MEMORY, RendererHints.displayValue(ByteSizeStrings.metric()));
RendererHints.register(UsesJavaMXBeans.COMMITTED_HEAP_MEMORY, RendererHints.displayValue(ByteSizeStrings.metric()));
RendererHints.register(UsesJavaMXBeans.NON_HEAP_MEMORY_USAGE, RendererHints.displayValue(ByteSizeStrings.metric()));
RendererHints.register(UsesJavaMXBeans.TOTAL_PHYSICAL_MEMORY_SIZE, RendererHints.displayValue(ByteSizeStrings.metric()));
RendererHints.register(UsesJavaMXBeans.FREE_PHYSICAL_MEMORY_SIZE, RendererHints.displayValue(ByteSizeStrings.metric()));
RendererHints.register(UsesJavaMXBeans.START_TIME, RendererHints.displayValue(Time.toDateString()));
RendererHints.register(UsesJavaMXBeans.UP_TIME, RendererHints.displayValue(Duration.millisToStringRounded()));
RendererHints.register(UsesJavaMXBeans.PROCESS_CPU_TIME, RendererHints.displayValue(Duration.millisToStringRounded()));
RendererHints.register(UsesJavaMXBeans.PROCESS_CPU_TIME_FRACTION_LAST, RendererHints.displayValue(MathFunctions.percent(4)));
RendererHints.register(UsesJavaMXBeans.PROCESS_CPU_TIME_FRACTION_IN_WINDOW, RendererHints.displayValue(MathFunctions.percent(4)));
initialized.set(true);
}
}
static {
init();
}
}