You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2021/11/30 20:30:55 UTC

[camel] 04/10: CAMEL-15133: camel-health - Resolve health-checks from classpath and make it friendlier to provide custom health checks.

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 330346fbd9ea771d247f1dae6a039e64096fab6a
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Nov 30 15:00:27 2021 +0100

    CAMEL-15133: camel-health - Resolve health-checks from classpath and make it friendlier to provide custom health checks.
---
 .../apache/camel/health/HealthCheckRegistry.java   |  6 ++
 .../camel/impl/engine/AbstractCamelContext.java    | 16 +++++-
 .../FastAnnotationTypeConverterLoader.java         |  1 +
 .../impl/health/DefaultHealthCheckRegistry.java    | 23 ++++++++
 .../impl/health/DefaultHealthChecksLoader.java     | 65 ++++++++++++++++++++++
 5 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRegistry.java b/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRegistry.java
index c2b3523..9f28f33 100644
--- a/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRegistry.java
+++ b/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRegistry.java
@@ -115,4 +115,10 @@ public interface HealthCheckRegistry extends CamelContextAware, StaticService, I
      * Returns a sequential {@code Stream} with the known {@link HealthCheck} as its source.
      */
     Stream<HealthCheck> stream();
+
+    /**
+     * Loads custom health checks by scanning classpath.
+     */
+    void loadHealthChecks();
+
 }
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index e1a1498..0c3b44b 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -2737,7 +2737,19 @@ public abstract class AbstractCamelContext extends BaseService
 
         // ensure additional type converters is loaded
         if (loadTypeConverters && typeConverter instanceof AnnotationScanTypeConverters) {
+            StartupStep step2 = startupStepRecorder.beginStep(CamelContext.class, null, "Scan TypeConverters");
             ((AnnotationScanTypeConverters) typeConverter).scanTypeConverters();
+            startupStepRecorder.endStep(step2);
+        }
+
+        // ensure additional health checks is loaded
+        if (loadHealthChecks) {
+            StartupStep step3 = startupStepRecorder.beginStep(CamelContext.class, null, "Scan HealthChecks");
+            HealthCheckRegistry hcr = getExtension(HealthCheckRegistry.class);
+            if (hcr != null) {
+                hcr.loadHealthChecks();
+            }
+            startupStepRecorder.endStep(step3);
         }
 
         // custom properties may use property placeholders so resolve those
@@ -2821,7 +2833,7 @@ public abstract class AbstractCamelContext extends BaseService
 
         bindDataFormats();
 
-        // start components
+        // init components
         ServiceHelper.initService(components.values());
 
         // create route definitions from route templates if we have any sources
@@ -2881,7 +2893,7 @@ public abstract class AbstractCamelContext extends BaseService
     @Override
     protected void doStart() throws Exception {
         if (firstStartDone) {
-            // its not good practice to reset a camel context
+            // its not good practice resetting a camel context
             LOG.warn("Starting CamelContext: {} after the context has been stopped is not recommended", getName());
         }
         StartupStep step = startupStepRecorder.beginStep(CamelContext.class, getName(), "Start CamelContext");
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/converter/FastAnnotationTypeConverterLoader.java b/core/camel-base/src/main/java/org/apache/camel/impl/converter/FastAnnotationTypeConverterLoader.java
index 7614f73..6c08c48 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/converter/FastAnnotationTypeConverterLoader.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/converter/FastAnnotationTypeConverterLoader.java
@@ -19,6 +19,7 @@ package org.apache.camel.impl.converter;
 import org.apache.camel.Converter;
 import org.apache.camel.spi.PackageScanClassResolver;
 
+@Deprecated
 public final class FastAnnotationTypeConverterLoader extends AnnotationTypeConverterLoader {
 
     public FastAnnotationTypeConverterLoader(PackageScanClassResolver resolver) {
diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthCheckRegistry.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthCheckRegistry.java
index 7d2140b..3f23821 100644
--- a/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthCheckRegistry.java
+++ b/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthCheckRegistry.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.impl.health;
 
+import java.util.Collection;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArraySet;
@@ -31,6 +32,8 @@ import org.apache.camel.health.HealthCheckRepository;
 import org.apache.camel.health.HealthCheckResolver;
 import org.apache.camel.support.service.ServiceSupport;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StopWatch;
+import org.apache.camel.util.TimeUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -47,6 +50,7 @@ public class DefaultHealthCheckRegistry extends ServiceSupport implements Health
     private final Set<HealthCheckRepository> repositories;
     private CamelContext camelContext;
     private boolean enabled = true;
+    private volatile boolean loadHealthChecksDone;
 
     public DefaultHealthCheckRegistry() {
         this(null);
@@ -223,6 +227,25 @@ public class DefaultHealthCheckRegistry extends ServiceSupport implements Health
         return Stream.empty();
     }
 
+    @Override
+    public void loadHealthChecks() {
+        StopWatch watch = new StopWatch();
+
+        if (!loadHealthChecksDone) {
+            loadHealthChecksDone = true;
+
+            DefaultHealthChecksLoader loader = new DefaultHealthChecksLoader(
+                    camelContext.adapt(ExtendedCamelContext.class).getPackageScanResourceResolver());
+            Collection<HealthCheck> col = loader.loadHealthChecks();
+
+            // report how many health checks we have loaded
+            if (col.size() > 0) {
+                String time = TimeUtils.printDuration(watch.taken());
+                LOG.info("Health checks (scanned: {}) loaded in {}", col.size(), time);
+            }
+        }
+    }
+
     private void checkIfAccepted(Object obj) {
         boolean accept = obj instanceof HealthCheck || obj instanceof HealthCheckRepository;
         if (!accept) {
diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthChecksLoader.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthChecksLoader.java
new file mode 100644
index 0000000..750fd6e
--- /dev/null
+++ b/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthChecksLoader.java
@@ -0,0 +1,65 @@
+/*
+ * 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.camel.impl.health;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.camel.health.HealthCheck;
+import org.apache.camel.spi.PackageScanResourceResolver;
+import org.apache.camel.spi.Resource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * To load custom health-checks by classpath scanning.
+ */
+public class DefaultHealthChecksLoader {
+
+    public static final String META_INF_SERVICES = "META-INF/services/org/apache/camel/health-check";
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultHealthChecksLoader.class);
+    private static final Charset UTF8 = Charset.forName("UTF-8");
+
+    protected PackageScanResourceResolver resolver;
+    protected Set<Class<?>> visitedClasses = new HashSet<>();
+    protected Set<String> visitedURIs = new HashSet<>();
+
+    public DefaultHealthChecksLoader(PackageScanResourceResolver resolver) {
+        this.resolver = resolver;
+    }
+
+    public Collection<HealthCheck> loadHealthChecks() {
+        Collection<HealthCheck> answer = new ArrayList<>();
+
+        LOG.trace("Searching for {} health checks", META_INF_SERVICES);
+
+        try {
+            Collection<Resource> resources = resolver.findResources(META_INF_SERVICES + "/*-check");
+            for (Resource resource : resources) {
+                System.out.println(resource);
+            }
+        } catch (Exception e) {
+            // ignore
+        }
+
+        return answer;
+    }
+
+}