nicolaferraro closed pull request #140: Use properties to configure components
and logging
URL: https://github.com/apache/camel-k/pull/140
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/README.adoc b/README.adoc
index 085ee5a..20ad199 100644
--- a/README.adoc
+++ b/README.adoc
@@ -46,6 +46,37 @@ kamel run runtime/examples/Sample.java
A "Sample.java" file is included in the
link:/runtime/examples[/runtime/examples] folder of this repository. You can
change the content of the file and execute the command again to see the changes.
+==== Configure Integration properties
+
+Properties associated to an integration can be configured either using a
ConfigMap/Secret or by setting using the "--property" flag, i.e.
+
+```
+kamel run --property my.message=test runtime/examples/props.js
+```
+
+==== Configure Integration Logging
+
+camel-k runtime uses log4j2 as logging framework and can be configured through
integration properties.
+If you need to change the logging level of various loggers, you can do so by
using the `logging.level` prefix:
+
+```
+logging.level.org.apache.camel = DEBUG
+```
+
+==== Configure Integration Components
+
+camel-k component can be configured programmatically inside an integration or
using properties with the following syntax.
+
+```
+camel.component.${scheme}.${property} = ${value}
+```
+
+As example if you want to change the queue size of the seda component, you can
use the following property:
+
+```
+camel.component.seda.queueSize = 10
+```
+
=== Running Integrations in "Dev" Mode for Fast Feedback
If you want to iterate quickly on a integration to have fast feedback on the
code you're writing, you can use run it in **"dev" mode**:
diff --git a/pkg/util/maven/maven_project.go b/pkg/util/maven/maven_project.go
index 95cf928..2a04968 100644
--- a/pkg/util/maven/maven_project.go
+++ b/pkg/util/maven/maven_project.go
@@ -49,6 +49,13 @@ type Dependencies struct {
// Add a dependency to maven's dependencies
func (deps *Dependencies) Add(dep Dependency) {
+ for _, d := range deps.Dependencies {
+ // Check if the given dependency is already included in the
dependency list
+ if d == dep {
+ return
+ }
+ }
+
deps.Dependencies = append(deps.Dependencies, dep)
}
diff --git a/runtime/jvm/pom.xml b/runtime/jvm/pom.xml
index 9dc3918..6251e75 100644
--- a/runtime/jvm/pom.xml
+++ b/runtime/jvm/pom.xml
@@ -32,6 +32,11 @@
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ <version>${log4j2.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java
b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java
index acb25f3..6ec328b 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java
@@ -16,28 +16,46 @@
*/
package org.apache.camel.k.jvm;
-import java.io.IOException;
-import java.nio.file.FileVisitResult;
-import java.nio.file.FileVisitor;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
+import java.util.Properties;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.main.Main;
+import org.apache.camel.main.MainListenerSupport;
+import org.apache.camel.support.LifecycleStrategySupport;
+import org.apache.camel.util.IntrospectionSupport;
import org.apache.camel.util.ObjectHelper;
-import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Application {
private static final Logger LOGGER =
LoggerFactory.getLogger(Application.class);
+ static {
+ //
+ // Load properties as system properties so they are accessible through
+ // camel's properties component as well as for runtime configuration.
+ //
+ RuntimeSupport.configureSystemProperties();
+
+ //
+ // Configure the logging subsystem log4j2 using a subset of spring boot
+ // conventions:
+ //
+ // logging.level.${nane} = OFF|FATAL|ERROR|WARN|INFO|DEBUG|TRACE|ALL
+ //
+ // We now support setting the logging level only
+ //
+ RuntimeSupport.configureLogging();
+ }
+
+ // *******************************
+ //
+ // Main
+ //
+ // *******************************
+
public static void main(String[] args) throws Exception {
final String resource =
System.getenv(Constants.ENV_CAMEL_K_ROUTES_URI);
final String language =
System.getenv(Constants.ENV_CAMEL_K_ROUTES_LANGUAGE);
@@ -46,7 +64,6 @@ public static void main(String[] args) throws Exception {
throw new IllegalStateException("No valid resource found in " +
Constants.ENV_CAMEL_K_ROUTES_URI + " environment variable");
}
- String locations = computePropertyPlaceholderLocations();
RoutesLoader loader = RoutesLoaders.loaderFor(resource, language);
RouteBuilder routes = loader.load(resource);
@@ -56,59 +73,55 @@ public static void main(String[] args) throws Exception {
LOGGER.info("Routes: {}", resource);
LOGGER.info("Language: {}", language);
- LOGGER.info("Locations: {}", locations);
Main main = new Main();
-
- if (ObjectHelper.isNotEmpty(locations)) {
- main.setPropertyPlaceholderLocations(locations);
- }
-
+ main.addMainListener(new ComponentPropertiesBinder());
main.addRouteBuilder(routes);
main.run();
}
// *******************************
//
- // helpers
+ // Listeners
//
// *******************************
- private static String computePropertyPlaceholderLocations() throws
IOException {
- final String conf = System.getenv(Constants.ENV_CAMEL_K_CONF);
- final String confd = System.getenv(Constants.ENV_CAMEL_K_CONF_D);
- final List<String> locations = new ArrayList<>();
-
- // Main location
- if (ObjectHelper.isNotEmpty(conf)) {
- locations.add("file:" + conf);
- }
-
- // Additional locations
- if (ObjectHelper.isNotEmpty(confd)) {
- Path root = Paths.get(confd);
- FileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
+ static class ComponentPropertiesBinder extends MainListenerSupport {
+ @Override
+ public void configure(CamelContext context) {
+ context.addLifecycleStrategy(new LifecycleStrategySupport() {
+ @SuppressWarnings("unchecked")
@Override
- public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
- Objects.requireNonNull(file);
- Objects.requireNonNull(attrs);
-
- String path = file.toFile().getAbsolutePath();
- String ext = FilenameUtils.getExtension(path);
-
- if (Objects.equals("properties", ext)) {
- locations.add("file:" + path);
- }
-
- return FileVisitResult.CONTINUE;
+ public void onComponentAdd(String name, Component component) {
+ // Integration properties are defined as system properties
+ final Properties properties = System.getProperties();
+
+ // Set the prefix used by setProperties to filter
+ // and apply properties to match the one used by
+ // camel spring boot:
+ //
+ // camel.component.${scheme}.${value}
+ //
+ final String prefix = "camel.component." + name + ".";
+
+ properties.entrySet().stream()
+ .filter(entry -> entry.getKey() instanceof String)
+ .filter(entry -> entry.getValue() != null)
+ .filter(entry ->
((String)entry.getKey()).startsWith(prefix))
+ .forEach(entry -> {
+ final String key =
((String)entry.getKey()).substring(prefix.length());
+ final Object val = entry.getValue();
+
+ try {
+
IntrospectionSupport.setProperty(component, key, val, false);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ );
}
- };
-
- if (Files.exists(root)) {
- Files.walkFileTree(root, visitor);
- }
+ });
}
-
- return String.join(",", locations);
}
+
}
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Constants.java
b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Constants.java
index 0e9bcae..d123d7a 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Constants.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Constants.java
@@ -23,6 +23,7 @@
public static final String ENV_CAMEL_K_CONF_D = "CAMEL_K_CONF_D";
public static final String SCHEME_CLASSPATH = "classpath:";
public static final String SCHEME_FILE = "file:";
+ public static final String LOGGING_LEVEL_PREFIX = "logging.level.";
private Constants() {
}
diff --git
a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java
b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java
new file mode 100644
index 0000000..6210b54
--- /dev/null
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java
@@ -0,0 +1,110 @@
+/**
+ * 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.k.jvm;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Objects;
+import java.util.Properties;
+
+import org.apache.camel.util.ObjectHelper;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+
+public final class RuntimeSupport {
+ private RuntimeSupport() {
+ }
+
+ public static void configureSystemProperties() {
+ final String conf = System.getenv(Constants.ENV_CAMEL_K_CONF);
+ final String confd = System.getenv(Constants.ENV_CAMEL_K_CONF_D);
+ final Properties properties = new Properties();
+
+ // Main location
+ if (ObjectHelper.isNotEmpty(conf)) {
+ try (Reader reader = Files.newBufferedReader(Paths.get(conf))) {
+ properties.load(reader);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ // Additional locations
+ if (ObjectHelper.isNotEmpty(confd)) {
+ Path root = Paths.get(confd);
+ FileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
+ Objects.requireNonNull(file);
+ Objects.requireNonNull(attrs);
+
+ String path = file.toFile().getAbsolutePath();
+ String ext = FilenameUtils.getExtension(path);
+
+ if (Objects.equals("properties", ext)) {
+ try (Reader reader =
Files.newBufferedReader(Paths.get(path))) {
+ properties.load(reader);
+ }
+ }
+
+ return FileVisitResult.CONTINUE;
+ }
+ };
+
+ if (Files.exists(root)) {
+ try {
+ Files.walkFileTree(root, visitor);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ System.getProperties().putAll(properties);
+ }
+
+ public static void configureLogging() {
+ final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
+ final Properties properties = System.getProperties();
+
+ properties.entrySet().stream()
+ .filter(entry -> entry.getKey() instanceof String)
+ .filter(entry -> entry.getValue() instanceof String)
+ .filter(entry ->
((String)entry.getKey()).startsWith(Constants.LOGGING_LEVEL_PREFIX))
+ .forEach(entry -> {
+ String key = ((String)entry.getKey());
+ String val = ((String)entry.getValue());
+
+ String logger =
key.substring(Constants.LOGGING_LEVEL_PREFIX.length());
+ Level level = Level.getLevel(val);
+ LoggerConfig config = new LoggerConfig(logger, level, true);
+
+ ctx.getConfiguration().addLogger(logger, config);
+ }
+ );
+ }
+}
diff --git
a/runtime/jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java
b/runtime/jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java
new file mode 100644
index 0000000..2bfba13
--- /dev/null
+++ b/runtime/jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java
@@ -0,0 +1,97 @@
+/**
+ * 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.k.jvm;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.seda.SedaComponent;
+import org.apache.camel.main.Main;
+import org.apache.camel.main.MainListenerSupport;
+import org.apache.camel.main.MainSupport;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class PropertiesTest {
+
+ @Test
+ public void testSystemProperties() throws Exception {
+ System.setProperty("my.property", "my.value");
+
+ try {
+ Main main = new Main();
+ main.setDuration(5);
+ main.addMainListener(new Application.ComponentPropertiesBinder());
+ main.addMainListener(new MainListenerSupport() {
+ @Override
+ public void afterStart(MainSupport main) {
+ try {
+ CamelContext context = main.getCamelContexts().get(0);
+ String value =
context.resolvePropertyPlaceholders("{{my.property}}");
+
+ assertThat(value).isEqualTo("my.value");
+
+ main.stop();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+
+ main.run();
+ } finally {
+ System.getProperties().remove("my.property");
+ }
+ }
+
+
+ @Test
+ public void testComponentConfiguration() throws Exception {
+ int queueSize1 = ThreadLocalRandom.current().nextInt(10, 100);
+ int queueSize2 = ThreadLocalRandom.current().nextInt(10, 100);
+
+ System.setProperty("camel.component.seda.queueSize",
Integer.toString(queueSize1));
+ System.setProperty("camel.component.my-seda.queueSize",
Integer.toString(queueSize2));
+
+ try {
+ Main main = new Main();
+ main.setDuration(5);
+ main.bind("my-seda", new SedaComponent());
+ main.addMainListener(new Application.ComponentPropertiesBinder());
+ main.addMainListener(new MainListenerSupport() {
+ @Override
+ public void afterStart(MainSupport main) {
+ try {
+ CamelContext context = main.getCamelContexts().get(0);
+
+ assertThat(context.getComponent("seda",
true)).hasFieldOrPropertyWithValue("queueSize", queueSize1);
+ assertThat(context.getComponent("my-seda",
true)).hasFieldOrPropertyWithValue("queueSize", queueSize2);
+
+ main.stop();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+
+ main.run();
+ } finally {
+ System.getProperties().remove("camel.component.seda.queueSize");
+ }
+ }
+}
diff --git a/runtime/jvm/src/test/resources/log4j2-test.xml
b/runtime/jvm/src/test/resources/log4j2-test.xml
new file mode 100644
index 0000000..619c63a
--- /dev/null
+++ b/runtime/jvm/src/test/resources/log4j2-test.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="INFO">
+ <Appenders>
+ <Console name="STDOUT" target="SYSTEM_OUT">
+ <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}|%-5level|%t|%c{1} -
%msg%n"/>
+ </Console>
+ <File name="FILE" fileName="target/camel-k-runtime-jmv-test.log">
+ <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}|%-5level|%t|%c{1} -
%msg%n"/>
+ </File>
+ </Appenders>
+
+ <Loggers>
+ <Root level="INFO">
+ <!--<AppenderRef ref="STDOUT"/>-->
+ <AppenderRef ref="FILE"/>
+ </Root>
+ </Loggers>
+
+</Configuration>
\ No newline at end of file
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services