diff --git a/pages/docs/compiler.md b/pages/docs/compiler.md
index 86f15b7cdb2fcee74dc9d63f9bfa64cee2e8f62f..2c2cff3319a20fc47df50eb0d5fd2a2117da60f8 100644
--- a/pages/docs/compiler.md
+++ b/pages/docs/compiler.md
@@ -4,7 +4,7 @@ The compiler is JastAdd-compliant, i.e., it accepts all flags available for Jast
 Additional options are as follows.
 
 | Name | Required (Default) | Description |
-|-|-|-|
+|---|---|---|
 | `--rootNode` | Yes | Root node in the base grammar. |
 | `--protocols` | No (`mqtt`) | Protocols to enable, currently available: `mqtt, rest`. |
 | `--printYaml` | No (false) | Print out YAML instead of generating files. |
@@ -12,14 +12,15 @@ Additional options are as follows.
 | `--logReads` | No (false) | Enable logging for every received message. |
 | `--logWrites` | No (false) | Enable logging for every sent message. |
 | `--logIncremental` | No (false) | Enable logging for observer in incremental dependency tracking. |
+| `--loggingTarget` | No (`console`) | Logging target to use, currently available: `console, slf4j`. |
 | `--experimental-jastadd-329` | No (false) | Use trace events `INC_FLUSH_START` and `INC_FLUSH_END` ([JastAdd issue #329][jastadd-issue-329]), see [section about automatic dependency tracking](/using#dependency-tracking-automatically-derived). |
 | `--incremental` | No (false) | Enables incremental dependency tracking (if `trace` is also set appropriately). |
 | `--trace[=flush]` | No (false) | Enables incremental dependency tracking (if `incremental` is also set appropriately). |
 | `--version` | No (false) | Print version info and exit (reused JastAdd option) |
 | `--o` | No (`.`) | Output directory (reused JastAdd option) |
 
-All files to be process have to be passed as arguments.
-Their type is decided by the file extension (`ast` and `relast` for input grammars, `connect` and `ragconnect` for RagConnect definitions file).
+All files to be processed have to be passed as arguments.
+Their type is deduced by the file extension (`ast` and `relast` for input grammars, `connect` and `ragconnect` for RagConnect definitions file).
 
 # Additional software dependencies
 
@@ -52,7 +53,7 @@ However, depending on the selected protocols and/or used features, additional de
 - Additional remarks:
     - Host is always `localhost`.
     - Might work with newer versions of `com.sparkjava.spark-core` as well.
-    - For debugging, it is beneficial to include an implementation for [SLF4J](http://www.slf4j.org/).
+    - For debugging, it is beneficial to include an implementation for [SLF4J][slf4j].
 
 ## Used features
 
@@ -91,5 +92,15 @@ However, depending on the selected protocols and/or used features, additional de
 - Remarks:
     - [Feature description](/using#an-advanced-example)
 
+### Logging Target SLF4J
+
+- Condition: When using `--loggingTarget=slf4j` to RagConnect
+- Required runtime dependencies:
+  - `group: 'org.slf4j', name: 'slf4j-api', version: '1.7.0'`
+- Required options for RelAST compiler: _none_
+- Required options for JastAdd: _none_
+- Remarks:
+  - Additionally, a slf4j binding is required, see [the slf4j user manual][slf4j]
 
 [jastadd-issue-329]: https://bitbucket.org/jastadd/jastadd2/issues/329/add-event-for-completion-of-flush
+[slf4j]: https://www.slf4j.org/manual.html
diff --git a/ragconnect.base/src/main/jastadd/Intermediate.jadd b/ragconnect.base/src/main/jastadd/Intermediate.jadd
index 47f3aa473e0959ece3a24b684b98b59893c58413..196e129b756dcda568db630f59904c8a6d843126 100644
--- a/ragconnect.base/src/main/jastadd/Intermediate.jadd
+++ b/ragconnect.base/src/main/jastadd/Intermediate.jadd
@@ -17,6 +17,26 @@ aspect SharedMustache {
 
   syn String RagConnect.internalRagConnectPrefix() = "_ragconnect_";
 
+  syn String RagConnect.logDebug() = logStatement("debug");
+  syn String RagConnect.logInfo() = logStatement("info");
+  syn String RagConnect.logWarn() = logStatement("warn");
+  syn String RagConnect.logError() = logStatement("error");
+  syn String RagConnect.logException() = logStatement("exception");
+  syn String RagConnect.log_() {
+    switch (getConfiguration().getLoggingTarget()) {
+      //noinspection ConstantConditions
+      case "console":
+        return "%s";
+      //noinspection ConstantConditions
+      case "slf4j":
+        return "{}";
+      default:
+        return "?";
+    }
+  }
+  syn String RagConnect.logConsoleOut() = internalRagConnectPrefix() + "logStdOut";
+  syn String RagConnect.logConsoleErr() = internalRagConnectPrefix() + "logStdErr";
+
   syn String RagConnect.observerInstanceSingletonMethodName() = internalRagConnectPrefix() + "Observer";
   syn String RagConnect.observerInstanceResetMethodName() = internalRagConnectPrefix() + "resetObserver";
 
@@ -30,6 +50,31 @@ aspect SharedMustache {
   syn boolean EndpointDefinition.typeIsOpt() = getEndpointTarget().typeIsOpt();
 
   // === attributes needed for computing above ones ===
+  syn String RagConnect.logStatement(String level) {
+    switch (getConfiguration().getLoggingTarget()) {
+      //noinspection ConstantConditions
+      case "console":
+        switch (level) {
+          case "debug":
+          case "info":
+            return "ASTNode." + logConsoleOut();
+          case "warn":
+          case "error":
+          case "exception":
+            return "ASTNode." + logConsoleErr();
+          default:
+            return "unknownLoggingLevelForConsole_" + level + "_";
+        }
+      //noinspection ConstantConditions
+      case "slf4j":
+        if (level.equals("exception")) {
+          level = "error";
+        }
+        return "org.slf4j.LoggerFactory.getLogger(getClass())." + level;
+      default:
+        return "unknownLoggingOptionGiven_" + getConfiguration().getLoggingTarget() + "_";
+    }
+  }
   syn boolean EndpointTarget.typeIsList() = false;
   eq TypeEndpointTarget.typeIsList() {
     return getType().isListComponent();
diff --git a/ragconnect.base/src/main/jastadd/RagConnect.relast b/ragconnect.base/src/main/jastadd/RagConnect.relast
index f6cf0dd68708157aa291b6b0b50077b2fe72034c..02cdec5f5d27cce513bfdfcc4dfdc7d06b6bda4b 100644
--- a/ragconnect.base/src/main/jastadd/RagConnect.relast
+++ b/ragconnect.base/src/main/jastadd/RagConnect.relast
@@ -36,6 +36,7 @@ Configuration ::=
 <LoggingEnabledForReads:boolean>
 <LoggingEnabledForWrites:boolean>
 <LoggingEnabledForIncremental:boolean>
+<LoggingTarget:String>
 <JastAddList:String>
 <JastAddOpt:String>
 <IncrementalOptionActive:boolean>
diff --git a/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java b/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java
index d8c9c550d183416e353900e97b6629383b31016e..6a13da092ab01785478ca1b05e9d998b76735f6e 100644
--- a/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java
+++ b/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java
@@ -10,6 +10,7 @@ import org.jastadd.relast.compiler.AbstractCompiler;
 import org.jastadd.relast.compiler.CompilerException;
 
 import java.io.*;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -28,8 +29,12 @@ public class Compiler extends AbstractCompiler {
   private BooleanOption optionLogReads;
   private BooleanOption optionLogWrites;
   private BooleanOption optionLogIncremental;
+  private ValueOption optionLogTarget;
   private BooleanOption optionExperimentalJastAdd329;
 
+  private static final String OPTION_LOGGING_TARGET_CONSOLE = "console";
+  private static final String OPTION_LOGGING_TARGET_SLF4J = "slf4j";
+
   private static final String OPTION_PROTOCOL_MQTT = "mqtt";
   private static final String OPTION_PROTOCOL_REST = "rest";
 
@@ -107,10 +112,10 @@ public class Compiler extends AbstractCompiler {
       }
       String handlerFileName = handler.getDefinitionFileName();
       try {
-        InputStream inputStream = Compiler.class.getClassLoader().getResourceAsStream(handlerFileName);
-        if (inputStream == null) {
-          throw new CompilerException("Could not open " + handlerFileName);
-        }
+        InputStream inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
+//        if (inputStream == null) {
+//          throw new CompilerException("Could not open " + handlerFileName);
+//        }
         Files.copy(inputStream,
             getConfiguration().outputDir().toPath().resolve(handlerFileName),
             StandardCopyOption.REPLACE_EXISTING);
@@ -196,6 +201,11 @@ public class Compiler extends AbstractCompiler {
     optionLogIncremental = addOption(
         new BooleanOption("logIncremental", "Enable logging for observer in incremental dependency tracking.")
             .defaultValue(false));
+    optionLogTarget = addOption(
+            new ValueOption("logTarget", "Logging target to use")
+                    .addDefaultValue(OPTION_LOGGING_TARGET_CONSOLE, "Use std out and std err")
+                    .addAcceptedValue(OPTION_LOGGING_TARGET_SLF4J, "Use SLF4J API")
+    );
     optionExperimentalJastAdd329 = addOption(
         new BooleanOption("experimental-jastadd-329", "Use trace events INC_FLUSH_START and INC_FLUSH_END (JastAdd issue #329).")
             .defaultValue(false));
@@ -298,6 +308,7 @@ public class Compiler extends AbstractCompiler {
     ragConnect.getConfiguration().setLoggingEnabledForReads(optionLogReads.value());
     ragConnect.getConfiguration().setLoggingEnabledForWrites(optionLogWrites.value());
     ragConnect.getConfiguration().setLoggingEnabledForIncremental(optionLogIncremental.value());
+    ragConnect.getConfiguration().setLoggingTarget(optionLogTarget.value());
     ragConnect.getConfiguration().setExperimentalJastAdd329(optionExperimentalJastAdd329.value());
 
     // reuse "--incremental" and "--trace=flush" options of JastAdd
diff --git a/ragconnect.base/src/main/resources/MqttHandler.jadd b/ragconnect.base/src/main/resources/MqttHandler.mustache
similarity index 92%
rename from ragconnect.base/src/main/resources/MqttHandler.jadd
rename to ragconnect.base/src/main/resources/MqttHandler.mustache
index 0651d5fa84940f16ea6ff2ba1c674b477e509fe8..d5a83a04d89e67ecc09e45c0487bd37e516fd9ad 100644
--- a/ragconnect.base/src/main/resources/MqttHandler.jadd
+++ b/ragconnect.base/src/main/resources/MqttHandler.mustache
@@ -1,4 +1,3 @@
-aspect MqttHandler {
 public class MqttServerHandler {
   private final java.util.Map<String, MqttHandler> handlers = new java.util.HashMap<>();
   private final java.util.Map<RagConnectToken, java.util.function.BiConsumer<String, byte[]>> tokensForRemoval = new java.util.HashMap<>();
@@ -90,7 +89,6 @@ public class MqttHandler {
   }
   private static final int DEFAULT_PORT = 1883;
 
-  private final org.apache.logging.log4j.Logger logger;
   private final String name;
 
   /** The host running the MQTT broker. */
@@ -112,7 +110,6 @@ public class MqttHandler {
 
   public MqttHandler(String name) {
     this.name = java.util.Objects.requireNonNull(name, "Name must be set");
-    this.logger = org.apache.logging.log4j.LogManager.getLogger(MqttHandler.class);
     this.normalCallbacks = new java.util.HashMap<>();
     this.wildcardCallbacks = new java.util.ArrayList<>();
     this.readyLatch = new java.util.concurrent.CountDownLatch(1);
@@ -149,7 +146,7 @@ public class MqttHandler {
     java.util.Objects.requireNonNull(host, "Host need to be set!");
 
     this.host = java.net.URI.create("tcp://" + host + ":" + port);
-    logger.debug("Host for {} is {}", this.name, this.host);
+    {{logDebug}}("Host for {{log_}} is {{log_}}", this.name, this.host);
 
     org.fusesource.mqtt.client.MQTT mqtt = new org.fusesource.mqtt.client.MQTT();
     mqtt.setHost(this.host);
@@ -159,12 +156,12 @@ public class MqttHandler {
     // add the listener to dispatch messages later
     connection.listener(new org.fusesource.mqtt.client.ExtendedListener() {
       public void onConnected() {
-        logger.debug("Connected");
+        {{logDebug}}("Connected");
       }
 
       @Override
       public void onDisconnected() {
-        logger.debug("Disconnected");
+        {{logDebug}}("Disconnected");
       }
 
       @Override
@@ -172,10 +169,10 @@ public class MqttHandler {
                             org.fusesource.hawtbuf.Buffer body,
                             org.fusesource.mqtt.client.Callback<org.fusesource.mqtt.client.Callback<Void>> ack) {
         // this method is called, whenever a MQTT message is received
-        String topicString = topic.toString();
+        final String topicString = topic.toString();
         java.util.List<java.util.function.BiConsumer<String, byte[]>> callbackList = callbacksFor(topicString);
         if (callbackList.isEmpty()) {
-          logger.debug("Got a message at {}, but no callback to call. Forgot to subscribe?", topic);
+          {{logDebug}}("Got a message at {{log_}}, but no callback to call. Forgot to subscribe?", topic);
         } else {
           byte[] message = body.toByteArray();
           for (java.util.function.BiConsumer<String, byte[]> callback : callbackList) {
@@ -183,7 +180,7 @@ public class MqttHandler {
               astLock.lock();
               callback.accept(topicString, message);
             } catch (Exception e) {
-              logger.catching(e);
+              {{logException}}("Exception in callback for " + topicString, e);
             } finally {
               astLock.unlock();
             }
@@ -197,7 +194,7 @@ public class MqttHandler {
                             org.fusesource.hawtbuf.Buffer body,
                             Runnable ack) {
         // not used by this type of connection
-        logger.warn("onPublish should not be called");
+        {{logWarn}}("onPublish should not be called");
       }
 
       @Override
@@ -219,13 +216,13 @@ public class MqttHandler {
               new org.fusesource.mqtt.client.Callback<>() {
                 @Override
                 public void onSuccess(Void value) {
-                  logger.debug("success sending welcome message");
+                  {{logDebug}}("success sending welcome message");
                   setReady();
                 }
 
             @Override
-            public void onFailure(Throwable value) {
-              logger.debug("failure sending welcome message", value);
+            public void onFailure(Throwable cause) {
+              {{logException}}("failure sending welcome message", cause);
             }
           });
         } else {
@@ -296,7 +293,7 @@ public class MqttHandler {
       return false;
     }
     // register callback
-    logger.debug("new connection for {}", topic);
+    {{logDebug}}("new connection for {{log_}}", topic);
     final boolean needSubscribe;
     if (isWildcardTopic(topic)) {
       String regex = regexForWildcardTopic(topic);
@@ -330,13 +327,13 @@ public class MqttHandler {
         connection.subscribe(topicArray, new org.fusesource.mqtt.client.Callback<>() {
           @Override
           public void onSuccess(byte[] qoses) {
-            logger.debug("Subscribed to {}, qoses: {}", topic, qoses);
+            {{logDebug}}("Subscribed to {{log_}}, qoses: {{log_}}", topic, qoses);
             operationFinished.countDown();
           }
 
           @Override
           public void onFailure(Throwable cause) {
-            logger.error("Could not subscribe to {}", topic, cause);
+            {{logException}}("Could not subscribe to " + topic, cause);
             success.set(false);
             operationFinished.countDown();
           }
@@ -403,7 +400,7 @@ public class MqttHandler {
     }
 
     if (topicToUnsubscribe == null) {
-      logger.warn("Disconnect for not connected topic '{}'", topic);
+      {{logWarn}}("Disconnect for not connected topic '{{log_}}'", topic);
       return false;
     }
 
@@ -422,7 +419,7 @@ public class MqttHandler {
           @Override
           public void onFailure(Throwable cause) {
             success.set(false);
-            logger.warn("Could not disconnect from {}", topic, cause);
+            {{logException}}("Could not disconnect from " + topic, cause);
             operationFinished.countDown();
           }
         });
@@ -433,7 +430,7 @@ public class MqttHandler {
           return false;
         }
       } catch (InterruptedException e) {
-        logger.catching(e);
+        {{logException}}("Interrupted while disconnecting from " + topic, e);
         success.set(false);
       }
     }
@@ -460,14 +457,14 @@ public class MqttHandler {
 
   public void close() {
     if (connection == null) {
-      logger.warn("Stopping without connection. Was setHost() called?");
+      {{logWarn}}("Stopping without connection. Was setHost() called?");
       return;
     }
     connection.getDispatchQueue().execute(() -> {
       connection.disconnect(new org.fusesource.mqtt.client.Callback<>() {
         @Override
         public void onSuccess(Void value) {
-          logger.info("Disconnected {} from {}", name, host);
+          {{logInfo}}("Disconnected {{log_}} from {{log_}}", name, host);
         }
 
         @Override
@@ -493,12 +490,12 @@ public class MqttHandler {
         connection.publish(topic, bytes, qos, retain, new org.fusesource.mqtt.client.Callback<>() {
           @Override
           public void onSuccess(Void value) {
-            logger.debug("Published some bytes to {}", topic);
+            {{logDebug}}("Published some bytes to {{log_}}", topic);
           }
 
           @Override
-          public void onFailure(Throwable value) {
-            logger.warn("Could not publish on topic '{}'", topic, value);
+          public void onFailure(Throwable cause) {
+            {{logException}}("Could not publish on topic " + topic, cause);
           }
         });
       });
@@ -507,4 +504,3 @@ public class MqttHandler {
     }
   }
 }
-}
diff --git a/ragconnect.base/src/main/resources/RestHandler.jadd b/ragconnect.base/src/main/resources/RestHandler.mustache
similarity index 85%
rename from ragconnect.base/src/main/resources/RestHandler.jadd
rename to ragconnect.base/src/main/resources/RestHandler.mustache
index 9187afdab7a15c0bd7dc10679991505874c8af61..25192af366bfd4da29ace5c11d661b8cc8fd0992 100644
--- a/ragconnect.base/src/main/resources/RestHandler.jadd
+++ b/ragconnect.base/src/main/resources/RestHandler.mustache
@@ -1,14 +1,9 @@
-import java.util.concurrent.TimeUnit;aspect RestHandler {
 public class RestServerHandler {
   private static final int DEFAULT_PORT = 4567;
   private final java.util.Map<Integer, RestHandler> handlers = new java.util.HashMap<>();
   private final java.util.Map<RagConnectToken, Object> tokensForRemoval = new java.util.HashMap<>();
   private String name;
 
-  public RestServerHandler() {
-    this("RagConnect");
-  }
-
   public RestServerHandler(String name) {
     this.name = name;
   }
@@ -39,7 +34,7 @@ public class RestServerHandler {
 
   public boolean disconnect(RagConnectToken connectToken) {
     RestHandler handler = resolveHandler(connectToken.uri);
-    return handler != null ? handler.disconnect(connectToken.uri.getPath(), tokensForRemoval.get(connectToken)) : false;
+    return handler != null && handler.disconnect(connectToken.uri.getPath(), tokensForRemoval.get(connectToken));
   }
 
   public void close() {
@@ -55,23 +50,13 @@ public class RestServerHandler {
 public class RestHandler {
   private static final int DEFAULT_PORT = 4567;
 
-  private final org.apache.logging.log4j.Logger logger;
-  private final String name;
   private int port;
-  private final java.util.concurrent.CountDownLatch exitCondition;
   /** Dispatch knowledge */
   private final java.util.Map<String, java.util.List<java.util.function.Consumer<String>>> callbacks;
   private final java.util.Map<String, SupplierWithException<String>> suppliers;
 
   public RestHandler() {
-    this("RagConnect");
-  }
-
-  public RestHandler(String name) {
-    this.logger = org.apache.logging.log4j.LogManager.getLogger(RestHandler.class);
-    this.name = name;
     this.port = DEFAULT_PORT;
-    this.exitCondition = new java.util.concurrent.CountDownLatch(1);
     this.callbacks = new java.util.HashMap<>();
     this.suppliers = new java.util.HashMap<>();
   }
@@ -111,7 +96,7 @@ public class RestHandler {
 
   public void newGETConnection(String path, SupplierWithException<String> supplier) {
     if (suppliers.get(path) != null) {
-      logger.warn("Overriding existing supplier for '{}'", path);
+      {{logWarn}}("Overriding existing supplier for '{{log_}}'", path);
     }
     suppliers.put(path, supplier);
     spark.Spark.get(path, (request, response) -> {
@@ -142,7 +127,7 @@ public class RestHandler {
   }
 
   private void start() {
-    logger.info("Starting REST server at {}", this.port);
+    {{logInfo}}("Starting REST server at {{log_}}", this.port);
     spark.Spark.port(this.port);
     spark.Spark.init();
     spark.Spark.awaitInitialization();
@@ -156,6 +141,5 @@ public class RestHandler {
 }
 @FunctionalInterface
 public interface SupplierWithException<T> {
-  public T get() throws Exception;
-}
+  T get() throws Exception;
 }
diff --git a/ragconnect.base/src/main/resources/handleUri.mustache b/ragconnect.base/src/main/resources/handleUri.mustache
index ff0ea7af7f920ac09a14de75a4afe1882540ac94..2312cd6983822c0e0b2987459047b7ca2a277fc2 100644
--- a/ragconnect.base/src/main/resources/handleUri.mustache
+++ b/ragconnect.base/src/main/resources/handleUri.mustache
@@ -6,18 +6,18 @@ try {
   host = uri.getHost();
   path = uri.getPath() + (uri.getFragment() != null ? "#" : "");
 } catch (java.net.URISyntaxException e) {
-  System.err.println(e.getMessage());  // Maybe re-throw error?
+  {{logError}}(e.getMessage());  // Maybe re-throw error?
   return false;
 }
 if (scheme == null || scheme.isBlank()) {
-  System.err.println("Missing or empty scheme in " + uri);
+  {{logError}}("Missing or empty scheme in " + uri);
   return false;
 }
 if (host == null || host.isBlank()) {
-  System.err.println("Missing or empty host in " + uri);
+  {{logError}}("Missing or empty host in " + uri);
   return false;
 }
 if (path == null || path.isBlank()) {
-  System.err.println("Missing or empty path in " + uri);
+  {{logError}}("Missing or empty path in " + uri);
   return false;
 }
diff --git a/ragconnect.base/src/main/resources/handler.mustache b/ragconnect.base/src/main/resources/handler.mustache
index 0d368731fd37454d5ea3982ebd2a3e2d03c8f047..49194266f96e84a4c24bc0987b83647082132dc2 100644
--- a/ragconnect.base/src/main/resources/handler.mustache
+++ b/ragconnect.base/src/main/resources/handler.mustache
@@ -25,8 +25,15 @@ aspect RagConnectHandler {
     {{fieldName}}.setupWaitUntilReady(time, unit);
   }
   {{/InUse}}
+{{> MqttHandler}}
 {{/mqttHandler}}
 
+{{#restHandler}}
+  {{#InUse}}
+{{> RestHandler}}
+  {{/InUse}}
+{{/restHandler}}
+
   class RagConnectToken {
     static java.util.concurrent.atomic.AtomicLong counter = new java.util.concurrent.atomic.AtomicLong(0);
     final long id;
@@ -81,7 +88,7 @@ aspect RagConnectHandler {
       if (errorMessage == null) {
         return true;
       } else {
-        System.err.println(errorMessage);
+        {{logWarn}}(errorMessage);
         return false;
       }
     }
@@ -145,7 +152,9 @@ aspect RagConnectHandler {
       }
       if (!result) {
         // only print error message, if all publishers failed to remove the token
-        errorMessages.stream().forEachOrdered(System.err::println);
+        for (String message : errorMessages) {
+          {{logError}}(message);
+        }
       }
       return result;
     }
diff --git a/ragconnect.base/src/main/resources/ragconnect.mustache b/ragconnect.base/src/main/resources/ragconnect.mustache
index dc6b839a87050d3993cd1bf6f19ffe3694d16242..ac7b906067f5f9ecd4a2bf0c51a368797f55dfbc 100644
--- a/ragconnect.base/src/main/resources/ragconnect.mustache
+++ b/ragconnect.base/src/main/resources/ragconnect.mustache
@@ -67,6 +67,24 @@ aspect RagConnect {
 
   {{> ListAspect}}
 
+  static void ASTNode.{{logConsoleOut}}(String message, Object... args) {
+    System.out.println(String.format(message, args));
+  }
+
+  static void ASTNode.{{logConsoleOut}}(String message, Throwable t) {
+    System.out.println(message);
+    t.printStackTrace();
+  }
+
+  static void ASTNode.{{logConsoleErr}}(String message, Object... args) {
+    System.err.println(String.format(message, args));
+  }
+
+  static void ASTNode.{{logConsoleErr}}(String message, Throwable t) {
+    System.err.println(message);
+    t.printStackTrace();
+  }
+
   public void {{rootNodeName}}.ragconnectCheckIncremental() {
   {{#configIncrementalOptionActive}}
     // check if --tracing is active
@@ -154,7 +172,8 @@ aspect RagConnectObserver {
     private void internal_add(RagConnectToken connectToken, ASTNode node, String attributeString,
         boolean compareParams, Object params, Runnable attributeCall) {
       {{#configLoggingEnabledForIncremental}}
-      System.out.println("** observer add: " + node + " on " + attributeString + (compareParams ? " (parameterized)" : ""));
+      {{logDebug}}("** observer add: {{log_}} on {{log_}}{{log_}}",
+        node, attributeString, (compareParams ? " (parameterized)" : ""));
       {{/configLoggingEnabledForIncremental}}
       // either add to an existing entry (with same node, attribute) or create new entry
       boolean needNewEntry = true;
@@ -193,7 +212,7 @@ aspect RagConnectObserver {
       // react to INC_FLUSH_START and remember entry
       if (event == ASTState.Trace.Event.INC_FLUSH_START) {
         {{#configLoggingEnabledForIncremental}}
-        System.out.println("** observer start: " + node + " on " + attribute);
+        {{logDebug}}("** observer start: {{log_}} on {{log_}}", node, attribute);
         {{/configLoggingEnabledForIncremental}}
         startEntries.addFirst(new RagConnectObserverStartEntry(node, attribute, value));
         return;
@@ -203,7 +222,7 @@ aspect RagConnectObserver {
       if (event == ASTState.Trace.Event.INC_FLUSH_END) {
         if (startEntries.isEmpty()) {
           {{#configLoggingEnabledForIncremental}}
-          System.out.println("** observer end without start! for " + node + " on " + attribute);
+          {{logDebug}}("** observer end without start! for {{log_}} on {{log_}}", node, attribute);
           {{/configLoggingEnabledForIncremental}}
           return;
         }
@@ -216,7 +235,8 @@ aspect RagConnectObserver {
           entryQueue.clear();
           startEntries.removeFirst();
           {{#configLoggingEnabledForIncremental}}
-          System.out.println("** observer process (entries: " + entriesToProcess.length + "): " + node + " on " + attribute);
+          {{logDebug}}("** observer process (entries: {{log_}}): {{log_}} on {{log_}}",
+            entriesToProcess.length, node, attribute);
           {{/configLoggingEnabledForIncremental}}
           for (RagConnectObserverEntry entry : entriesToProcess) {
             entry.attributeCall.run();
@@ -232,14 +252,14 @@ aspect RagConnectObserver {
       }
 
       {{#configLoggingEnabledForIncremental}}
-      System.out.println("** observer check INC_FLUSH_ATTR event: " + node + " on " + attribute);
+      {{logDebug}}("** observer check INC_FLUSH_ATTR event: {{log_}} on {{log_}}", node, attribute);
       {{/configLoggingEnabledForIncremental}}
       // iterate through list, if matching pair. could maybe be more efficient.
       for (RagConnectObserverEntry entry : observedNodes) {
         if (entry.node.equals(node) && entry.attributeString.equals(attribute) && (!entry.compareParams || java.util.Objects.equals(entry.params, params))) {
           // hit. call the attribute/nta-token
           {{#configLoggingEnabledForIncremental}}
-          System.out.println("** observer hit: " + entry.node + " on " + entry.attributeString);
+          {{logDebug}}("** observer hit: {{log_}} on {{log_}}", entry.node, entry.attributeString);
           {{/configLoggingEnabledForIncremental}}
 {{#configExperimentalJastAdd329}}
           entryQueue.add(entry);
diff --git a/ragconnect.base/src/main/resources/receiveDefinition.mustache b/ragconnect.base/src/main/resources/receiveDefinition.mustache
index 3bd20363ab557af22e937f7cbc35a869df3dc075..cb4dc8dc718eba53b0cd6a3bce9b4f996cdd4675 100644
--- a/ragconnect.base/src/main/resources/receiveDefinition.mustache
+++ b/ragconnect.base/src/main/resources/receiveDefinition.mustache
@@ -27,7 +27,7 @@ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParamete
   java.util.function.BiConsumer<String, byte[]> consumer = (topic, message) -> {
     {{> mappingApplication}}
 {{#configLoggingEnabledForReads}}
-    System.out.println("[Receive] " + {{connectParameterName}} + " -> {{entityName}} = " + {{lastResult}});
+    {{logDebug}}("[Receive] {{log_}} -> {{entityName}} = {{log_}}", {{connectParameterName}}, {{lastResult}});
 {{/configLoggingEnabledForReads}}
 {{#hasTypeEndpointTarget}}
     {{lastResult}}.treeResolveAll();
@@ -73,7 +73,8 @@ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParamete
     int index = {{resolveInListMethodName}}(topic);
     {{> mappingApplication}}
 {{#configLoggingEnabledForReads}}
-    System.out.println("[Receive] " + {{connectParameterName}} + " (" + topic + ") -> {{entityName}} = " + {{lastResult}});
+    {{logDebug}}("[Receive] {{log_}} ({{log_}}) -> {{entityName}} = {{log_}}",
+      {{connectParameterName}}, topic, {{lastResult}});
 {{/configLoggingEnabledForReads}}
     {{lastResult}}.set{{idTokenName}}(topic);
     if (index == -1) {
@@ -110,7 +111,7 @@ private boolean {{parentTypeName}}.{{internalConnectMethodName}}(String {{connec
   {{/InUse}}
   {{/restHandler}}
     default:
-      System.err.println("Unknown protocol '" + scheme + "'.");
+      {{logError}}("Unknown protocol '{{log_}}'.", scheme);
       success = false;
   }
   if (success) {
@@ -123,7 +124,8 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam
   {{>handleUri}}
   java.util.List<RagConnectToken> connectTokens = connectTokenMap.removeAll(this, true, uri, "{{entityName}}");
   if (connectTokens.isEmpty()) {
-    System.err.println("Disconnect called without connection for receiving " + this + ".{{entityName}} to '" + {{connectParameterName}} + "'!");
+    {{logWarn}}("Disconnect called without connection for receiving {{log_}}.{{entityName}} to '{{log_}}'!",
+      this, {{connectParameterName}});
     return false;
   }
   RagConnectDisconnectHandlerMethod disconnectingMethod;
@@ -141,7 +143,8 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam
   {{/InUse}}
   {{/restHandler}}
     default:
-      System.err.println("Unknown protocol '" + scheme + "' in '" + {{connectParameterName}} + "' for disconnecting {{parentTypeName}}.{{entityName}}");
+      {{logError}}("Unknown protocol '{{log_}}' in '{{log_}}' for disconnecting {{parentTypeName}}.{{entityName}}",
+        scheme, {{connectParameterName}});
       return false;
   }
   boolean success = true;
diff --git a/ragconnect.base/src/main/resources/sendDefinition.mustache b/ragconnect.base/src/main/resources/sendDefinition.mustache
index 18d48cafc978318d3e06b32af8e9f315e75c31a4..b066c690444a48cb8aadd64ccdd2dcdc2a46f78d 100644
--- a/ragconnect.base/src/main/resources/sendDefinition.mustache
+++ b/ragconnect.base/src/main/resources/sendDefinition.mustache
@@ -12,7 +12,7 @@ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParamete
       final String topic = {{attributeName}}().extractTopic(uri);
       {{senderName}}.add(() -> {
         {{#configLoggingEnabledForWrites}}
-        System.out.println("[Send] {{entityName}} = " + {{getterMethodCall}} + " -> " + {{connectParameterName}});
+        {{logDebug}}("[Send] {{entityName}} = {{log_}} -> {{log_}}", {{getterMethodCall}}, {{connectParameterName}});
         {{/configLoggingEnabledForWrites}}
         handler.publish(topic, {{lastValueGetterCall}});
         }{{#IndexBasedListAccess}}, index{{/IndexBasedListAccess}}, connectToken);
@@ -35,7 +35,7 @@ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParamete
   {{/InUse}}
   {{/restHandler}}
     default:
-      System.err.println("Unknown protocol '" + scheme + "'.");
+      {{logError}}("Unknown protocol '{{log_}}'.", scheme);
       success = false;
   }
   if (success) {
@@ -63,7 +63,8 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam
   {{>handleUri}}
   java.util.List<RagConnectToken> connectTokens = connectTokenMap.removeAll(this, false, uri, "{{entityName}}");
   if (connectTokens.isEmpty()) {
-    System.err.println("Disconnect called without connection for sending " + this + ".{{entityName}} to '" + {{connectParameterName}} + "'!");
+    {{logWarn}}("Disconnect called without connection for sending {{log_}}.{{entityName}} to '{{log_}}'!",
+      this, {{connectParameterName}});
     return false;
   }
   {{#configIncrementalOptionActive}}
@@ -86,7 +87,8 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam
   {{/InUse}}
   {{/restHandler}}
     default:
-      System.err.println("Unknown protocol '" + scheme + "' in '" + {{connectParameterName}} + "' for disconnecting {{parentTypeName}}.{{entityName}}");
+      {{logError}}("Unknown protocol '{{log_}}' in '{{log_}}' for disconnecting {{parentTypeName}}.{{entityName}}",
+        scheme, {{connectParameterName}});
       return false;
   }
   boolean success = true;
diff --git a/ragconnect.base/src/main/resources/typeDecl.mustache b/ragconnect.base/src/main/resources/typeDecl.mustache
index e37001ee779e6d5fcf471a80085a6a2817b7882b..1f674da36852786afab198b086b39b3cbf543b7b 100644
--- a/ragconnect.base/src/main/resources/typeDecl.mustache
+++ b/ragconnect.base/src/main/resources/typeDecl.mustache
@@ -27,7 +27,7 @@ public boolean {{Name}}.{{connectMethodName}}(String {{connectParameterName}}{{#
     {{/isListComponent}}
   {{/occurencesInProductionRules}}
     default:
-      System.err.println("No matching context while connecting " + this + " to " + {{connectParameterName}});
+      {{logError}}("No matching context while connecting {{log_}} to {{log_}}", this, {{connectParameterName}});
       return false;
   }
 }
@@ -38,7 +38,7 @@ public boolean {{Name}}.{{disconnectMethodName}}(String {{connectParameterName}}
   case "{{parentTypeName}}.{{Name}}": return (({{parentTypeName}}) _ragconnect_myParent()).{{disconnectMethodName}}({{connectParameterName}});
 {{/occurencesInProductionRules}}
     default:
-      System.err.println("No matching context while disconnecting for " + this + " from " + {{connectParameterName}});
+      {{logError}}("No matching context while disconnecting {{log_}} to {{log_}}", this, {{connectParameterName}});
       return false;
   }
 }