Author: ghenzler
Date: Fri Jan 4 14:48:42 2019
New Revision: 1850371
URL: http://svn.apache.org/viewvc?rev=1850371&view=rev
Log:
FELIX-6012 Introduce module "generalchecks" with basic general purpose checks
Added:
felix/trunk/healthcheck/generalchecks/
felix/trunk/healthcheck/generalchecks/bnd.bnd
felix/trunk/healthcheck/generalchecks/pom.xml (with props)
felix/trunk/healthcheck/generalchecks/src/
felix/trunk/healthcheck/generalchecks/src/main/
felix/trunk/healthcheck/generalchecks/src/main/java/
felix/trunk/healthcheck/generalchecks/src/main/java/org/
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/BundlesStartedCheck.java
(with props)
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/CpuCheck.java
(with props)
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/DiskSpaceCheck.java
(with props)
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/MemoryCheck.java
(with props)
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/ThreadUsageCheck.java
(with props)
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/util/
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/util/UnitsUtil.java
(with props)
felix/trunk/healthcheck/generalchecks/src/test/
felix/trunk/healthcheck/generalchecks/src/test/java/
felix/trunk/healthcheck/generalchecks/src/test/java/org/
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/util/
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/util/UnitsUtilTest.java
(with props)
Added: felix/trunk/healthcheck/generalchecks/bnd.bnd
URL:
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/bnd.bnd?rev=1850371&view=auto
==============================================================================
--- felix/trunk/healthcheck/generalchecks/bnd.bnd (added)
+++ felix/trunk/healthcheck/generalchecks/bnd.bnd Fri Jan 4 14:48:42 2019
@@ -0,0 +1,9 @@
+Bundle-Category: healthcheck
+
+Bundle-Description: ${project.description}
+
+Bundle-DocURL: https://felix.apache.org
+
+Bundle-License: Apache License, Version 2.0
+
+Bundle-Vendor: The Apache Software Foundation
Added: felix/trunk/healthcheck/generalchecks/pom.xml
URL:
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/pom.xml?rev=1850371&view=auto
==============================================================================
--- felix/trunk/healthcheck/generalchecks/pom.xml (added)
+++ felix/trunk/healthcheck/generalchecks/pom.xml Fri Jan 4 14:48:42 2019
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>6</version>
+ <relativePath/>
+ </parent>
+
+ <artifactId>org.apache.felix.healthcheck.generalchecks</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+
+ <name>Apache Felix Health Check :: General Checks</name>
+ <inceptionYear>2013</inceptionYear>
+
+ <description>
+ General purpose health checks that can be simply configured to check
for generic aspects like disk space, started bundles, remote service
availability, etc.
+ </description>
+
+ <scm>
+
<connection>scm:svn:http://svn.apache.org/repos/asf/felix/trunk/healthcheck/genericchecks</connection>
+
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/felix/trunk/healthcheck/genericchecks</developerConnection>
+ <url>http://svn.apache.org/viewvc/felix/trunk/http/genericchecks/</url>
+ </scm>
+
+ <build>
+ <plugins>
+
+ <plugin>
+ <groupId>biz.aQute.bnd</groupId>
+ <artifactId>bnd-maven-plugin</artifactId>
+ <version>4.1.0</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>bnd-process</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>biz.aQute.bnd</groupId>
+ <artifactId>bnd-baseline-maven-plugin</artifactId>
+ <version>4.1.0</version>
+ </plugin>
+
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>osgi.core</artifactId>
+ <version>6.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>osgi.cmpn</artifactId>
+ <version>6.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.healthcheck.api</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.healthcheck.annotation</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.7.6</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.4</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- START test scope dependencies -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ <!-- END test scope dependencies -->
+
+ </dependencies>
+</project>
Propchange: felix/trunk/healthcheck/generalchecks/pom.xml
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/BundlesStartedCheck.java
URL:
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/BundlesStartedCheck.java?rev=1850371&view=auto
==============================================================================
---
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/BundlesStartedCheck.java
(added)
+++
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/BundlesStartedCheck.java
Fri Jan 4 14:48:42 2019
@@ -0,0 +1,163 @@
+/*
+ * 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 SF 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.felix.hc.generalchecks;
+
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.felix.hc.annotation.HealthCheckService;
+import org.apache.felix.hc.api.HealthCheck;
+import org.apache.felix.hc.api.Result;
+import org.apache.felix.hc.util.FormattingResultLog;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@HealthCheckService(name = BundlesStartedCheck.HC_NAME)
+@Component(configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = BundlesStartedCheck.Config.class, factory = true)
+public class BundlesStartedCheck implements HealthCheck {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(BundlesStartedCheck.class);
+
+ public static final String HC_NAME = "Bundles Started";
+ public static final String HC_LABEL = "Health Check: " + HC_NAME;
+
+ @ObjectClassDefinition(name = HC_LABEL, description = "Checks the
configured path(s) against the given thresholds")
+ public @interface Config {
+ @AttributeDefinition(name = "Name", description = "Name of this health
check")
+ String hc_name() default HC_NAME;
+
+ @AttributeDefinition(name = "Tags", description = "List of tags for
this health check, used to select subsets of health checks for execution e.g.
by a composite health check.")
+ String[] hc_tags() default {};
+
+ @AttributeDefinition(name = "Includes RegEx", description = "RegEx to
select all relevant bundles for this check")
+ String includesRegex() default ".*";
+
+ @AttributeDefinition(name = "Excludes RegEx", description = "Optional
RegEx to exclude bundles from this check")
+ String excludesRegex() default "";
+
+ @AttributeDefinition(name = "CRITICAL for inactive bundles",
description = "By default inactive bundles produce warnings, if this is set to
true inactive bundles produce a CRITICAL result")
+ boolean useCriticalForInactive() default false;
+
+ @AttributeDefinition
+ String webconsole_configurationFactory_nameHint() default "Bundles
started includes: {includesRegex} excludes: {excludesRegex}";
+ }
+
+ private BundleContext bundleContext;
+ private Pattern includesRegex;
+ private Pattern excludesRegex;
+ boolean useCriticalForInactive;
+
+ @Activate
+ protected void activate(BundleContext bundleContext, Config config) {
+ this.bundleContext = bundleContext;
+ this.includesRegex = Pattern.compile(config.includesRegex());
+ this.excludesRegex = StringUtils.isNotBlank(config.excludesRegex()) ?
Pattern.compile(config.excludesRegex()) : null;
+ this.useCriticalForInactive = config.useCriticalForInactive();
+ LOG.info("Activated bundles started HC for includesRegex={}
excludesRegex={}% useCriticalForInactive={}", includesRegex, excludesRegex,
useCriticalForInactive);
+ }
+
+
+ @Override
+ public Result execute() {
+ FormattingResultLog log = new FormattingResultLog();
+
+ Bundle[] bundles = this.bundleContext.getBundles();
+ log.debug("Framwork has {} bundles in total", bundles.length);
+
+ int countExcluded = 0;
+ int relevantBundlesCount = 0;
+ int inctiveCount = 0;
+ for (Bundle bundle : bundles) {
+ String bundleSymbolicName = bundle.getSymbolicName();
+ int bundleState = bundle.getState();
+
+ if(!includesRegex.matcher(bundleSymbolicName).matches()) {
+ LOG.debug("Bundle {} not matched by {}", bundleSymbolicName,
includesRegex);
+ continue;
+ }
+
+ if(excludesRegex!=null &&
excludesRegex.matcher(bundleSymbolicName).matches()) {
+ LOG.debug("Bundle {} excluded {}", bundleSymbolicName,
excludesRegex);
+ countExcluded ++;
+ continue;
+ }
+ relevantBundlesCount++;
+
+ boolean bundleIsLogged = false;
+ if (bundleState != Bundle.ACTIVE) {
+ // support lazy activation
(https://www.osgi.org/developer/design/lazy-start/)
+ if (bundleState == Bundle.STARTING &&
isLazyActivation(bundle)) {
+ LOG.debug("Ignoring lazily activated bundle {}",
bundleSymbolicName);
+ } else if (StringUtils.isNotBlank((String)
bundle.getHeaders().get(Constants.FRAGMENT_HOST))) {
+ LOG.debug("Ignoring bundle fragment: {}",
bundleSymbolicName);
+ } else {
+ String msg = "Inactive bundle {} {}: {}";
+ Object[] msgObjs = new Object[] {bundle.getBundleId(),
bundleSymbolicName, getStateLabel(bundleState)};
+ LOG.debug(msg, msgObjs);
+ if(useCriticalForInactive) {
+ log.critical(msg, msgObjs);
+ } else {
+ log.warn(msg, msgObjs);
+ }
+ bundleIsLogged = true;
+ inctiveCount++;
+ }
+ }
+ if(!bundleIsLogged) {
+ log.debug("Bundle {} {}: {}", bundle.getBundleId(),
bundleSymbolicName, getStateLabel(bundleState));
+ }
+ }
+
+ String baseMsg = relevantBundlesCount+"
bundles"+(!includesRegex.pattern().equals(".*")?" for pattern
"+includesRegex.pattern(): "");
+ String excludedMsg = countExcluded > 0 ? " (" + countExcluded + "
excluded via pattern "+excludesRegex.pattern()+")" : "";
+ if (inctiveCount > 0) {
+ log.info("Found "+inctiveCount + " inactive of "+baseMsg +
excludedMsg);
+ } else {
+ log.info("All "+baseMsg+" are started" + excludedMsg);
+ }
+
+ return new Result(log);
+ }
+
+ private static boolean isLazyActivation(Bundle b) {
+ return
Constants.ACTIVATION_LAZY.equals(b.getHeaders().get(Constants.BUNDLE_ACTIVATIONPOLICY));
+ }
+
+ private static String getStateLabel(int state) {
+ switch(state) {
+ case Bundle.UNINSTALLED: return "UNINSTALLED";
+ case Bundle.INSTALLED: return "INSTALLED";
+ case Bundle.RESOLVED: return "RESOLVED";
+ case Bundle.STARTING: return "STARTING";
+ case Bundle.STOPPING: return "STOPPING";
+ case Bundle.ACTIVE: return "ACTIVE";
+ default: return ""+state;
+ }
+ }
+
+}
Propchange:
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/BundlesStartedCheck.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/CpuCheck.java
URL:
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/CpuCheck.java?rev=1850371&view=auto
==============================================================================
---
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/CpuCheck.java
(added)
+++
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/CpuCheck.java
Fri Jan 4 14:48:42 2019
@@ -0,0 +1,118 @@
+/*
+ * 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 SF 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.felix.hc.generalchecks;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+
+import org.apache.felix.hc.annotation.HealthCheckService;
+import org.apache.felix.hc.api.HealthCheck;
+import org.apache.felix.hc.api.Result;
+import org.apache.felix.hc.api.ResultLog;
+import org.apache.felix.hc.util.FormattingResultLog;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@HealthCheckService(name = CpuCheck.HC_NAME)
+@Component(configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = CpuCheck.Config.class, factory = false)
+public class CpuCheck implements HealthCheck {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CpuCheck.class);
+
+ public static final String HC_NAME = "CPU";
+ public static final String HC_LABEL = "Health Check: " + HC_NAME;
+
+ @ObjectClassDefinition(name = HC_LABEL, description = "Checks for high CPU
load")
+ public @interface Config {
+ @AttributeDefinition(name = "Name", description = "Name of this health
check")
+ String hc_name() default HC_NAME;
+
+ @AttributeDefinition(name = "Tags", description = "List of tags for
this health check, used to select subsets of health checks for execution e.g.
by a composite health check.")
+ String[] hc_tags() default {};
+
+ @AttributeDefinition(name = "Disk used threshold for WARN",
description = "in percent, if disk usage is over this limit the result is WARN")
+ long cpuPercentageThresholdWarn() default 95;
+
+ }
+
+ private long cpuPercentageThresholdWarn;
+
+ @Activate
+ protected void activate(final Config config) {
+ cpuPercentageThresholdWarn = config.cpuPercentageThresholdWarn();
+ LOG.info("Activated CPU HC: cpuPercentageThresholdWarn={}%",
cpuPercentageThresholdWarn);
+ }
+
+ @Override
+ public Result execute() {
+
+ FormattingResultLog log = new FormattingResultLog();
+
+ double processCpuLoad = Double.NaN;
+ try {
+ processCpuLoad = getProcessCpuLoad();
+ } catch (Exception e) {
+ log.add(new ResultLog.Entry(Result.Status.HEALTH_CHECK_ERROR,
"Could not get process CPU load: " + e, e));
+ }
+
+ if (Double.isNaN(processCpuLoad)) {
+ log.info("No CPU load available yet");
+ } else {
+ String loadStr = String.format("%.1f", processCpuLoad);
+ Result.Status status = processCpuLoad < cpuPercentageThresholdWarn
? Result.Status.OK : Result.Status.WARN;
+ log.add(new ResultLog.Entry(status, "Process CPU Usage: " +
loadStr + "%"));
+ }
+ return new Result(log);
+
+ }
+
+ public double getProcessCpuLoad() throws MalformedObjectNameException,
ReflectionException, InstanceNotFoundException {
+
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ ObjectName name =
ObjectName.getInstance("java.lang:type=OperatingSystem");
+ AttributeList list = mbs.getAttributes(name, new String[] {
"ProcessCpuLoad" });
+
+ if (list.isEmpty()) {
+ return Double.NaN;
+ }
+
+ Attribute att = (Attribute) list.get(0);
+ Double value = (Double) att.getValue();
+
+ if (value == -1.0) {
+ return Double.NaN;
+ }
+
+ return value * 100;
+ }
+
+}
Propchange:
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/CpuCheck.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/DiskSpaceCheck.java
URL:
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/DiskSpaceCheck.java?rev=1850371&view=auto
==============================================================================
---
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/DiskSpaceCheck.java
(added)
+++
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/DiskSpaceCheck.java
Fri Jan 4 14:48:42 2019
@@ -0,0 +1,123 @@
+/*
+ * 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 SF 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.felix.hc.generalchecks;
+
+import static org.apache.felix.hc.generalchecks.util.UnitsUtil.formatBytes;
+
+import java.io.File;
+import java.util.Arrays;
+
+import org.apache.felix.hc.annotation.HealthCheckService;
+import org.apache.felix.hc.api.HealthCheck;
+import org.apache.felix.hc.api.Result;
+import org.apache.felix.hc.api.ResultLog;
+import org.apache.felix.hc.util.FormattingResultLog;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@HealthCheckService(name = DiskSpaceCheck.HC_NAME)
+@Component(configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = DiskSpaceCheck.Config.class, factory = true)
+public class DiskSpaceCheck implements HealthCheck {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(DiskSpaceCheck.class);
+
+ public static final String HC_NAME = "Disk Space";
+ public static final String HC_LABEL = "Health Check: " + HC_NAME;
+
+ @ObjectClassDefinition(name = HC_LABEL, description = "Checks the
configured path(s) against the given thresholds")
+ public @interface Config {
+ @AttributeDefinition(name = "Name", description = "Name of this health
check")
+ String hc_name() default HC_NAME;
+
+ @AttributeDefinition(name = "Tags", description = "List of tags for
this health check, used to select subsets of health checks for execution e.g.
by a composite health check.")
+ String[] hc_tags() default {};
+
+ @AttributeDefinition(name = "Disk used threshold for WARN",
description = "in percent, if disk usage is over this limit the result is WARN")
+ long diskUsedThresholdWarn() default 90;
+
+ @AttributeDefinition(name = "Disk used threshold for CRITICAL",
description = "in percent, if disk usage is over this limit the result is
CRITICAL")
+ long diskUsedThresholdCritical() default 97;
+
+ @AttributeDefinition(name = "Paths to check for disk usage",
description = "Paths that is checked for free space according the configured
thresholds")
+ String[] diskPaths() default { "." };
+
+ @AttributeDefinition
+ String webconsole_configurationFactory_nameHint() default "{hc.name}:
{diskPaths} used>{diskUsedThresholdWarn}% -> WARN
used>{diskUsedThresholdCritical}% -> CRITICAL";
+ }
+
+ private long diskUsedThresholdWarn;
+ private long diskUsedThresholdCritical;
+ private String[] diskPaths;
+
+ @Activate
+ protected void activate(final Config config) {
+ diskUsedThresholdWarn = config.diskUsedThresholdWarn();
+ diskUsedThresholdCritical = config.diskUsedThresholdCritical();
+ diskPaths = config.diskPaths();
+
+ LOG.info("Activated disk usage HC for path(s) {}
diskUsedThresholdWarn={}% diskUsedThresholdCritical={}%",
Arrays.asList(diskPaths),
+ diskUsedThresholdWarn, diskUsedThresholdCritical);
+ }
+
+ @Override
+ public Result execute() {
+
+ FormattingResultLog log = new FormattingResultLog();
+
+ for (String diskPath : diskPaths) {
+
+ File diskPathFile = new File(diskPath);
+
+ if (!diskPathFile.exists()) {
+ log.warn("Directory '{}' does not exist", diskPathFile);
+ continue;
+ } else if (!diskPathFile.isDirectory()) {
+ log.warn("Directory '{}' is not a directory", diskPathFile);
+ continue;
+ }
+
+ double total = diskPathFile.getTotalSpace();
+ double free = diskPathFile.getUsableSpace();
+ double usedPercentage = (total - free) / total * 100d;
+
+ String totalStr = formatBytes(total);
+ String freeStr = formatBytes(free);
+ String msg = String.format("Disk Usage %s: %.1f%% of %s used / %s
free", diskPathFile.getAbsolutePath(),
+ usedPercentage,
+ totalStr, freeStr);
+
+ Result.Status status = usedPercentage >
this.diskUsedThresholdCritical ? Result.Status.CRITICAL
+ : usedPercentage > this.diskUsedThresholdWarn ?
Result.Status.WARN
+ : Result.Status.OK;
+
+ log.add(new ResultLog.Entry(status, msg));
+
+ }
+
+ return new Result(log);
+ }
+
+
+}
Propchange:
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/DiskSpaceCheck.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/MemoryCheck.java
URL:
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/MemoryCheck.java?rev=1850371&view=auto
==============================================================================
---
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/MemoryCheck.java
(added)
+++
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/MemoryCheck.java
Fri Jan 4 14:48:42 2019
@@ -0,0 +1,99 @@
+/*
+ * 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 SF 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.felix.hc.generalchecks;
+
+import static org.apache.felix.hc.generalchecks.util.UnitsUtil.formatBytes;
+
+import org.apache.felix.hc.annotation.HealthCheckService;
+import org.apache.felix.hc.api.HealthCheck;
+import org.apache.felix.hc.api.Result;
+import org.apache.felix.hc.api.ResultLog.Entry;
+import org.apache.felix.hc.util.FormattingResultLog;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@HealthCheckService(name = MemoryCheck.HC_NAME)
+@Component(configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = MemoryCheck.Config.class, factory = false)
+public class MemoryCheck implements HealthCheck {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(MemoryCheck.class);
+
+ public static final String HC_NAME = "Memory";
+ public static final String HC_LABEL = "Health Check: " + HC_NAME;
+
+ @ObjectClassDefinition(name = HC_LABEL, description = "Checks for high CPU
load")
+ public @interface Config {
+ @AttributeDefinition(name = "Name", description = "Name of this health
check")
+ String hc_name() default HC_NAME;
+
+ @AttributeDefinition(name = "Tags", description = "List of tags for
this health check, used to select subsets of health checks for execution e.g.
by a composite health check.")
+ String[] hc_tags() default {};
+
+ @AttributeDefinition(name = "Heap used threshold for WARN",
description = "in percent, if heap usage is over this limit the result is WARN")
+ long heapUsedPercentageThresholdWarn() default 90;
+
+ @AttributeDefinition(name = "Heap used threshold for CRITICAL",
description = "in percent, if heap usage is over this limit the result is
CRITICAL")
+ long heapUsedPercentageThresholdCritical() default 99;
+ }
+
+ private long heapUsedPercentageThresholdWarn;
+ private long heapUsedPercentageThresholdCritical;
+
+ @Activate
+ protected void activate(final Config config) {
+ heapUsedPercentageThresholdWarn =
config.heapUsedPercentageThresholdWarn();
+ heapUsedPercentageThresholdCritical =
config.heapUsedPercentageThresholdCritical();
+ LOG.info("Activated Memory HC: heapUsedPercentageThresholdWarn={}%
heapUsedPercentageThresholdCritical={}%", heapUsedPercentageThresholdWarn,
heapUsedPercentageThresholdCritical);
+ }
+
+ @Override
+ public Result execute() {
+ FormattingResultLog log = new FormattingResultLog();
+
+ Runtime runtime = Runtime.getRuntime();
+
+ long freeMemory = runtime.freeMemory();
+ log.debug("Free memory: {}", formatBytes(freeMemory));
+ long currentlyAllocatedByJVM = runtime.totalMemory();
+ log.debug("Currently allocated memory: {}",
formatBytes(currentlyAllocatedByJVM));
+ long usedMemory = currentlyAllocatedByJVM - freeMemory;
+ log.debug("Used memory: {}", formatBytes(usedMemory));
+ long maxMemoryAvailableToJVM = runtime.maxMemory();
+
+ double memoryUsedPercentage = ((double) usedMemory /
maxMemoryAvailableToJVM * 100d);
+
+ Result.Status status =
+ memoryUsedPercentage < this.heapUsedPercentageThresholdWarn ?
Result.Status.OK :
+ memoryUsedPercentage <
this.heapUsedPercentageThresholdCritical ? Result.Status.WARN
+ : Result.Status.CRITICAL;
+
+ String message = String.format("Memory Usage: %.1f%% of %s maximal
heap used", memoryUsedPercentage, formatBytes(maxMemoryAvailableToJVM));
+
+ log.add(new Entry(status, message));
+
+ return new Result(log);
+ }
+
+}
Propchange:
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/MemoryCheck.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/ThreadUsageCheck.java
URL:
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/ThreadUsageCheck.java?rev=1850371&view=auto
==============================================================================
---
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/ThreadUsageCheck.java
(added)
+++
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/ThreadUsageCheck.java
Fri Jan 4 14:48:42 2019
@@ -0,0 +1,198 @@
+/*
+ * 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 SF 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.felix.hc.generalchecks;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.hc.annotation.HealthCheckService;
+import org.apache.felix.hc.api.HealthCheck;
+import org.apache.felix.hc.api.Result;
+import org.apache.felix.hc.api.ResultLog;
+import org.apache.felix.hc.util.FormattingResultLog;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@HealthCheckService(name = ThreadUsageCheck.HC_NAME)
+@Component(configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = ThreadUsageCheck.Config.class, factory = false)
+public class ThreadUsageCheck implements HealthCheck {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(ThreadUsageCheck.class);
+
+ public static final String HC_NAME = "Thread Usage";
+ public static final String HC_LABEL = "Health Check: " + HC_NAME;
+
+ @ObjectClassDefinition(name = HC_LABEL, description = "Checks for thread
usage and deadlocks")
+ public @interface Config {
+ @AttributeDefinition(name = "Name", description = "Name of this health
check")
+ String hc_name() default HC_NAME;
+
+ @AttributeDefinition(name = "Tags", description = "List of tags for
this health check, used to select subsets of health checks for execution e.g.
by a composite health check.")
+ String[] hc_tags() default {};
+
+ @AttributeDefinition(name = "Sample Period", description = "Period to
measure usage per thread")
+ long samplePeriodInMs() default 200;
+
+ @AttributeDefinition(name = "CPU Time Threshold for WARN in %",
description = "Will WARN once this threshold is reached in average for all
threads. This value is multiplied by number of available cores as reported by
Runtime.getRuntime().availableProcessors()")
+ long cpuPercentageThresholdWarn() default 95;
+
+ }
+
+ private long samplePeriodInMs;
+
+ private long cpuPercentageThresholdWarn;
+
+ @Activate
+ protected final void activate(Config config) {
+ this.samplePeriodInMs = config.samplePeriodInMs();
+ this.cpuPercentageThresholdWarn = config.cpuPercentageThresholdWarn();
+ LOG.info("Activated thread usage HC samplePeriodInMs={}ms
cpuPercentageThresholdWarn={}%", samplePeriodInMs, cpuPercentageThresholdWarn);
+ }
+
+ @Override
+ public Result execute() {
+ FormattingResultLog log = new FormattingResultLog();
+
+ log.debug("Checking threads for exceeding {}% CPU time within time
period of {}ms", cpuPercentageThresholdWarn, samplePeriodInMs);
+
+ try {
+ ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();
+
+ List<ThreadTimeInfo> threadTimeInfos = collectThreadTimeInfos(log,
threadMxBean);
+
+ Collections.sort(threadTimeInfos);
+
+ float totalCpuTimePercentage = 0;
+ for (int i = 0; i < threadTimeInfos.size(); i++) {
+
+ ThreadTimeInfo threadInfo = threadTimeInfos.get(i);
+ float cpuTimePercentage = ((float) threadInfo.getCpuTime() /
((float) samplePeriodInMs * 1000000)) * 100f;
+ totalCpuTimePercentage += cpuTimePercentage;
+
+ String msg = String.format("%4.1f", cpuTimePercentage) + "%
used by thread \"" + threadInfo.name + "\"";
+
+ // usually just shows the 3 busiest threads. For the case more
threads take more than 15% CPU time, up to 10 threads are shown.
+ // use hcDebug=true to show all threads
+ if (i < 3 || (i < 10 && cpuTimePercentage > 15)) {
+ log.info(msg);
+ } else {
+ log.debug(msg);
+ }
+ }
+
+ int availableProcessors =
Runtime.getRuntime().availableProcessors();
+ boolean isHighCpuTime = totalCpuTimePercentage >
(cpuPercentageThresholdWarn * availableProcessors);
+ Result.Status status = isHighCpuTime ? Result.Status.WARN :
Result.Status.OK;
+
+ double cpuTimePerProcessor = totalCpuTimePercentage /
availableProcessors;
+ String msg = threadTimeInfos.size() + " threads using " +
String.format("%.1f", totalCpuTimePercentage) + "% CPU Time ("
+ + String.format("%.1f", cpuTimePerProcessor) + "% per
single core having " + availableProcessors + " cores)";
+ if (isHighCpuTime) {
+ msg += ">" + cpuPercentageThresholdWarn + "% threshold for
WARN";
+ }
+ log.add(new ResultLog.Entry(status, msg));
+
+ checkForDeadlock(log, threadMxBean);
+
+ } catch (Exception e) {
+ LOG.error("Could not analyse thread usage " + e, e);
+ log.healthCheckError("Could not analyse thread usage", e);
+ }
+
+ return new Result(log);
+
+ }
+
+ List<ThreadTimeInfo> collectThreadTimeInfos(FormattingResultLog log,
ThreadMXBean threadMxBean) {
+
+ Map<Long, ThreadTimeInfo> threadTimeInfos = new HashMap<Long,
ThreadTimeInfo>();
+
+ long[] allThreadIds = threadMxBean.getAllThreadIds();
+ for (long threadId : allThreadIds) {
+ ThreadTimeInfo threadTimeInfo = new ThreadTimeInfo();
+ long threadCpuTimeStart = threadMxBean.getThreadCpuTime(threadId);
+ threadTimeInfo.start = threadCpuTimeStart;
+ ThreadInfo threadInfo = threadMxBean.getThreadInfo(threadId);
+ threadTimeInfo.name = threadInfo != null ?
threadInfo.getThreadName() : "Thread id " + threadId + " (name not resolvable)";
+ threadTimeInfos.put(threadId, threadTimeInfo);
+ }
+
+ try {
+ Thread.sleep(samplePeriodInMs);
+ } catch (InterruptedException e) {
+ log.warn("Could not sleep configured samplePeriodInMs={} to gather
thread load", samplePeriodInMs);
+ }
+
+ for (long threadId : allThreadIds) {
+ ThreadTimeInfo threadTimeInfo = threadTimeInfos.get(threadId);
+ if (threadTimeInfo == null) {
+ continue;
+ }
+ long threadCpuTimeStop = threadMxBean.getThreadCpuTime(threadId);
+ threadTimeInfo.stop = threadCpuTimeStop;
+ }
+
+ List<ThreadTimeInfo> threads = new
ArrayList<ThreadTimeInfo>(threadTimeInfos.values());
+
+ return threads;
+ }
+
+ void checkForDeadlock(FormattingResultLog log, ThreadMXBean threadMxBean) {
+ long[] findDeadlockedThreads = threadMxBean.findDeadlockedThreads();
+ if (findDeadlockedThreads != null) {
+ for (long threadId : findDeadlockedThreads) {
+ log.critical("Thread " +
threadMxBean.getThreadInfo(threadId).getThreadName() + " is DEADLOCKED");
+ }
+ }
+ }
+
+ static class ThreadTimeInfo implements Comparable<ThreadTimeInfo> {
+ long start;
+ long stop;
+ String name;
+
+ long getCpuTime() {
+ long cpuTime = stop - start;
+ if (cpuTime < 0) {
+ cpuTime = 0;
+ }
+ return cpuTime;
+ }
+
+ @Override
+ public int compareTo(ThreadTimeInfo otherThreadTimeInfo) {
+ if (otherThreadTimeInfo == null) {
+ return -1;
+ }
+ return (int) (otherThreadTimeInfo.getCpuTime() -
this.getCpuTime());
+ }
+ }
+}
Propchange:
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/ThreadUsageCheck.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/util/UnitsUtil.java
URL:
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/util/UnitsUtil.java?rev=1850371&view=auto
==============================================================================
---
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/util/UnitsUtil.java
(added)
+++
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/util/UnitsUtil.java
Fri Jan 4 14:48:42 2019
@@ -0,0 +1,41 @@
+/*
+ * 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 SF 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.felix.hc.generalchecks.util;
+
+public class UnitsUtil {
+
+ private static final String SIZES[] = { "kB", "MB", "GB", "TB" };
+
+ public static String formatBytes(double size) {
+ double step = 1024, current = step;
+
+ int i;
+ for (i = 0; i < SIZES.length - 1; ++i) {
+ if (size < current * step) {
+ break;
+ }
+ current *= step;
+ }
+
+ String unit = SIZES[i];
+ double value = size / current;
+ String retVal = String.format("%.1f", value) + unit;
+ return retVal;
+ }
+
+}
Propchange:
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/util/UnitsUtil.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/util/UnitsUtilTest.java
URL:
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/util/UnitsUtilTest.java?rev=1850371&view=auto
==============================================================================
---
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/util/UnitsUtilTest.java
(added)
+++
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/util/UnitsUtilTest.java
Fri Jan 4 14:48:42 2019
@@ -0,0 +1,33 @@
+/*
+ * 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 SF 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.felix.hc.generalchecks.util;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class UnitsUtilTest {
+
+ @Test
+ public void testFormatBytes() {
+ assertEquals("5.0MB", UnitsUtil.formatBytes(5d*1024*1024));
+ assertEquals("2.0GB", UnitsUtil.formatBytes(2d*1024*1024*1024));
+ assertEquals("706.1kB", UnitsUtil.formatBytes(722998));
+ }
+
+}
Propchange:
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/util/UnitsUtilTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain