Repository: apache/camel-k
Pull request #2244 (2021-04-28 13:55:08)

doc(install): operationalize options
<!-- Description -->
* Polished the toleration trait example
* Added a section dedicate to the "operationalization" options introduced in 1.4.0



<!--
Enter your extended release note in the below block. If the PR requires
additional action from users switching to the new release, include the string
"action required". If no release note is required, write "NONE". 

You can (optionally) mark this PR with labels "kind/bug" or "kind/feature" to make sure
the text is added to the right section of the release notes. 
-->

**Release Note**
```release-note
doc(install): operationalize options
```



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 215aacffd..2241297ac 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,13 +9,20 @@
 - Update run-from-github page to correct github example path [\#2230](https://github.com/apache/camel-k/issues/2230)
 - Release 1.4.0 [\#2134](https://github.com/apache/camel-k/issues/2134)
 - Can't mount secrets with binary data [\#2009](https://github.com/apache/camel-k/issues/2009)
+- kamelet-binding : suport for error handling [\#1941](https://github.com/apache/camel-k/issues/1941)
 
 **Merged pull requests:**
 
+- fix\(api\): Fix error handler types deepcopy generation [\#2253](https://github.com/apache/camel-k/pull/2253) ([astefanutti](https://github.com/astefanutti))
+- Added support for the json log format via the logging trait [\#2252](https://github.com/apache/camel-k/pull/2252) ([orpiske](https://github.com/orpiske))
+- Improve readability of error messages in Camel K [\#2245](https://github.com/apache/camel-k/pull/2245) ([orpiske](https://github.com/orpiske))
 - fix\(ci\): Use Docker to build OLM index image [\#2242](https://github.com/apache/camel-k/pull/2242) ([astefanutti](https://github.com/astefanutti))
+- fix\(build\): Default to routine build strategy for local IntegrationPlatform [\#2240](https://github.com/apache/camel-k/pull/2240) ([astefanutti](https://github.com/astefanutti))
+- chore: ugprade Service Binding Operator v0.7.1 [\#2235](https://github.com/apache/camel-k/pull/2235) ([johnpoth](https://github.com/johnpoth))
 - chore: change references to use "main" [\#2234](https://github.com/apache/camel-k/pull/2234) ([nicolaferraro](https://github.com/nicolaferraro))
 - Bump version to 1.5.0-SNAPSHOT [\#2233](https://github.com/apache/camel-k/pull/2233) ([nicolaferraro](https://github.com/nicolaferraro))
 - issue2230- fix for run-from-github page [\#2231](https://github.com/apache/camel-k/pull/2231) ([bfitzpat](https://github.com/bfitzpat))
+- feat\(kamelets\): kamelet binding error handler [\#2217](https://github.com/apache/camel-k/pull/2217) ([squakez](https://github.com/squakez))
 
 ## [v1.4.0](https://github.com/apache/camel-k/tree/v1.4.0) (2021-04-16)
 
@@ -704,7 +711,6 @@
 - Basic javascript example generates "Multiple applicable overloads found for method name process" [\#1144](https://github.com/apache/camel-k/issues/1144)
 - Basic groovy example generates "Ambiguous method overloading for method org.apache.camel.model.RouteDefinition\#process" [\#1143](https://github.com/apache/camel-k/issues/1143)
 - Multiple traits to create a service [\#1061](https://github.com/apache/camel-k/issues/1061)
-- camel-k installation struggles [\#1059](https://github.com/apache/camel-k/issues/1059)
 - Camel K Operator is not reading the Telegram endpoint API-Key properly. [\#1039](https://github.com/apache/camel-k/issues/1039)
 - No interface for setting the number of pods on which an integration is to be deployed [\#1032](https://github.com/apache/camel-k/issues/1032)
 - Is there a way to co-locate the camel-k-operator, builder and PV in the same node [\#924](https://github.com/apache/camel-k/issues/924)
@@ -1111,6 +1117,7 @@
 - No component found with scheme: http4 // Camel-k 1.0.0M4 [\#1072](https://github.com/apache/camel-k/issues/1072)
 - Registry beans issues after upgrade from kamel 0.3.4 to kamel 1.0.0 M4 [\#1071](https://github.com/apache/camel-k/issues/1071)
 - broken routes.js example [\#1065](https://github.com/apache/camel-k/issues/1065)
+- camel-k installation struggles [\#1059](https://github.com/apache/camel-k/issues/1059)
 - camel-k-maven-plugin must not contain any of these characters \/:"\<\>|?\* but found \> @ line 16, column 18 [\#1056](https://github.com/apache/camel-k/issues/1056)
 - Automatically extract trait configuration for user manual [\#1014](https://github.com/apache/camel-k/issues/1014)
 - Cannot set blockOwnerDeletion in this case because cannot find RESTMapping for APIVersion camel.apache.org/v1alpha1 Kind IntegrationKit [\#764](https://github.com/apache/camel-k/issues/764)
@@ -1950,6 +1957,7 @@
 - chore\(release\): package examples to publish them during release [\#295](https://github.com/apache/camel-k/pull/295) ([nicolaferraro](https://github.com/nicolaferraro))
 - Allow to generate install resources if needed [\#294](https://github.com/apache/camel-k/pull/294) ([nicolaferraro](https://github.com/nicolaferraro))
 - Re-add missing commits [\#293](https://github.com/apache/camel-k/pull/293) ([nicolaferraro](https://github.com/nicolaferraro))
+- Inject camel-k version as environment variable [\#286](https://github.com/apache/camel-k/pull/286) ([lburgazzoli](https://github.com/lburgazzoli))
 - chore\(log\): make dev-mode work in Knative [\#280](https://github.com/apache/camel-k/pull/280) ([nicolaferraro](https://github.com/nicolaferraro))
 - Fix \#221: use registry name instead of IP in Knative on Openshift [\#278](https://github.com/apache/camel-k/pull/278) ([nicolaferraro](https://github.com/nicolaferraro))
 - Determine active/passive endpoints from Catalog [\#277](https://github.com/apache/camel-k/pull/277) ([lburgazzoli](https://github.com/lburgazzoli))
@@ -2130,7 +2138,6 @@
 - chore\(kamel\): improve completion and context delete [\#111](https://github.com/apache/camel-k/pull/111) ([lburgazzoli](https://github.com/lburgazzoli))
 - chore\(dep\): remove dependency on yaml.v1 [\#110](https://github.com/apache/camel-k/pull/110) ([lburgazzoli](https://github.com/lburgazzoli))
 - Add asciidoc documentation with sub-documents and some badges [\#109](https://github.com/apache/camel-k/pull/109) ([nicolaferraro](https://github.com/nicolaferraro))
-- Refactor build, deploy and run workflow [\#107](https://github.com/apache/camel-k/pull/107) ([lburgazzoli](https://github.com/lburgazzoli))
 - Bump version to 0.0.3-SNAPSHOT [\#105](https://github.com/apache/camel-k/pull/105) ([nicolaferraro](https://github.com/nicolaferraro))
 
 ## [0.0.2](https://github.com/apache/camel-k/tree/0.0.2) (2018-09-19)
@@ -2161,6 +2168,7 @@
 
 **Merged pull requests:**
 
+- Refactor build, deploy and run workflow [\#107](https://github.com/apache/camel-k/pull/107) ([lburgazzoli](https://github.com/lburgazzoli))
 - Fix golint findings, remove unused code [\#103](https://github.com/apache/camel-k/pull/103) ([lburgazzoli](https://github.com/lburgazzoli))
 - feat\(examples\): Add a Camel-caffeine Cache java sample [\#101](https://github.com/apache/camel-k/pull/101) ([oscerd](https://github.com/oscerd))
 - Add delete integration option [\#100](https://github.com/apache/camel-k/pull/100) ([dmvolod](https://github.com/dmvolod))
diff --git a/config/crd/bases/camel.apache.org_kameletbindings.yaml b/config/crd/bases/camel.apache.org_kameletbindings.yaml
index c9a8b8724..60ac3ba49 100644
--- a/config/crd/bases/camel.apache.org_kameletbindings.yaml
+++ b/config/crd/bases/camel.apache.org_kameletbindings.yaml
@@ -63,6 +63,11 @@ spec:
           spec:
             description: KameletBindingSpec --
             properties:
+              errorHandler:
+                description: ErrorHandler is an optional handler called upon an error
+                  occuring in the integration
+                type: object
+                x-kubernetes-preserve-unknown-fields: true
               integration:
                 description: Integration is an optional integration used to specify
                   custom parameters
diff --git a/deploy/olm-catalog/camel-k-dev/1.4.0/camel.apache.org_kameletbindings.yaml b/deploy/olm-catalog/camel-k-dev/1.4.0/camel.apache.org_kameletbindings.yaml
index c9a8b8724..2b78d2f58 100644
--- a/deploy/olm-catalog/camel-k-dev/1.4.0/camel.apache.org_kameletbindings.yaml
+++ b/deploy/olm-catalog/camel-k-dev/1.4.0/camel.apache.org_kameletbindings.yaml
@@ -63,6 +63,11 @@ spec:
           spec:
             description: KameletBindingSpec --
             properties:
+              errorHandler:
+                description: ErrorHandler is an optional handler called upon an error
+                  occuring in the integration
+                type: object
+                x-kubernetes-preserve-unknown-fields: true
               integration:
                 description: Integration is an optional integration used to specify
                   custom parameters
@@ -84,6 +89,21 @@ spec:
                     items:
                       type: string
                     type: array
+                  errorHandler:
+                    description: ErrorHandlerSpec respresents an integration error
+                      handler to be used as default at runtime
+                    properties:
+                      parameters:
+                        description: ErrorHandlerParameters is an unstructured object
+                          representing the configuration parameters available for
+                          an error handler
+                        type: object
+                        x-kubernetes-preserve-unknown-fields: true
+                      type:
+                        type: string
+                      uri:
+                        type: string
+                    type: object
                   flows:
                     items:
                       description: Flow is an unstructured object representing a Camel
diff --git a/deploy/olm-catalog/camel-k-dev/1.5.0-snapshot/camel.apache.org_kameletbindings.yaml b/deploy/olm-catalog/camel-k-dev/1.5.0-snapshot/camel.apache.org_kameletbindings.yaml
index c9a8b8724..60ac3ba49 100644
--- a/deploy/olm-catalog/camel-k-dev/1.5.0-snapshot/camel.apache.org_kameletbindings.yaml
+++ b/deploy/olm-catalog/camel-k-dev/1.5.0-snapshot/camel.apache.org_kameletbindings.yaml
@@ -63,6 +63,11 @@ spec:
           spec:
             description: KameletBindingSpec --
             properties:
+              errorHandler:
+                description: ErrorHandler is an optional handler called upon an error
+                  occuring in the integration
+                type: object
+                x-kubernetes-preserve-unknown-fields: true
               integration:
                 description: Integration is an optional integration used to specify
                   custom parameters
diff --git a/deploy/traits.yaml b/deploy/traits.yaml
index 75522d267..000289e95 100755
--- a/deploy/traits.yaml
+++ b/deploy/traits.yaml
@@ -271,6 +271,22 @@ traits:
     type: bool
     description: Enables injection of `NAMESPACE` and `POD_NAME` environment variables
       (default `true`)
+- name: error-handler
+  platform: true
+  profiles:
+  - Kubernetes
+  - Knative
+  - OpenShift
+  description: The error-handler is a platform trait used to inject Error Handler
+    source into the integration runtime.
+  properties:
+  - name: enabled
+    type: bool
+    description: Can be used to enable or disable a trait. All traits share this common
+      property.
+  - name: ref
+    type: string
+    description: The error handler ref name provided or found in application properties
 - name: gc
   platform: false
   profiles:
@@ -285,7 +301,7 @@ traits:
     description: Can be used to enable or disable a trait. All traits share this common
       property.
   - name: discovery-cache
-    type: ./pkg/trait.discoveryCacheType
+    type: camel-k/pkg/trait.discoveryCacheType
     description: Discovery client cache to be used, either `disabled`, `disk` or `memory`
       (default `memory`)
 - name: ingress
@@ -545,6 +561,27 @@ traits:
   - name: auto
     type: bool
     description: Enable automatic discovery of all trait properties.
+- name: logging
+  platform: false
+  profiles:
+  - Kubernetes
+  - Knative
+  - OpenShift
+  description: This trait is used to control logging options (such as color)
+  properties:
+  - name: enabled
+    type: bool
+    description: Can be used to enable or disable a trait. All traits share this common
+      property.
+  - name: color
+    type: bool
+    description: Colorize the log output
+  - name: json
+    type: bool
+    description: Output the log in json format
+  - name: json-pretty-print
+    type: bool
+    description: Enable "pretty printing" of the json log
 - name: master
   platform: false
   profiles:
diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc
index ea9558a71..abc26c5fe 100644
--- a/docs/modules/ROOT/nav.adoc
+++ b/docs/modules/ROOT/nav.adoc
@@ -11,6 +11,7 @@
 *** xref:installation/registry/github.adoc[Github Packages]
 *** xref:installation/registry/gcr.adoc[Gcr.io]
 *** xref:installation/registry/icr.adoc[IBM Container Registry]
+** xref:installation/scheduling.adoc[Pod scheduling]
 * xref:running/running.adoc[Running]
 ** xref:running/dev-mode.adoc[Dev Mode]
 ** xref:running/run-from-github.adoc[Run from GitHub]
@@ -41,6 +42,7 @@
 ** xref:traits:deployer.adoc[Deployer]
 ** xref:traits:deployment.adoc[Deployment]
 ** xref:traits:environment.adoc[Environment]
+** xref:traits:error-handler.adoc[Error Handler]
 ** xref:traits:gc.adoc[Gc]
 ** xref:traits:ingress.adoc[Ingress]
 ** xref:traits:istio.adoc[Istio]
@@ -49,6 +51,7 @@
 ** xref:traits:kamelets.adoc[Kamelets]
 ** xref:traits:knative-service.adoc[Knative Service]
 ** xref:traits:knative.adoc[Knative]
+** xref:traits:logging.adoc[Logging]
 ** xref:traits:master.adoc[Master]
 ** xref:traits:openapi.adoc[Openapi]
 ** xref:traits:owner.adoc[Owner]
diff --git a/docs/modules/ROOT/pages/installation/scheduling.adoc b/docs/modules/ROOT/pages/installation/scheduling.adoc
new file mode 100644
index 000000000..98253f039
--- /dev/null
+++ b/docs/modules/ROOT/pages/installation/scheduling.adoc
@@ -0,0 +1,42 @@
+[[scheduling-infra-pod]]
+= Scheduling infrastructure Pods and Resource managment
+
+During the installation procedure you will be able to provide information on how to best "operationalize" your infrastructure. Through the configuration of `--node-selector`, `--toleration` and `--operator-resources` you will be able to drive the operator `Pod`s scheduling and to be able to assign resources.
+
+The usage of these advanced properties assumes you're familiar with the https://kubernetes.io/docs/concepts/scheduling-eviction/[Kubernetes Scheduling] concepts and configurations.
+
+NOTE: the aforementioned flags setting will work both with `OLM` installation and regular installation.
+
+[[scheduling-infra-pod-scheduling]]
+== Scheduling
+
+=== Node Selectors
+The most basic operation we provide is to let you assign Camel K operator `Pod`s to a specific cluster `Node` via `--node-selector` option. The functionality is based on https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/[`NodeSelector` Kubernetes feature]. As an example, you can schedule Camel K infra `Pod`s to a specific `Node` of your cluster:
+
+```
+kamel install --node-selector kubernetes.io/hostname=ip-172-20-114-199.ec2.internal ...
+```
+
+The option will accept any `key=value` pair as specified and supported by Kubernetes. You can specify more than one `node-selector`.
+
+=== Tolerations
+The `--toleration` option will let you tolerate a Camel K infra `Pod` to support any matching `Taint` according the https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/[`Taint` and `Toleration` Kubernetes feature]. As an example, let's suppose we have a node tainted as "dedicated=camel-k:NoSchedule". In order to allow the infra `Pod`s to be scheduled on that `Node` we can provide the following option during installation procedure:
+
+```
+kamel install --toleration dedicated=camel-k:NoSchedule ...
+```
+
+The option accept a value in the following format `Key[=Value]:Effect[:Seconds]` where the values in squared bracket are considered optional and `Effect` must admit any of the `Taint`s accepted values: `NoSchedule`, `PreferNoSchedule`, `NoExecute`. You can specify more than one `toleration`.
+
+[[scheduling-infra-pod-resources]]
+== Resources
+
+While installing the Camel K operator, you can also specify the resources requests and limits to assign to the operator `Pod` with `--operator-resources` option. The option will expect the configuration as required by https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/[Kubernetes Resource managment]. 
+
+```
+kamel install --operator-resources requests.cpu=256m --operator-resources limits.cpu=500m --operator-resources limits.memory=512Mi ...
+```
+
+The value expected by the option are in the form `requestType.requestResource=value` where `requestType` must be either `requests` or `limits`, `requestResource` must be either `cpu` or `memory` and `value` expressed in the numeric value as expected by the resource. You can specify more than one `operator-resources`.
+
+NOTE: if you specify a limit, but does not specify a request, Kubernetes automatically assigns a request that matches the limit.
\ No newline at end of file
diff --git a/docs/modules/ROOT/pages/kamelets/kameletbindings-error-handler.adoc b/docs/modules/ROOT/pages/kamelets/kameletbindings-error-handler.adoc
new file mode 100644
index 000000000..fe3f1cef2
--- /dev/null
+++ b/docs/modules/ROOT/pages/kamelets/kameletbindings-error-handler.adoc
@@ -0,0 +1,156 @@
+[[kameletbindings-error-handler]]
+= Kamelet Bindings Error Handler
+
+`Kamelet Binding`s offer a mechanism to specify an error policy to adopt in case an event produced by a `source` or consumed by a `sink`. Through the definition of an `errorHandler` you will be able to apply certain logic to the failing event, such as simply logging, ignoring the event or posting the event to a `Dead Letter Channel`.
+
+[source,yaml]
+----
+apiVersion: camel.apache.org/v1alpha1
+kind: KameletBinding
+metadata:
+  name: my-kamelet-binding
+spec:
+  source: # <1>
+...
+  sink: # <2>
+...
+  errorHandler: # <3>
+----
+<1> Reference to the source that provides data
+<2> Reference to the sink where data should be sent to
+<3> Error Handler Configuration
+
+[[kameletbindings-error-handler-types]]
+== Error Handler Types
+
+We have different types of error handler: `ǹone`, `log`, `dead-letter-channel`, `bean`, `ref`. The `errorHandler` parameter is optional. The runtime will use the configuration to create an https://camel.apache.org/manual/latest/error-handler.html[Error Handler] as specified by Apache Camel.
+
+[[kameletbindings-error-handler-none]]
+=== No error handler
+
+There may be certain cases where you want to just ignore any failure happening on your integration. In this situation just use a `ǹone` error handler. Under the hood the configuration will create a https://camel.apache.org/manual/latest/error-handler.html#ErrorHandler-NoErrorHandler[`No` error handler builder]. 
+
+[source,yaml]
+----
+apiVersion: camel.apache.org/v1alpha1
+kind: KameletBinding
+metadata:
+  name: my-kamelet-binding
+spec:
+  source:
+...
+  sink: 
+...
+  errorHandler: 
+    none: # <1>
+----
+<1> `none` error handler does not expect any configuration
+
+[[kameletbindings-error-handler-log]]
+=== Log error handler
+
+Apache Camel offers a default behavior for handling any failure: log to standard output. However you can use the `log` error handler to specify other behaviors such as redelivery or delay policy. Under the hood the configuration will create a https://camel.apache.org/manual/latest/error-handler.html#_defaulterrorhandler[`Default` error handler builder].
+
+
+[source,yaml]
+----
+apiVersion: camel.apache.org/v1alpha1
+kind: KameletBinding
+metadata:
+  name: my-kamelet-binding
+spec:
+  source:
+...
+  sink: 
+...
+  errorHandler: 
+    log:
+      parameters: # <1>
+        maximumRedeliveries: 3
+        redeliveryDelay: 2000
+----
+<1> Parameters belonging to the `log` error handler type
+
+[[kameletbindings-error-handler-dlc]]
+=== Dead Letter Channel error handler
+
+The `Dead Letter Channel` is probably the most interesting error handler type as it allows you to redirect any failing event to any other component, such as a third party URI, a queue or even another `Kamelet` which will be performing certain logic with the failing event. Under the hood the configuration will create a https://camel.apache.org/manual/latest/error-handler.html#_dead_letter_channel[`Dead Letter Channel` error handler builder].
+
+[source,yaml]
+----
+apiVersion: camel.apache.org/v1alpha1
+kind: KameletBinding
+metadata:
+  name: my-kamelet-binding
+spec:
+  source:
+...
+  sink: 
+...
+  errorHandler: 
+    dead-letter-channel:
+      endpoint: 
+        ref: # <1>
+          kind: Kamelet
+          apiVersion: camel.apache.org/v1alpha1
+          name: error-handler
+        properties:
+          message: "ERROR!" # <2>
+          ...
+      parameters:
+        maximumRedeliveries: 1 # <3>
+        ... 
+----
+<1> You can use `ref` or `uri`. `ref` will be interpreted by the operator according the `kind`, `apiVersion` and `name`. You can use any `Kamelet`, `KafkaTopic` channel or `Knative` destination.
+<2> Properties belonging to the endpoint (in this example, to the `Kamelet` named error handler)
+<3> Parameters belonging to the `dead-letter-channel` error handler type
+
+[[kameletbindings-error-handler-bean]]
+=== Bean error handler
+
+With the `Bean` error handler you can extend the functionality of the Error Handler by providing a custom bean to be used as Error Handler.
+
+[source,yaml]
+----
+apiVersion: camel.apache.org/v1alpha1
+kind: KameletBinding
+metadata:
+  name: my-kamelet-binding
+spec:
+  source:
+...
+  sink: 
+...
+  errorHandler: 
+    bean:
+      type: "org.apache.camel.builder.DeadLetterChannelBuilder" # <1>
+      properties: # <2>
+        deadLetterUri: log:error
+        ... 
+----
+<1> Fully qualified name of the ErrorHandlerBuilder
+<2> Properties expected by your type
+
+[[kameletbindings-error-handler-ref]]
+=== Ref error handler
+
+With the `Ref` error handler you can use any `Bean` that is expected to be found in the Camel registry at runtime.
+
+[source,yaml]
+----
+apiVersion: camel.apache.org/v1alpha1
+kind: KameletBinding
+metadata:
+  name: my-kamelet-binding
+spec:
+  source:
+...
+  sink: 
+...
+  errorHandler: 
+    ref: my-custom-builder # <1>
+... 
+----
+<1> The name of the bean to be looked up at runtime
+
+NOTE: make sure to have the `ref` correctly bind at runtime.
\ No newline at end of file
diff --git a/docs/modules/ROOT/pages/kamelets/kamelets-user.adoc b/docs/modules/ROOT/pages/kamelets/kamelets-user.adoc
index 4a334cb4a..ef48761c5 100644
--- a/docs/modules/ROOT/pages/kamelets/kamelets-user.adoc
+++ b/docs/modules/ROOT/pages/kamelets/kamelets-user.adoc
@@ -356,6 +356,10 @@ This KameletBinding explicitly defines an URI where data is going to be pushed.
 NOTE: the `uri` option is also conventionally used in Knative to specify a non-kubernetes destination.
 To comply with the Knative specifications, in case an "http" or "https" URI is used, Camel will send https://cloudevents.io/[CloudEvents] to the destination.
 
+=== Error Handling
+
+You can configure an error handler in order to specify what to do when some event ends up with failure. See xref:kamelets/kameletbindings-error-handler.adoc[Kamelet Bindings Error Handler User Guide] for more detail.
+
 [[kamelets-specification]]
 == Kamelet Specification
 
diff --git a/docs/modules/ROOT/pages/kamelets/kamelets.adoc b/docs/modules/ROOT/pages/kamelets/kamelets.adoc
index 6ba3ff5cc..c0d0327b7 100644
--- a/docs/modules/ROOT/pages/kamelets/kamelets.adoc
+++ b/docs/modules/ROOT/pages/kamelets/kamelets.adoc
@@ -4,4 +4,5 @@
 This section of the documentation contains information about Kamelets from both a user and a developer point of view:
 
 - The xref:kamelets/kamelets-user.adoc[Kamelets User Guide] is for users that want to use Kamelets for connecting systems with their applications
+- The xref:kamelets/kameletbindings-error-handler.adoc[Kamelet Bindings Error Handler User Guide] explains how to configure an error handler on a `Kamelet Binding`
 - The xref:kamelets/kamelets-dev.adoc[Kamelets Developer Guide] is a reference for developers that want to create new Kamelets and share them with users
diff --git a/docs/modules/traits/pages/error-handler.adoc b/docs/modules/traits/pages/error-handler.adoc
new file mode 100755
index 000000000..7ddfd172c
--- /dev/null
+++ b/docs/modules/traits/pages/error-handler.adoc
@@ -0,0 +1,36 @@
+= Error Handler Trait
+
+// Start of autogenerated code - DO NOT EDIT! (description)
+The error-handler is a platform trait used to inject Error Handler source into the integration runtime.
+
+
+This trait is available in the following profiles: **Kubernetes, Knative, OpenShift**.
+
+WARNING: The error-handler trait is a *platform trait*: disabling it may compromise the platform functionality.
+
+// End of autogenerated code - DO NOT EDIT! (description)
+// Start of autogenerated code - DO NOT EDIT! (configuration)
+== Configuration
+
+Trait properties can be specified when running any integration with the CLI:
+[source,console]
+----
+$ kamel run --trait error-handler.[key]=[value] --trait error-handler.[key2]=[value2] integration.groovy
+----
+The following configuration options are available:
+
+[cols="2m,1m,5a"]
+|===
+|Property | Type | Description
+
+| error-handler.enabled
+| bool
+| Can be used to enable or disable a trait. All traits share this common property.
+
+| error-handler.ref
+| string
+| The error handler ref name provided or found in application properties
+
+|===
+
+// End of autogenerated code - DO NOT EDIT! (configuration)
diff --git a/docs/modules/traits/pages/gc.adoc b/docs/modules/traits/pages/gc.adoc
index 375057d57..c1a693780 100755
--- a/docs/modules/traits/pages/gc.adoc
+++ b/docs/modules/traits/pages/gc.adoc
@@ -26,7 +26,7 @@ The following configuration options are available:
 | Can be used to enable or disable a trait. All traits share this common property.
 
 | gc.discovery-cache
-| ./pkg/trait.discoveryCacheType
+| camel-k/pkg/trait.discoveryCacheType
 | Discovery client cache to be used, either `disabled`, `disk` or `memory` (default `memory`)
 
 |===
diff --git a/docs/modules/traits/pages/logging.adoc b/docs/modules/traits/pages/logging.adoc
new file mode 100755
index 000000000..a8981743c
--- /dev/null
+++ b/docs/modules/traits/pages/logging.adoc
@@ -0,0 +1,42 @@
+= Logging Trait
+
+// Start of autogenerated code - DO NOT EDIT! (description)
+This trait is used to control logging options (such as color)
+
+
+This trait is available in the following profiles: **Kubernetes, Knative, OpenShift**.
+
+// End of autogenerated code - DO NOT EDIT! (description)
+// Start of autogenerated code - DO NOT EDIT! (configuration)
+== Configuration
+
+Trait properties can be specified when running any integration with the CLI:
+[source,console]
+----
+$ kamel run --trait logging.[key]=[value] --trait logging.[key2]=[value2] integration.groovy
+----
+The following configuration options are available:
+
+[cols="2m,1m,5a"]
+|===
+|Property | Type | Description
+
+| logging.enabled
+| bool
+| Can be used to enable or disable a trait. All traits share this common property.
+
+| logging.color
+| bool
+| Colorize the log output
+
+| logging.json
+| bool
+| Output the log in json format
+
+| logging.json-pretty-print
+| bool
+| Enable "pretty printing" of the json log
+
+|===
+
+// End of autogenerated code - DO NOT EDIT! (configuration)
diff --git a/docs/modules/traits/pages/toleration.adoc b/docs/modules/traits/pages/toleration.adoc
index 07f8cb9f9..d3b3e88f6 100755
--- a/docs/modules/traits/pages/toleration.adoc
+++ b/docs/modules/traits/pages/toleration.adoc
@@ -43,3 +43,20 @@ The following configuration options are available:
 |===
 
 // End of autogenerated code - DO NOT EDIT! (configuration)
+
+== Examples
+
+* To tolerate the integration pod(s) to be scheduled on the master node:
++
+[source,console]
+$ kamel run -t toleration.taints="node-role.kubernetes.io/master:NoSchedule" ...
+
+* To tolerate the integration pod(s) executing on a node with network not available for 300 seconds:
++
+[source,console]
+$ kamel run -t toleration.taints="node.kubernetes.io/network-unavailable:NoExecute:300" ...
+
+* To tolerate the integration pod(s) to be scheduled on a node with a disk of SSD type:
++
+[source,console]
+$ kamel run -t toleration.taints="disktype=ssd:PreferNoSchedule" ...
\ No newline at end of file
diff --git a/examples/kamelets/error-handler/error-handler.kamelet.yaml b/examples/kamelets/error-handler/error-handler.kamelet.yaml
new file mode 100644
index 000000000..a5aa060f9
--- /dev/null
+++ b/examples/kamelets/error-handler/error-handler.kamelet.yaml
@@ -0,0 +1,40 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+apiVersion: camel.apache.org/v1alpha1
+kind: Kamelet
+metadata:
+  name: error-handler
+spec:
+  definition:
+    title: "Error Log Sink"
+    description: "Error logger channel"
+    required:
+      - message
+    properties:
+      message:
+        title: Message
+        description: The message to log
+        type: string
+        example: "error while checking the source"    
+  flow:
+    from:
+      uri: kamelet:source
+      steps:
+      - set-body:
+          constant: "{{message}}"
+      - to: "log:error-sink"  
diff --git a/examples/kamelets/error-handler/incremental-id-source.kamelet.yaml b/examples/kamelets/error-handler/incremental-id-source.kamelet.yaml
new file mode 100644
index 000000000..ee475da99
--- /dev/null
+++ b/examples/kamelets/error-handler/incremental-id-source.kamelet.yaml
@@ -0,0 +1,51 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+apiVersion: camel.apache.org/v1alpha1
+kind: Kamelet
+metadata:
+  name: incremental-id-source
+  labels:
+    camel.apache.org/kamelet.type: "source"
+spec:
+  definition:
+    title: "Incremental ID Source"
+    description: "Produces periodic events with an incremental ID and fails when the ID contains any 0 character"
+    properties:
+      period:
+        title: Period
+        description: The interval between two events
+        type: integer
+        default: 1000
+  types:
+    out:
+      mediaType: text/plain
+  flow:
+    from:
+      uri: timer:tick
+      parameters:
+        period: "{{period}}"
+      steps:
+      - set-body:
+          simple: "Producing message #${exchangeProperty.CamelTimerCounter}"
+      - choice:
+          when:
+          - simple: "${bodyAs(String)} contains 0"
+            steps:
+            - set-body:
+                simple: "${mandatoryBodyAs(Boolean)}"
+      - to: "kamelet:sink"                
diff --git a/examples/kamelets/error-handler/kamelet-binding-error-handler.yaml b/examples/kamelets/error-handler/kamelet-binding-error-handler.yaml
new file mode 100644
index 000000000..7a935d6d4
--- /dev/null
+++ b/examples/kamelets/error-handler/kamelet-binding-error-handler.yaml
@@ -0,0 +1,54 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+apiVersion: camel.apache.org/v1alpha1
+kind: KameletBinding
+metadata:
+  name: kamelet-binding-error-handler
+spec:
+  source:
+    ref:
+      kind: Kamelet
+      apiVersion: camel.apache.org/v1alpha1
+      name: incremental-id-source
+  sink:
+    ref:
+      kind: Kamelet
+      apiVersion: camel.apache.org/v1alpha1
+      name: log-sink
+  errorHandler:   
+#    log:
+#      parameters:
+#        maximumRedeliveries: 3
+#        redeliveryDelay: 2000      
+#    ref: "something"
+#    bean:
+#      type: "org.apache.camel.builder.DeadLetterChannelBuilder"
+#      properties:
+#        deadLetterUri: log:error
+    dead-letter-channel:
+      endpoint:
+        ref:
+          kind: Kamelet
+          apiVersion: camel.apache.org/v1alpha1
+          name: error-handler
+        properties:
+          message: "ERROR!"
+      parameters:
+        maximumRedeliveries: 3
+        redeliveryDelay: 2000    
+    
diff --git a/examples/kamelets/error-handler/log-sink.kamelet.yaml b/examples/kamelets/error-handler/log-sink.kamelet.yaml
new file mode 100644
index 000000000..aa11481f4
--- /dev/null
+++ b/examples/kamelets/error-handler/log-sink.kamelet.yaml
@@ -0,0 +1,32 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+apiVersion: camel.apache.org/v1alpha1
+kind: Kamelet
+metadata:
+  name: log-sink
+  labels:
+    camel.apache.org/kamelet.type: "sink"
+spec:
+  definition:
+    title: "Regular Log Sink"
+    description: "Consume events from a channel"  
+  flow:
+    from:
+      uri: kamelet:source
+      steps:
+      - to: "log:ok"
diff --git a/examples/kamelets/error-handler/readme.md b/examples/kamelets/error-handler/readme.md
new file mode 100644
index 000000000..42293cd1c
--- /dev/null
+++ b/examples/kamelets/error-handler/readme.md
@@ -0,0 +1,71 @@
+# Kamelets Binding Error Handler example
+This example shows how to create a simple _source_ `Kamelet` which sends periodically events (and certain failures). The events are consumed by a log _sink_ in a `KameletBinding`. With the support of the `ErrorHandler` we will be able to redirect all errors to a `Dead Letter Channel` _error-handler_ `Kamelet`.
+
+## Incremental ID Source Kamelet
+First of all, you must install the _incremental-id-source_ Kamelet defined in `incremental-id-source.kamelet.yaml` file. This source will emit events every second with an autoincrement counter that will be forced to fail when the number 0 is caught. With this trick, we will simulate possible event faults.
+```
+$ kubectl apply -f incremental-id-source.kamelet.yaml
+```
+You can check the newly created `kamelet` checking the list of kamelets available:
+```
+$ kubectl get kamelets
+
+NAME                            PHASE
+incremental-id-source           Ready
+```
+## Log Sink Kamelet
+Now it's the turn of installing the log-sink_ Kamelet defined in `log-sink.kamelet.yaml` file:
+```
+$ kubectl apply -f log-sink.kamelet.yaml
+```
+You can check the newly created `kamelet` checking the list of kamelets available:
+```
+$ kubectl get kamelets
+
+NAME                    PHASE
+log-sink                Ready
+incremental-id-source   Ready
+```
+## Error handler Kamelet
+We finally install an error handler as specified in `error-handler.kamelet.yaml` file. This is a simple logger, but you can use any endpoint to collect and store the failing events.
+```
+$ kubectl apply -f error-handler.kamelet.yaml
+```
+You can check the newly created `kamelet` checking the list of kamelets available:
+```
+$ kubectl get kamelets
+
+NAME                    PHASE
+error-handler           Ready
+log-sink                Ready
+incremental-id-source   Ready
+```
+## Error Handler Kamelet Binding
+We can create a `KameletBinding` which is started by the _incremental-id-source_ `Kamelet` and log events to _log-sink_ `Kamelet`. As this will sporadically fail, we can configure an _errorHandler_ with the _error-handler_ `Kamelet` as **Dead Letter Channel**. We want to configure also some redelivery policies. We can declare it as in `kamelet-binding-error-handler.yaml` file:
+```
+...
+  errorHandler:
+    dead-letter-channel:
+      endpoint:
+        ref:
+          kind: Kamelet
+          apiVersion: camel.apache.org/v1alpha1
+          name: error-handler
+        properties:
+          message: "ERROR!"
+      parameters:
+        maximumRedeliveries: 3
+        redeliveryDelay: 2000
+```
+Execute the following command to start the `Integration`:
+```
+kubectl apply -f kamelet-binding-error-handler.yaml
+```
+As soon as the `Integration` starts, it will log the events on the `ok` log channel and errors on the `error` log channel:
+```
+[1] 2021-04-21 13:03:43,773 INFO  [sink] (Camel (camel-1) thread #0 - timer://tick) Exchange[ExchangePattern: InOnly, BodyType: String, Body: Producing message #8]
+[1] 2021-04-21 13:03:44,774 INFO  [sink] (Camel (camel-1) thread #0 - timer://tick) Exchange[ExchangePattern: InOnly, BodyType: String, Body: Producing message #9]
+[1] 2021-04-21 13:03:45,898 INFO  [error-sink] (Camel (camel-1) thread #0 - timer://tick) Exchange[ExchangePattern: InOnly, BodyType: String, Body: ERROR!]
+[1] 2021-04-21 13:09:46,775 INFO  [sink] (Camel (camel-1) thread #0 - timer://tick) Exchange[ExchangePattern: InOnly, BodyType: String, Body: Producing message #11]
+```
+This example is useful to guide you through the configuration of an error handler. In a production environment you will likely configure the error handler `Kamelet` pointing to a persistent queue.
\ No newline at end of file
diff --git a/helm/camel-k/crds/crd-kamelet-binding.yaml b/helm/camel-k/crds/crd-kamelet-binding.yaml
index c9a8b8724..60ac3ba49 100644
--- a/helm/camel-k/crds/crd-kamelet-binding.yaml
+++ b/helm/camel-k/crds/crd-kamelet-binding.yaml
@@ -63,6 +63,11 @@ spec:
           spec:
             description: KameletBindingSpec --
             properties:
+              errorHandler:
+                description: ErrorHandler is an optional handler called upon an error
+                  occuring in the integration
+                type: object
+                x-kubernetes-preserve-unknown-fields: true
               integration:
                 description: Integration is an optional integration used to specify
                   custom parameters
diff --git a/pkg/apis/camel/v1/common_types.go b/pkg/apis/camel/v1/common_types.go
index a94d6042d..e5b327b82 100644
--- a/pkg/apis/camel/v1/common_types.go
+++ b/pkg/apis/camel/v1/common_types.go
@@ -206,8 +206,9 @@ type SourceSpec struct {
 type SourceType string
 
 const (
-	SourceTypeDefault  SourceType = ""
-	SourceTypeTemplate SourceType = "template"
+	SourceTypeDefault      SourceType = ""
+	SourceTypeTemplate     SourceType = "template"
+	SourceTypeErrorHandler SourceType = "errorHandler"
 )
 
 // DataSpec --
diff --git a/pkg/apis/camel/v1/integration_types_support.go b/pkg/apis/camel/v1/integration_types_support.go
index 53705c90b..f7e505e43 100644
--- a/pkg/apis/camel/v1/integration_types_support.go
+++ b/pkg/apis/camel/v1/integration_types_support.go
@@ -131,6 +131,19 @@ func (in *IntegrationSpec) AddDependency(dependency string) {
 	in.Dependencies = append(in.Dependencies, newDep)
 }
 
+// GetConfigurationProperty returns a configuration property
+func (in *IntegrationSpec) GetConfigurationProperty(property string) string {
+	for _, confSpec := range in.Configuration {
+		if confSpec.Type == "property" && strings.HasPrefix(confSpec.Value, property) {
+			splitConf := strings.Split(confSpec.Value, "=")
+			if len(splitConf) > 1 {
+				return splitConf[1]
+			}
+		}
+	}
+	return ""
+}
+
 // AddOrReplaceGeneratedResources --
 func (in *IntegrationStatus) AddOrReplaceGeneratedResources(resources ...ResourceSpec) {
 	newResources := make([]ResourceSpec, 0)
diff --git a/pkg/apis/camel/v1alpha1/error_handler_types.go b/pkg/apis/camel/v1alpha1/error_handler_types.go
new file mode 100644
index 000000000..d60074a99
--- /dev/null
+++ b/pkg/apis/camel/v1alpha1/error_handler_types.go
@@ -0,0 +1,231 @@
+/*
+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 v1alpha1
+
+import (
+	"encoding/json"
+	"fmt"
+
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+)
+
+// ErrorHandlerRefName --
+const ErrorHandlerRefName = "camel.k.errorHandler.ref"
+
+// ErrorHandlerRefDefaultName --
+const ErrorHandlerRefDefaultName = "defaultErrorHandler"
+
+// ErrorHandlerAppPropertiesPrefix --
+const ErrorHandlerAppPropertiesPrefix = "camel.beans.defaultErrorHandler"
+
+// ErrorHandlerSpec represents an unstructured object for an error handler
+type ErrorHandlerSpec struct {
+	v1.RawMessage `json:",omitempty"`
+}
+
+// ErrorHandlerParameters represent an unstructured object for error handler parameters
+type ErrorHandlerParameters struct {
+	v1.RawMessage `json:",omitempty"`
+}
+
+// BeanProperties represent an unstructured object properties to be set on a bean
+type BeanProperties struct {
+	v1.RawMessage `json:",omitempty"`
+}
+
+// +kubebuilder:object:generate=false
+
+// ErrorHandler is a generic interface that represent any type of error handler specification
+type ErrorHandler interface {
+	Type() ErrorHandlerType
+	Endpoint() *Endpoint
+	Configuration() (map[string]interface{}, error)
+}
+
+type baseErrorHandler struct {
+}
+
+// Type --
+func (e baseErrorHandler) Type() ErrorHandlerType {
+	return errorHandlerTypeBase
+}
+
+// Endpoint --
+func (e baseErrorHandler) Endpoint() *Endpoint {
+	return nil
+}
+
+// Configuration --
+func (e baseErrorHandler) Configuration() (map[string]interface{}, error) {
+	return nil, nil
+}
+
+// ErrorHandlerNone --
+type ErrorHandlerNone struct {
+	baseErrorHandler
+}
+
+// Type --
+func (e ErrorHandlerNone) Type() ErrorHandlerType {
+	return ErrorHandlerTypeNone
+}
+
+// Configuration --
+func (e ErrorHandlerNone) Configuration() (map[string]interface{}, error) {
+	return map[string]interface{}{
+		ErrorHandlerAppPropertiesPrefix: "#class:org.apache.camel.builder.NoErrorHandlerBuilder",
+		ErrorHandlerRefName:             ErrorHandlerRefDefaultName,
+	}, nil
+}
+
+// ErrorHandlerLog represent a default (log) error handler type
+type ErrorHandlerLog struct {
+	ErrorHandlerNone
+	Parameters *ErrorHandlerParameters `json:"parameters,omitempty"`
+}
+
+// Type --
+func (e ErrorHandlerLog) Type() ErrorHandlerType {
+	return ErrorHandlerTypeLog
+}
+
+// Configuration --
+func (e ErrorHandlerLog) Configuration() (map[string]interface{}, error) {
+	properties, err := e.ErrorHandlerNone.Configuration()
+	if err != nil {
+		return nil, err
+	}
+	properties[ErrorHandlerAppPropertiesPrefix] = "#class:org.apache.camel.builder.DefaultErrorHandlerBuilder"
+
+	if e.Parameters != nil {
+		var parameters map[string]interface{}
+		err := json.Unmarshal(e.Parameters.RawMessage, &parameters)
+		if err != nil {
+			return nil, err
+		}
+		for key, value := range parameters {
+			properties[ErrorHandlerAppPropertiesPrefix+"."+key] = value
+		}
+	}
+
+	return properties, nil
+}
+
+// ErrorHandlerDeadLetterChannel represents a dead letter channel error handler type
+type ErrorHandlerDeadLetterChannel struct {
+	ErrorHandlerLog
+	DLCEndpoint *Endpoint `json:"endpoint,omitempty"`
+}
+
+// Type --
+func (e ErrorHandlerDeadLetterChannel) Type() ErrorHandlerType {
+	return ErrorHandlerTypeDeadLetterChannel
+}
+
+// Endpoint --
+func (e ErrorHandlerDeadLetterChannel) Endpoint() *Endpoint {
+	return e.DLCEndpoint
+}
+
+// Configuration --
+func (e ErrorHandlerDeadLetterChannel) Configuration() (map[string]interface{}, error) {
+	properties, err := e.ErrorHandlerLog.Configuration()
+	if err != nil {
+		return nil, err
+	}
+	properties[ErrorHandlerAppPropertiesPrefix] = "#class:org.apache.camel.builder.DeadLetterChannelBuilder"
+
+	return properties, err
+}
+
+// ErrorHandlerRef represents a reference to an error handler builder available in the registry
+type ErrorHandlerRef struct {
+	baseErrorHandler
+	v1.RawMessage
+}
+
+// Type --
+func (e ErrorHandlerRef) Type() ErrorHandlerType {
+	return ErrorHandlerTypeRef
+}
+
+// Configuration --
+func (e ErrorHandlerRef) Configuration() (map[string]interface{}, error) {
+	var refName string
+	err := json.Unmarshal(e.RawMessage, &refName)
+	if err != nil {
+		return nil, err
+	}
+
+	properties := map[string]interface{}{
+		ErrorHandlerRefName: refName,
+	}
+
+	return properties, nil
+}
+
+// ErrorHandlerBean represents a bean error handler type
+type ErrorHandlerBean struct {
+	ErrorHandlerNone
+	BeanType       *string         `json:"type,omitempty"`
+	BeanProperties *BeanProperties `json:"properties,omitempty"`
+}
+
+// Type --
+func (e ErrorHandlerBean) Type() ErrorHandlerType {
+	return ErrorHandlerTypeBean
+}
+
+// Configuration --
+func (e ErrorHandlerBean) Configuration() (map[string]interface{}, error) {
+	properties, err := e.ErrorHandlerNone.Configuration()
+	if err != nil {
+		return nil, err
+	}
+	properties[ErrorHandlerAppPropertiesPrefix] = fmt.Sprintf("#class:%v", *e.BeanType)
+
+	if e.BeanProperties != nil {
+		var beanProperties map[string]interface{}
+		err := json.Unmarshal(e.BeanProperties.RawMessage, &beanProperties)
+		if err != nil {
+			return nil, err
+		}
+		for key, value := range beanProperties {
+			properties[ErrorHandlerAppPropertiesPrefix+"."+key] = value
+		}
+	}
+
+	return properties, err
+}
+
+// ErrorHandlerType --
+type ErrorHandlerType string
+
+const (
+	errorHandlerTypeBase ErrorHandlerType = ""
+	// ErrorHandlerTypeNone --
+	ErrorHandlerTypeNone ErrorHandlerType = "none"
+	// ErrorHandlerTypeLog --
+	ErrorHandlerTypeLog ErrorHandlerType = "log"
+	// ErrorHandlerTypeDeadLetterChannel --
+	ErrorHandlerTypeDeadLetterChannel ErrorHandlerType = "dead-letter-channel"
+	// ErrorHandlerTypeRef --
+	ErrorHandlerTypeRef ErrorHandlerType = "ref"
+	// ErrorHandlerTypeBean --
+	ErrorHandlerTypeBean ErrorHandlerType = "bean"
+)
diff --git a/pkg/apis/camel/v1alpha1/kamelet_binding_types.go b/pkg/apis/camel/v1alpha1/kamelet_binding_types.go
index 8fea2ac1b..cfe8779d1 100644
--- a/pkg/apis/camel/v1alpha1/kamelet_binding_types.go
+++ b/pkg/apis/camel/v1alpha1/kamelet_binding_types.go
@@ -32,6 +32,8 @@ type KameletBindingSpec struct {
 	Source Endpoint `json:"source,omitempty"`
 	// Sink is the destination of the integration defined by this binding
 	Sink Endpoint `json:"sink,omitempty"`
+	// ErrorHandler is an optional handler called upon an error occuring in the integration
+	ErrorHandler ErrorHandlerSpec `json:"errorHandler,omitempty"`
 	// Steps contains an optional list of intermediate steps that are executed between the Source and the Sink
 	Steps []Endpoint `json:"steps,omitempty"`
 }
@@ -51,9 +53,10 @@ type Endpoint struct {
 type EndpointType string
 
 const (
-	EndpointTypeSource EndpointType = "source"
-	EndpointTypeAction EndpointType = "action"
-	EndpointTypeSink   EndpointType = "sink"
+	EndpointTypeSource       EndpointType = "source"
+	EndpointTypeAction       EndpointType = "action"
+	EndpointTypeSink         EndpointType = "sink"
+	EndpointTypeErrorHandler EndpointType = "errorHandler"
 )
 
 // EndpointProperties is a key/value struct represented as JSON raw to allow numeric/boolean values
diff --git a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
index 71938f5dd..dd0e4ba6a 100644
--- a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
@@ -26,6 +26,26 @@ func (in *AuthorizationSpec) DeepCopy() *AuthorizationSpec {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BeanProperties) DeepCopyInto(out *BeanProperties) {
+	*out = *in
+	if in.RawMessage != nil {
+		in, out := &in.RawMessage, &out.RawMessage
+		*out = make(v1.RawMessage, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BeanProperties.
+func (in *BeanProperties) DeepCopy() *BeanProperties {
+	if in == nil {
+		return nil
+	}
+	out := new(BeanProperties)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Endpoint) DeepCopyInto(out *Endpoint) {
 	*out = *in
@@ -83,6 +103,151 @@ func (in *EndpointProperties) DeepCopy() *EndpointProperties {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ErrorHandlerBean) DeepCopyInto(out *ErrorHandlerBean) {
+	*out = *in
+	out.ErrorHandlerNone = in.ErrorHandlerNone
+	if in.BeanType != nil {
+		in, out := &in.BeanType, &out.BeanType
+		*out = new(string)
+		**out = **in
+	}
+	if in.BeanProperties != nil {
+		in, out := &in.BeanProperties, &out.BeanProperties
+		*out = new(BeanProperties)
+		(*in).DeepCopyInto(*out)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ErrorHandlerBean.
+func (in *ErrorHandlerBean) DeepCopy() *ErrorHandlerBean {
+	if in == nil {
+		return nil
+	}
+	out := new(ErrorHandlerBean)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ErrorHandlerDeadLetterChannel) DeepCopyInto(out *ErrorHandlerDeadLetterChannel) {
+	*out = *in
+	in.ErrorHandlerLog.DeepCopyInto(&out.ErrorHandlerLog)
+	if in.DLCEndpoint != nil {
+		in, out := &in.DLCEndpoint, &out.DLCEndpoint
+		*out = new(Endpoint)
+		(*in).DeepCopyInto(*out)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ErrorHandlerDeadLetterChannel.
+func (in *ErrorHandlerDeadLetterChannel) DeepCopy() *ErrorHandlerDeadLetterChannel {
+	if in == nil {
+		return nil
+	}
+	out := new(ErrorHandlerDeadLetterChannel)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ErrorHandlerLog) DeepCopyInto(out *ErrorHandlerLog) {
+	*out = *in
+	out.ErrorHandlerNone = in.ErrorHandlerNone
+	if in.Parameters != nil {
+		in, out := &in.Parameters, &out.Parameters
+		*out = new(ErrorHandlerParameters)
+		(*in).DeepCopyInto(*out)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ErrorHandlerLog.
+func (in *ErrorHandlerLog) DeepCopy() *ErrorHandlerLog {
+	if in == nil {
+		return nil
+	}
+	out := new(ErrorHandlerLog)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ErrorHandlerNone) DeepCopyInto(out *ErrorHandlerNone) {
+	*out = *in
+	out.baseErrorHandler = in.baseErrorHandler
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ErrorHandlerNone.
+func (in *ErrorHandlerNone) DeepCopy() *ErrorHandlerNone {
+	if in == nil {
+		return nil
+	}
+	out := new(ErrorHandlerNone)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ErrorHandlerParameters) DeepCopyInto(out *ErrorHandlerParameters) {
+	*out = *in
+	if in.RawMessage != nil {
+		in, out := &in.RawMessage, &out.RawMessage
+		*out = make(v1.RawMessage, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ErrorHandlerParameters.
+func (in *ErrorHandlerParameters) DeepCopy() *ErrorHandlerParameters {
+	if in == nil {
+		return nil
+	}
+	out := new(ErrorHandlerParameters)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ErrorHandlerRef) DeepCopyInto(out *ErrorHandlerRef) {
+	*out = *in
+	out.baseErrorHandler = in.baseErrorHandler
+	if in.RawMessage != nil {
+		in, out := &in.RawMessage, &out.RawMessage
+		*out = make(v1.RawMessage, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ErrorHandlerRef.
+func (in *ErrorHandlerRef) DeepCopy() *ErrorHandlerRef {
+	if in == nil {
+		return nil
+	}
+	out := new(ErrorHandlerRef)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ErrorHandlerSpec) DeepCopyInto(out *ErrorHandlerSpec) {
+	*out = *in
+	if in.RawMessage != nil {
+		in, out := &in.RawMessage, &out.RawMessage
+		*out = make(v1.RawMessage, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ErrorHandlerSpec.
+func (in *ErrorHandlerSpec) DeepCopy() *ErrorHandlerSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(ErrorHandlerSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *EventTypeSpec) DeepCopyInto(out *EventTypeSpec) {
 	*out = *in
@@ -370,6 +535,7 @@ func (in *KameletBindingSpec) DeepCopyInto(out *KameletBindingSpec) {
 	}
 	in.Source.DeepCopyInto(&out.Source)
 	in.Sink.DeepCopyInto(&out.Sink)
+	in.ErrorHandler.DeepCopyInto(&out.ErrorHandler)
 	if in.Steps != nil {
 		in, out := &in.Steps, &out.Steps
 		*out = make([]Endpoint, len(*in))
diff --git a/pkg/cmd/get.go b/pkg/cmd/get.go
index bf0f1300a..8d963edba 100644
--- a/pkg/cmd/get.go
+++ b/pkg/cmd/get.go
@@ -41,7 +41,7 @@ func newCmdGet(rootCmdOptions *RootCmdOptions) (*cobra.Command, *getCmdOptions)
 	cmd := cobra.Command{
 		Use:     "get [integration]",
 		Short:   "Get integrations deployed on Kubernetes",
-		Long:    `Get the status of integrations deployed on on Kubernetes.`,
+		Long:    `Get the status of integrations deployed on Kubernetes.`,
 		PreRunE: decode(&options),
 		RunE:    options.run,
 	}
diff --git a/pkg/controller/kameletbinding/common.go b/pkg/controller/kameletbinding/common.go
index 411bde8d2..5da336ad6 100644
--- a/pkg/controller/kameletbinding/common.go
+++ b/pkg/controller/kameletbinding/common.go
@@ -53,6 +53,7 @@ func createIntegrationFor(ctx context.Context, c client.Client, kameletbinding *
 			},
 		},
 	}
+
 	// start from the integration spec defined in the binding
 	if kameletbinding.Spec.Integration != nil {
 		it.Spec = *kameletbinding.Spec.Integration.DeepCopy()
@@ -79,6 +80,11 @@ func createIntegrationFor(ctx context.Context, c client.Client, kameletbinding *
 	if err != nil {
 		return nil, errors.Wrap(err, "could not determine sink URI")
 	}
+	// error handler is optional
+	errorHandler, err := maybeErrorHandler(kameletbinding.Spec.ErrorHandler, bindingContext)
+	if err != nil {
+		return nil, errors.Wrap(err, "could not determine error handler")
+	}
 
 	steps := make([]*bindings.Binding, 0, len(kameletbinding.Spec.Steps))
 	for idx, step := range kameletbinding.Spec.Steps {
@@ -93,10 +99,13 @@ func createIntegrationFor(ctx context.Context, c client.Client, kameletbinding *
 		steps = append(steps, stepBinding)
 	}
 
-	allBindings := make([]*bindings.Binding, 0, len(steps)+2)
+	allBindings := make([]*bindings.Binding, 0, len(steps)+3)
 	allBindings = append(allBindings, from)
 	allBindings = append(allBindings, steps...)
 	allBindings = append(allBindings, to)
+	if errorHandler != nil {
+		allBindings = append(allBindings, errorHandler)
+	}
 
 	propList := make([]string, 0)
 	for _, b := range allBindings {
@@ -129,17 +138,17 @@ func createIntegrationFor(ctx context.Context, c client.Client, kameletbinding *
 		"to": to.URI,
 	})
 
-	flow := map[string]interface{}{
+	flowFrom := map[string]interface{}{
 		"from": map[string]interface{}{
 			"uri":   from.URI,
 			"steps": dslSteps,
 		},
 	}
-	encodedFlow, err := json.Marshal(flow)
+	encodedFrom, err := json.Marshal(flowFrom)
 	if err != nil {
 		return nil, err
 	}
-	it.Spec.Flows = append(it.Spec.Flows, v1.Flow{RawMessage: encodedFlow})
+	it.Spec.Flows = append(it.Spec.Flows, v1.Flow{RawMessage: encodedFrom})
 
 	return &it, nil
 }
diff --git a/pkg/controller/kameletbinding/error_handler.go b/pkg/controller/kameletbinding/error_handler.go
new file mode 100644
index 000000000..5325324f0
--- /dev/null
+++ b/pkg/controller/kameletbinding/error_handler.go
@@ -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 kameletbinding
+
+import (
+	"encoding/json"
+	"fmt"
+
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+	"github.com/apache/camel-k/pkg/util/bindings"
+	"github.com/pkg/errors"
+)
+
+func maybeErrorHandler(errHandlConf v1alpha1.ErrorHandlerSpec, bindingContext bindings.BindingContext) (*bindings.Binding, error) {
+	var errorHandlerBinding *bindings.Binding
+	if errHandlConf.RawMessage != nil {
+		errorHandlerSpec, err := parseErrorHandler(errHandlConf.RawMessage)
+		if err != nil {
+			return nil, errors.Wrap(err, "could not parse error handler")
+		}
+		// We need to get the translated URI from any referenced resource (ie, kamelets)
+		if errorHandlerSpec.Type() == v1alpha1.ErrorHandlerTypeDeadLetterChannel {
+			errorHandlerBinding, err = bindings.Translate(bindingContext, bindings.EndpointContext{Type: v1alpha1.EndpointTypeErrorHandler}, *errorHandlerSpec.Endpoint())
+			if err != nil {
+				return nil, errors.Wrap(err, "could not determine error handler URI")
+			}
+		} else {
+			// Create a new binding otherwise in order to store error handler application properties
+			errorHandlerBinding = &bindings.Binding{
+				ApplicationProperties: make(map[string]string),
+			}
+		}
+
+		err = setErrorHandlerConfiguration(errorHandlerBinding, errorHandlerSpec)
+		if err != nil {
+			return nil, errors.Wrap(err, "could not set integration error handler")
+		}
+
+		return errorHandlerBinding, nil
+	}
+	return nil, nil
+}
+
+func parseErrorHandler(rawMessage v1.RawMessage) (v1alpha1.ErrorHandler, error) {
+	var properties map[v1alpha1.ErrorHandlerType]v1.RawMessage
+	err := json.Unmarshal(rawMessage, &properties)
+	if err != nil {
+		return nil, err
+	}
+	if len(properties) > 1 {
+		return nil, errors.Errorf("You must provide just 1 error handler, provided %d", len(properties))
+	}
+
+	for errHandlType, errHandlValue := range properties {
+		var dst v1alpha1.ErrorHandler
+		switch errHandlType {
+		case v1alpha1.ErrorHandlerTypeNone:
+			dst = new(v1alpha1.ErrorHandlerNone)
+		case v1alpha1.ErrorHandlerTypeLog:
+			dst = new(v1alpha1.ErrorHandlerLog)
+		case v1alpha1.ErrorHandlerTypeDeadLetterChannel:
+			dst = new(v1alpha1.ErrorHandlerDeadLetterChannel)
+		case v1alpha1.ErrorHandlerTypeRef:
+			dst = new(v1alpha1.ErrorHandlerRef)
+		case v1alpha1.ErrorHandlerTypeBean:
+			dst = new(v1alpha1.ErrorHandlerBean)
+		default:
+			return nil, errors.Errorf("Unknown error handler type %s", errHandlType)
+		}
+
+		err := json.Unmarshal(errHandlValue, dst)
+		if err != nil {
+			return nil, err
+		}
+
+		return dst, nil
+	}
+
+	return nil, errors.New("You must provide any supported error handler")
+}
+
+func setErrorHandlerConfiguration(errorHandlerBinding *bindings.Binding, errorHandler v1alpha1.ErrorHandler) error {
+	properties, err := errorHandler.Configuration()
+	if err != nil {
+		return err
+	}
+	for key, value := range properties {
+		errorHandlerBinding.ApplicationProperties[key] = fmt.Sprintf("%v", value)
+	}
+	if errorHandler.Type() == v1alpha1.ErrorHandlerTypeDeadLetterChannel && errorHandlerBinding.URI != "" {
+		errorHandlerBinding.ApplicationProperties[fmt.Sprintf("%s.deadLetterUri", v1alpha1.ErrorHandlerAppPropertiesPrefix)] = fmt.Sprintf("%v", errorHandlerBinding.URI)
+	}
+	return nil
+}
diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go
index 6b712ac54..94a6ac48e 100644
--- a/pkg/resources/resources.go
+++ b/pkg/resources/resources.go
@@ -144,7 +144,7 @@ var assets = func() http.FileSystem {
 			modTime:          time.Time{},
 			uncompressedSize: 2397,
 
-			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x55\xc1\x6e\xe3\x36\x10\xbd\xeb\x2b\x1e\xac\xcb\x2e\x10\xdb\xc9\x02\x05\x16\xea\x49\x4d\x9c\xc6\x68\x6a\x1b\x96\xb7\xc1\x9e\x0a\x9a\x1a\x4b\x44\x28\x8e\x4a\x52\xf6\xaa\x5f\x5f\x50\xb6\x1c\xdb\x9b\xa6\x3d\x04\x58\x9e\x2c\xcd\xcc\x9b\xf7\x66\x9e\xe8\x18\xc3\xf7\x3b\x51\x8c\x47\x25\xc9\x38\xca\xe1\x19\xbe\x24\xa4\xb5\x90\x25\x21\xe3\x8d\xdf\x09\x4b\xb8\xe7\xc6\xe4\xc2\x2b\x36\xf8\x90\x66\xf7\x1f\xd1\x98\x9c\x2c\xd8\x10\xd8\xa2\x62\x4b\x51\x0c\xc9\xc6\x5b\xb5\x6e\x3c\x5b\xe8\x3d\x20\x44\x61\x89\x2a\x32\xde\x8d\x80\x8c\xa8\x43\x9f\xcd\x57\xd3\xdb\x09\x36\x4a\x13\x72\xe5\xf6\x45\x94\x63\xa7\x7c\x19\xc5\xf0\xa5\x72\xd8\xb1\x7d\xc6\x86\x2d\x44\x9e\xab\xd0\x58\x68\x28\xb3\x61\x5b\xed\x69\x58\x2a\x84\xcd\x95\x29\x20\xb9\x6e\xad\x2a\x4a\x0f\xde\x19\xb2\xae\x54\xf5\x28\x8a\xb1\x0a\x32\xb2\xfb\x9e\x89\xdb\xc3\x76\x3d\x3d\xe3\x2b\x37\x07\x0d\x27\x72\x0f\x53\xb8\xc2\x1f\x64\x5d\x68\xf2\x69\x74\x1d\xc5\xf8\x10\x52\x06\x87\xe0\xe0\xe3\xcf\x68\xb9\x41\x25\x5a\x18\xf6\x68\x1c\x9d\x20\xd3\x37\x49\xb5\x87\x32\x90\x5c\xd5\x5a\x09\x23\xe9\x45\xd6\xb1\xc3\x08\x1d\x81\x80\xc1\x6b\x2f\x94\x81\xe8\x64\x80\x37\xa7\x69\x10\x3e\x8a\xa3\x18\xdd\x29\xbd\xaf\x93\xf1\x78\xb7\xdb\x8d\x44\x47\x77\xc4\xb6\x18\xf7\xea\xc6\x8f\xd3\xdb\xc9\x2c\x9b\x0c\x3b\xca\x51\x8c\x2f\x46\x93\x73\xb0\xf4\x57\xa3\x2c\xe5\x58\xb7\x10\x75\xad\x95\x14\x6b\x4d\xd0\x62\x17\x16\xd7\x6d\xa7\x5b\xba\x32\xd8\x59\xe5\x95\x29\xae\xe0\x0e\x5b\x8f\xe2\xb3\xed\xbc\x8c\xab\xa7\xa7\xdc\x59\x02\x1b\x08\x83\x41\x9a\x61\x9a\x0d\xf0\x4b\x9a\x4d\xb3\xab\x28\xc6\xd3\x74\xf5\x30\xff\xb2\xc2\x53\xba\x5c\xa6\xb3\xd5\x74\x92\x61\xbe\xc4\xed\x7c\x76\x37\x5d\x4d\xe7\xb3\x0c\xf3\x7b\xa4\xb3\xaf\xf8\x6d\x3a\xbb\xbb\x02\x29\x5f\x92\x05\x7d\xab\x6d\xe0\xcf\x16\x2a\x0c\x92\xf2\xb0\xd3\xde\x40\x3d\x81\xe0\x8f\xf0\xec\x6a\x92\x6a\xa3\x24\xb4\x30\x45\x23\x0a\x42\xc1\x5b\xb2\x26\xd8\xa3\x26\x5b\x29\x17\xd6\xe9\x20\x4c\x1e\xc5\xd0\xaa\x52\xbe\x73\x91\xfb\x5e\x54\x68\xf3\x9e\xdf\x56\x24\x6a\x75\xb0\x53\x12\x36\xe0\xc6\xdb\x9b\xe8\x59\x99\x3c\xc1\x1d\xd5\x9a\xdb\xf0\x71\x44\x15\x79\x91\x0b\x2f\x92\x08\x30\xa2\xa2\x04\x52\x54\xa4\x87\xcf\x43\xae\xc9\x0a\xcf\x36\x02\xb4\x58\x93\x76\x21\x05\x01\x29\xc1\xe0\x90\x34\xe8\x5e\x75\x0f\xa7\xde\x08\x16\x64\x43\xc6\x27\x38\xa2\x84\x49\x05\x04\x4b\x9d\x17\x5c\x82\x9b\x08\x70\xde\x0a\x4f\x45\xbb\xc7\xf6\x6d\x4d\x09\x96\x24\x2d\x09\x4f\x21\x4c\x9a\xa4\x67\xbb\x0f\x57\xc2\xcb\xf2\xf1\x84\xcb\x1b\x94\x3d\x55\xb5\x16\x9e\x0e\x95\x27\x2a\xc3\xd1\x67\x20\x6f\xc0\xec\xcf\xff\x12\xd8\x27\xbf\x32\xa0\x5e\x7b\xf7\x9b\xec\x56\x49\x4a\xa5\xe4\xc6\xf8\xd9\x5b\x8d\xc3\xb5\x26\x54\xb8\x59\x5e\x98\x0e\xff\x8b\x2b\xa0\x2a\x51\x50\x82\x9c\xe5\x33\xd9\x91\xe2\xf1\x9e\xf8\xf8\x50\x92\xdc\x8c\x7e\x1a\x5d\x0f\xb3\x59\xba\xc8\x1e\xe6\xab\xcb\xc2\x45\xa3\xf5\x82\xb5\x92\x6d\x82\xe9\x66\xc6\x7e\x61\xc9\x05\xa7\xbc\xe4\x49\xae\x2a\x61\xf2\xe4\xe4\x55\x20\xf6\x1c\xf0\x2f\xde\xbd\x42\xaf\x66\xeb\xdd\x65\xed\x51\xea\x82\xad\x4f\xf0\xf9\xfa\xf3\xf5\x59\x46\xbf\xa2\x8a\xbc\x55\xd2\x9d\xc4\xc8\x6c\x2f\xc1\xf6\xa9\x4f\xe9\xea\xf6\xe1\xcf\x59\xfa\xfb\x24\x5b\xa4\xb7\x93\x0b\xb8\xad\xd0\x0d\xdd\x5b\xae\x92\x8b\x00\xb0\x51\xa4\xf3\x25\x6d\xbe\x8f\x1c\x62\x0b\xe1\xcb\xe4\xe8\xa9\x51\x68\xe7\x6a\x21\xe9\x55\x1a\xf3\xc5\x64\x99\xae\xe6\xcb\x8e\xc9\x6b\x24\x2e\xcd\x72\x09\xb0\x98\xdf\xfd\x6b\xed\xfb\x09\x38\x4b\x8d\x71\x1c\x5b\xb8\x6a\x85\xde\x89\xd6\x75\x77\x55\xbf\x4f\x1c\x45\x5f\x41\x99\x9c\x6a\x32\x39\x19\xaf\x5b\x6c\x2c\x57\x6f\xce\xbe\xd7\xf5\x83\x36\xa3\xd5\x96\x0c\x39\xb7\xb0\xbc\xa6\x73\xa0\xf0\x47\xf7\x2b\xf9\x4b\xf4\xba\x03\x1d\x97\x24\xb4\x2f\xff\xbe\x0c\xf6\x7e\xbd\x39\x0b\x28\xa3\xbc\x12\xfa\x8e\xb4\x68\x33\x92\x6c\x72\x97\xe0\xd3\xb9\xa7\x6b\xb2\x8a\xf3\x63\xf4\xe6\x3a\xfa\x27\x00\x00\xff\xff\x23\x63\x71\x5a\x5d\x09\x00\x00"),
+			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x55\xc1\x6e\xe3\x36\x10\xbd\xeb\x2b\x1e\xac\xcb\x2e\x10\xdb\xc9\xa2\x87\x85\x7a\x52\x13\xa7\x31\x9a\xda\x86\xe5\x6d\xb0\xa7\x82\xa6\xc6\x12\x11\x8a\xa3\x92\x94\xbd\xea\xd7\x17\x94\x2d\xc7\xf6\xa6\x69\x0f\x01\x96\x27\x4b\x33\xf3\xe6\xbd\x99\x27\x3a\xc6\xf0\xfd\x4e\x14\xe3\x51\x49\x32\x8e\x72\x78\x86\x2f\x09\x69\x2d\x64\x49\xc8\x78\xe3\x77\xc2\x12\xee\xb9\x31\xb9\xf0\x8a\x0d\x3e\xa4\xd9\xfd\x47\x34\x26\x27\x0b\x36\x04\xb6\xa8\xd8\x52\x14\x43\xb2\xf1\x56\xad\x1b\xcf\x16\x7a\x0f\x08\x51\x58\xa2\x8a\x8c\x77\x23\x20\x23\xea\xd0\x67\xf3\xd5\xf4\x76\x82\x8d\xd2\x84\x5c\xb9\x7d\x11\xe5\xd8\x29\x5f\x46\x31\x7c\xa9\x1c\x76\x6c\x9f\xb1\x61\x0b\x91\xe7\x2a\x34\x16\x1a\xca\x6c\xd8\x56\x7b\x1a\x96\x0a\x61\x73\x65\x0a\x48\xae\x5b\xab\x8a\xd2\x83\x77\x86\xac\x2b\x55\x3d\x8a\x62\xac\x82\x8c\xec\xbe\x67\xe2\xf6\xb0\x5d\x4f\xcf\xf8\xca\xcd\x41\xc3\x89\xdc\xc3\x14\xae\xf0\x07\x59\x17\x9a\x7c\x1a\x5d\x47\x31\x3e\x84\x94\xc1\x21\x38\xf8\xf8\x33\x5a\x6e\x50\x89\x16\x86\x3d\x1a\x47\x27\xc8\xf4\x4d\x52\xed\xa1\x0c\x24\x57\xb5\x56\xc2\x48\x7a\x91\x75\xec\x30\x42\x47\x20\x60\xf0\xda\x0b\x65\x20\x3a\x19\xe0\xcd\x69\x1a\x84\x8f\xe2\x28\x46\x77\x4a\xef\xeb\x64\x3c\xde\xed\x76\x23\xd1\xd1\x1d\xb1\x2d\xc6\xbd\xba\xf1\xe3\xf4\x76\x32\xcb\x26\xc3\x8e\x72\x14\xe3\x8b\xd1\xe4\x1c\x2c\xfd\xd5\x28\x4b\x39\xd6\x2d\x44\x5d\x6b\x25\xc5\x5a\x13\xb4\xd8\x85\xc5\x75\xdb\xe9\x96\xae\x0c\x76\x56\x79\x65\x8a\x2b\xb8\xc3\xd6\xa3\xf8\x6c\x3b\x2f\xe3\xea\xe9\x29\x77\x96\xc0\x06\xc2\x60\x90\x66\x98\x66\x03\xfc\x92\x66\xd3\xec\x2a\x8a\xf1\x34\x5d\x3d\xcc\xbf\xac\xf0\x94\x2e\x97\xe9\x6c\x35\x9d\x64\x98\x2f\x71\x3b\x9f\xdd\x4d\x57\xd3\xf9\x2c\xc3\xfc\x1e\xe9\xec\x2b\x7e\x9b\xce\xee\xae\x40\xca\x97\x64\x41\xdf\x6a\x1b\xf8\xb3\x85\x0a\x83\xa4\x3c\xec\xb4\x37\x50\x4f\x20\xf8\x23\x3c\xbb\x9a\xa4\xda\x28\x09\x2d\x4c\xd1\x88\x82\x50\xf0\x96\xac\x09\xf6\xa8\xc9\x56\xca\x85\x75\x3a\x08\x93\x47\x31\xb4\xaa\x94\xef\x5c\xe4\xbe\x17\x15\xda\xbc\xe7\xb7\x15\x89\x5a\x1d\xec\x94\x84\x0d\xb8\xf1\xf6\x26\x7a\x56\x26\x4f\x70\x47\xb5\xe6\x36\x7c\x1c\x51\x45\x5e\xe4\xc2\x8b\x24\x02\x8c\xa8\x28\x81\x14\x15\xe9\xe1\xf3\x90\x6b\xb2\xc2\xb3\x8d\x00\x2d\xd6\xa4\x5d\x48\x41\x40\x4a\x30\x38\x24\x0d\xba\x57\xdd\xc3\xa9\x37\x82\x05\xd9\x90\xf1\x09\x8e\x28\x61\x52\x01\xc1\x52\xe7\x05\x97\xe0\x26\x02\x9c\xb7\xc2\x53\xd1\xee\xb1\x7d\x5b\x53\x82\x25\x49\x4b\xc2\x53\x08\x93\x26\xe9\xd9\xee\xc3\x95\xf0\xb2\x7c\x3c\xe1\xf2\x06\x65\x4f\x55\xad\x85\xa7\x43\xe5\x89\xca\x70\xf4\x19\xc8\x1b\x30\xfb\xf3\xbf\x04\xf6\xc9\xaf\x0c\xa8\xd7\xde\xfd\x26\xbb\x55\x92\x52\x29\xb9\x31\x7e\xf6\x56\xe3\x70\xad\x09\x15\x6e\x96\x17\xa6\xc3\xff\xe2\x0a\xa8\x4a\x14\x94\x20\x67\xf9\x4c\x76\xa4\x78\xbc\x27\x3e\x3e\x94\x24\x37\xa3\x9f\x46\xd7\xc3\x6c\x96\x2e\xb2\x87\xf9\xea\xb2\x70\xd1\x68\xbd\x60\xad\x64\x9b\x60\xba\x99\xb1\x5f\x58\x72\xc1\x29\x2f\x79\x92\xab\x4a\x98\x3c\x39\x79\x15\x88\x3d\x07\xfc\x8b\x77\xaf\xd0\xab\xd9\x7a\x77\x59\x7b\x94\xba\x60\xeb\x13\x7c\xbe\xfe\x7c\x7d\x96\xd1\xaf\xa8\x22\x6f\x95\x74\x27\x31\x32\xdb\x4b\xb0\x7d\xea\x53\xba\xba\x7d\xf8\x73\x96\xfe\x3e\xc9\x16\xe9\xed\xe4\x02\x6e\x2b\x74\x43\xf7\x96\xab\xe4\x22\x00\x6c\x14\xe9\x7c\x49\x9b\xef\x23\x87\xd8\x42\xf8\x32\x39\x7a\x6a\x14\xda\xb9\x5a\x48\x7a\x95\xc6\x7c\x31\x59\xa6\xab\xf9\xb2\x63\xf2\x1a\x89\x4b\xb3\x5c\x02\x2c\xe6\x77\xff\x5a\xfb\x7e\x02\xce\x52\x63\x1c\xc7\x16\xae\x5a\xa1\x77\xa2\x75\xdd\x5d\xd5\xef\x13\x47\xd1\x57\x50\x26\xa7\x9a\x4c\x4e\xc6\xeb\x16\x1b\xcb\xd5\x9b\xb3\xef\x75\xfd\xa0\xcd\x68\xb5\x25\x43\xce\x2d\x2c\xaf\xe9\x1c\x28\xfc\xd1\xfd\x4a\xfe\x12\xbd\xee\x40\xc7\x25\x09\xed\xcb\xbf\x2f\x83\xbd\x5f\x6f\xce\x02\xca\x28\xaf\x84\xbe\x23\x2d\xda\x8c\x24\x9b\xdc\x25\xf8\x74\xee\xe9\x9a\xac\xe2\xfc\x18\xbd\xb9\x8e\xfe\x09\x00\x00\xff\xff\x60\x97\xc7\xdb\x5d\x09\x00\x00"),
 		},
 		"/manager/operator-service-account.yaml": &vfsgen۰CompressedFileInfo{
 			name:             "operator-service-account.yaml",
diff --git a/pkg/trait/error_handler.go b/pkg/trait/error_handler.go
new file mode 100644
index 000000000..aa59b4e51
--- /dev/null
+++ b/pkg/trait/error_handler.go
@@ -0,0 +1,91 @@
+/*
+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 trait
+
+import (
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+	"gopkg.in/yaml.v2"
+)
+
+// The error-handler is a platform trait used to inject Error Handler source into the integration runtime.
+//
+// +camel-k:trait=error-handler
+type errorHandlerTrait struct {
+	BaseTrait `property:",squash"`
+	// The error handler ref name provided or found in application properties
+	ErrorHandlerRef string `property:"ref" json:"ref,omitempty"`
+}
+
+func newErrorHandlerTrait() Trait {
+	return &errorHandlerTrait{
+		BaseTrait: NewBaseTrait("error-handler", 500),
+	}
+}
+
+// IsPlatformTrait overrides base class method
+func (t *errorHandlerTrait) IsPlatformTrait() bool {
+	return true
+}
+
+func (t *errorHandlerTrait) Configure(e *Environment) (bool, error) {
+	if t.Enabled != nil && !*t.Enabled {
+		return false, nil
+	}
+
+	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization, v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) {
+		return false, nil
+	}
+
+	if t.ErrorHandlerRef == "" {
+		t.ErrorHandlerRef = e.Integration.Spec.GetConfigurationProperty(v1alpha1.ErrorHandlerRefName)
+	}
+
+	return t.ErrorHandlerRef != "", nil
+}
+
+func (t *errorHandlerTrait) Apply(e *Environment) error {
+	if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) {
+		return t.addErrorHandlerAsSource(e)
+	}
+	return nil
+}
+
+func (t *errorHandlerTrait) addErrorHandlerAsSource(e *Environment) error {
+	flowErrorHandler := map[string]interface{}{
+		"error-handler": map[string]string{
+			"ref": t.ErrorHandlerRef,
+		},
+	}
+	encodedFlowErrorHandler, err := yaml.Marshal([]map[string]interface{}{flowErrorHandler})
+	if err != nil {
+		return err
+	}
+	errorHandlerSource := v1.SourceSpec{
+		DataSpec: v1.DataSpec{
+			Name:    "camel-k-embedded-error-handler.yaml",
+			Content: string(encodedFlowErrorHandler),
+		},
+		Language: v1.LanguageYaml,
+		Type:     v1.SourceTypeErrorHandler,
+	}
+
+	e.Integration.Status.AddOrReplaceGeneratedSources(errorHandlerSource)
+
+	return nil
+}
diff --git a/pkg/trait/kamelets.go b/pkg/trait/kamelets.go
index df437d9fe..916b4b280 100644
--- a/pkg/trait/kamelets.go
+++ b/pkg/trait/kamelets.go
@@ -94,8 +94,8 @@ func (t *kameletsTrait) Configure(e *Environment) (bool, error) {
 	}
 
 	if t.Auto == nil || *t.Auto {
+		var kamelets []string
 		if t.List == "" {
-			var kamelets []string
 			sources, err := kubernetes.ResolveIntegrationSources(e.C, e.Client, e.Integration, e.Resources)
 			if err != nil {
 				return false, err
@@ -105,17 +105,25 @@ func (t *kameletsTrait) Configure(e *Environment) (bool, error) {
 				util.StringSliceUniqueConcat(&kamelets, extractKamelets(meta.ToURIs))
 				return true
 			})
+		}
+		// Check if a Kamelet is configured as default error handler URI
+		defaultErrorHandlerURI := e.Integration.Spec.GetConfigurationProperty(v1alpha1.ErrorHandlerAppPropertiesPrefix + ".deadLetterUri")
+		if defaultErrorHandlerURI != "" {
+			if strings.HasPrefix(defaultErrorHandlerURI, "kamelet:") {
+				kamelets = append(kamelets, extractKamelet(defaultErrorHandlerURI))
+			}
+		}
+
+		if len(kamelets) > 0 {
 			sort.Strings(kamelets)
 			t.List = strings.Join(kamelets, ",")
 		}
-
 	}
 
 	return len(t.getKameletKeys()) > 0, nil
 }
 
 func (t *kameletsTrait) Apply(e *Environment) error {
-
 	if e.IntegrationInPhase(v1.IntegrationPhaseInitialization, v1.IntegrationPhaseRunning) {
 		if err := t.addKamelets(e); err != nil {
 			return err
@@ -404,10 +412,18 @@ func integrationSourceFromKameletSource(e *Environment, kamelet *v1alpha1.Kamele
 
 func extractKamelets(uris []string) (kamelets []string) {
 	for _, uri := range uris {
-		matches := kameletNameRegexp.FindStringSubmatch(uri)
-		if len(matches) > 1 {
-			kamelets = append(kamelets, matches[1])
+		kamelet := extractKamelet(uri)
+		if kamelet != "" {
+			kamelets = append(kamelets, kamelet)
 		}
 	}
 	return
 }
+
+func extractKamelet(uri string) (kamelet string) {
+	matches := kameletNameRegexp.FindStringSubmatch(uri)
+	if len(matches) > 1 {
+		return matches[1]
+	}
+	return ""
+}
diff --git a/pkg/trait/logging.go b/pkg/trait/logging.go
new file mode 100644
index 000000000..84b111780
--- /dev/null
+++ b/pkg/trait/logging.go
@@ -0,0 +1,87 @@
+/*
+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 trait
+
+import (
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/pkg/util"
+	"github.com/apache/camel-k/pkg/util/envvar"
+	"strconv"
+)
+
+const (
+	envVarQuarkusLogConsoleColor           = "QUARKUS_LOG_CONSOLE_COLOR"
+	envVarQuarkusLogConsoleJson            = "QUARKUS_LOG_CONSOLE_JSON"
+	envVarQuarkusLogConsoleJsonPrettyPrint = "QUARKUS_LOG_CONSOLE_JSON_PRETTY_PRINT"
+	depQuarkusLoggingJson                  = "mvn:io.quarkus:quarkus-logging-json"
+)
+
+// This trait is used to control logging options (such as color)
+//
+// +camel-k:trait=logging
+type loggingTrait struct {
+	BaseTrait `property:",squash"`
+	// Colorize the log output
+	Color *bool `property:"color" json:"color,omitempty"`
+	// Output the log in json format
+	Json *bool `property:"json" json:"json,omitempty"`
+	// Enable "pretty printing" of the json log
+	JsonPrettyPrint *bool `property:"json-pretty-print" json:"jsonPrettyPrint,omitempty"`
+}
+
+func newLoggingTraitTrait() Trait {
+	return &loggingTrait{
+		BaseTrait:       NewBaseTrait("logging", 800),
+		Color:           util.BoolP(true),
+		Json:            util.BoolP(false),
+		JsonPrettyPrint: util.BoolP(false),
+	}
+}
+
+func (l loggingTrait) Configure(environment *Environment) (bool, error) {
+	if l.Enabled != nil && !*l.Enabled {
+		return false, nil
+	}
+
+	return environment.IntegrationInPhase(v1.IntegrationPhaseInitialization, v1.IntegrationPhaseDeploying,
+		v1.IntegrationPhaseRunning), nil
+}
+
+func (l loggingTrait) Apply(environment *Environment) error {
+
+	if environment.IntegrationInPhase(v1.IntegrationPhaseInitialization) {
+		if *l.Json {
+			if environment.Integration.Status.Dependencies == nil {
+				environment.Integration.Status.Dependencies = make([]string, 0)
+			}
+
+			util.StringSliceUniqueAdd(&environment.Integration.Status.Dependencies, depQuarkusLoggingJson)
+		}
+
+		return nil
+	}
+
+	envvar.SetVal(&environment.EnvVars, envVarQuarkusLogConsoleJson, strconv.FormatBool(*l.Json))
+	envvar.SetVal(&environment.EnvVars, envVarQuarkusLogConsoleJsonPrettyPrint, strconv.FormatBool(*l.JsonPrettyPrint))
+
+	if !*l.Json {
+		envvar.SetVal(&environment.EnvVars, envVarQuarkusLogConsoleColor, strconv.FormatBool(*l.Color))
+	}
+
+	return nil
+}
diff --git a/pkg/trait/trait_register.go b/pkg/trait/trait_register.go
index 4c06b3790..f8e079459 100644
--- a/pkg/trait/trait_register.go
+++ b/pkg/trait/trait_register.go
@@ -26,6 +26,7 @@ func init() {
 	AddToTraits(newOpenAPITrait)
 	AddToTraits(newKnativeTrait)
 	AddToTraits(newKameletsTrait)
+	AddToTraits(newErrorHandlerTrait)
 	AddToTraits(newDependenciesTrait)
 	AddToTraits(newBuilderTrait)
 	AddToTraits(newQuarkusTrait)
@@ -49,4 +50,5 @@ func init() {
 	AddToTraits(newServiceBindingTrait)
 	AddToTraits(newOwnerTrait)
 	AddToTraits(newPdbTrait)
+	AddToTraits(newLoggingTraitTrait)
 }


Test patch:
diff --git a/e2e/common/traits/error_handler_test.go b/e2e/common/traits/error_handler_test.go
new file mode 100644
index 000000000..506eba4e6
--- /dev/null
+++ b/e2e/common/traits/error_handler_test.go
@@ -0,0 +1,57 @@
+// +build integration
+
+// To enable compilation of this file in Goland, go to "Settings -> Go -> Vendoring & Build Tags -> Custom Tags" and add "integration"
+
+/*
+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 traits
+
+import (
+	"testing"
+
+	. "github.com/onsi/gomega"
+
+	v1 "k8s.io/api/core/v1"
+
+	. "github.com/apache/camel-k/e2e/support"
+	camelv1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+)
+
+func TestErrorHandlerTrait(t *testing.T) {
+	WithNewTestNamespace(t, func(ns string) {
+		Expect(Kamel("install", "-n", ns).Execute()).To(Succeed())
+
+		t.Run("Run errored integration with error handler", func(t *testing.T) {
+			name := "error-handler"
+			Expect(Kamel("run", "-n", ns, "files/ErroredRoute.java",
+				"--name", name,
+				"-t", "error-handler.enabled=true",
+				"-t", "error-handler.ref=defaultErrorHandler",
+				"-p", "camel.beans.defaultErrorHandler=#class:org.apache.camel.builder.DeadLetterChannelBuilder",
+				"-p", "camel.beans.defaultErrorHandler.deadLetterUri=log:my-special-error-handler-in-place?level=ERROR&showCaughtException=false&showBody=false&showBodyType=false&showExchangePattern=false",
+			).Execute()).To(Succeed())
+			Eventually(IntegrationPodPhase(ns, name), TestTimeoutMedium).Should(Equal(v1.PodRunning))
+			Eventually(IntegrationCondition(ns, name, camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
+			Eventually(IntegrationLogs(ns, name), TestTimeoutShort).ShouldNot(ContainSubstring("InvalidPayloadException"))
+			Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("my-special-error-handler-in-place"))
+		})
+
+		// Clean up
+		Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
+	})
+}
diff --git a/e2e/common/traits/files/ErroredRoute.java b/e2e/common/traits/files/ErroredRoute.java
new file mode 100644
index 000000000..702e16372
--- /dev/null
+++ b/e2e/common/traits/files/ErroredRoute.java
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+import org.apache.camel.builder.RouteBuilder;
+
+public class ErroredRoute extends RouteBuilder {
+  @Override
+  public void configure() throws Exception {
+	  from("timer:tick")
+    .setBody().simple("Hello")
+    // We want to force a failure
+	  .setBody().simple("${mandatoryBodyAs(Boolean)}")
+    .to("log:info");
+  }
+}
diff --git a/pkg/controller/kameletbinding/error_handler_test.go b/pkg/controller/kameletbinding/error_handler_test.go
new file mode 100644
index 000000000..94e6643ba
--- /dev/null
+++ b/pkg/controller/kameletbinding/error_handler_test.go
@@ -0,0 +1,134 @@
+/*
+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 kameletbinding
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestParseErrorHandlerNoneDoesSucceed(t *testing.T) {
+	noErrorHandler, err := parseErrorHandler(
+		[]byte(`{"none": null}`),
+	)
+	assert.Nil(t, err)
+	assert.Equal(t, v1alpha1.ErrorHandlerTypeNone, noErrorHandler.Type())
+	parameters, err := noErrorHandler.Configuration()
+	assert.Nil(t, err)
+	assert.Equal(t, "#class:org.apache.camel.builder.NoErrorHandlerBuilder", parameters[v1alpha1.ErrorHandlerAppPropertiesPrefix])
+	assert.Equal(t, v1alpha1.ErrorHandlerRefDefaultName, parameters[v1alpha1.ErrorHandlerRefName])
+}
+
+func TestParseErrorHandlerLogDoesSucceed(t *testing.T) {
+	logErrorHandler, err := parseErrorHandler(
+		[]byte(`{"log": null}`),
+	)
+	assert.Nil(t, err)
+	assert.Equal(t, v1alpha1.ErrorHandlerTypeLog, logErrorHandler.Type())
+	parameters, err := logErrorHandler.Configuration()
+	assert.Nil(t, err)
+	assert.Equal(t, "#class:org.apache.camel.builder.DefaultErrorHandlerBuilder", parameters[v1alpha1.ErrorHandlerAppPropertiesPrefix])
+	assert.Equal(t, v1alpha1.ErrorHandlerRefDefaultName, parameters[v1alpha1.ErrorHandlerRefName])
+}
+
+func TestParseErrorHandlerLogWithParametersDoesSucceed(t *testing.T) {
+	logErrorHandler, err := parseErrorHandler(
+		[]byte(`{"log": {"parameters": {"param1": "value1", "param2": "value2"}}}`),
+	)
+	assert.Nil(t, err)
+	assert.Equal(t, v1alpha1.ErrorHandlerTypeLog, logErrorHandler.Type())
+	parameters, err := logErrorHandler.Configuration()
+	assert.Nil(t, err)
+	assert.Equal(t, "#class:org.apache.camel.builder.DefaultErrorHandlerBuilder", parameters[v1alpha1.ErrorHandlerAppPropertiesPrefix])
+	assert.Equal(t, "value1", parameters["camel.beans.defaultErrorHandler.param1"])
+	assert.Equal(t, "value2", parameters["camel.beans.defaultErrorHandler.param2"])
+	assert.Equal(t, v1alpha1.ErrorHandlerRefDefaultName, parameters[v1alpha1.ErrorHandlerRefName])
+}
+
+func TestParseErrorHandlerDLCDoesSucceed(t *testing.T) {
+	fmt.Println("Test")
+	dlcErrorHandler, err := parseErrorHandler(
+		[]byte(`{"dead-letter-channel": {"endpoint": {"uri": "someUri"}}}`),
+	)
+	assert.Nil(t, err)
+	assert.NotNil(t, dlcErrorHandler)
+	assert.Equal(t, v1alpha1.ErrorHandlerTypeDeadLetterChannel, dlcErrorHandler.Type())
+	assert.Equal(t, "someUri", *dlcErrorHandler.Endpoint().URI)
+	parameters, err := dlcErrorHandler.Configuration()
+	assert.Nil(t, err)
+	assert.Equal(t, "#class:org.apache.camel.builder.DeadLetterChannelBuilder", parameters[v1alpha1.ErrorHandlerAppPropertiesPrefix])
+	assert.Equal(t, v1alpha1.ErrorHandlerRefDefaultName, parameters[v1alpha1.ErrorHandlerRefName])
+}
+
+func TestParseErrorHandlerDLCWithParametersDoesSucceed(t *testing.T) {
+	dlcErrorHandler, err := parseErrorHandler(
+		[]byte(`{
+			"dead-letter-channel": {
+				"endpoint": {
+					"uri": "someUri"
+					}, 
+				"parameters": 
+					{"param1": "value1", "param2": "value2"}
+			}
+		}`),
+	)
+	assert.Nil(t, err)
+	assert.NotNil(t, dlcErrorHandler)
+	assert.Equal(t, v1alpha1.ErrorHandlerTypeDeadLetterChannel, dlcErrorHandler.Type())
+	assert.Equal(t, "someUri", *dlcErrorHandler.Endpoint().URI)
+	parameters, err := dlcErrorHandler.Configuration()
+	assert.Nil(t, err)
+	assert.Equal(t, "#class:org.apache.camel.builder.DeadLetterChannelBuilder", parameters[v1alpha1.ErrorHandlerAppPropertiesPrefix])
+	assert.Equal(t, v1alpha1.ErrorHandlerRefDefaultName, parameters[v1alpha1.ErrorHandlerRefName])
+	assert.Equal(t, "value1", parameters["camel.beans.defaultErrorHandler.param1"])
+	assert.Equal(t, "value2", parameters["camel.beans.defaultErrorHandler.param2"])
+}
+
+func TestParseErrorHandlerBeanWithParamsDoesSucceed(t *testing.T) {
+	beanErrorHandler, err := parseErrorHandler(
+		[]byte(`{
+			"bean": {
+				"type": "com.acme.MyType",
+				"properties": 
+					{"beanProp1": "value1", "beanProp2": "value2"}
+			}
+		}`),
+	)
+	assert.Nil(t, err)
+	assert.Equal(t, v1alpha1.ErrorHandlerTypeBean, beanErrorHandler.Type())
+	parameters, err := beanErrorHandler.Configuration()
+	assert.Nil(t, err)
+	assert.Equal(t, "#class:com.acme.MyType", parameters[v1alpha1.ErrorHandlerAppPropertiesPrefix])
+	assert.Equal(t, v1alpha1.ErrorHandlerRefDefaultName, parameters[v1alpha1.ErrorHandlerRefName])
+	assert.Equal(t, "value1", parameters["camel.beans.defaultErrorHandler.beanProp1"])
+	assert.Equal(t, "value2", parameters["camel.beans.defaultErrorHandler.beanProp2"])
+}
+
+func TestParseErrorHandlerRefDoesSucceed(t *testing.T) {
+	refErrorHandler, err := parseErrorHandler(
+		[]byte(`{"ref": "my-registry-ref"}`),
+	)
+	assert.Nil(t, err)
+	assert.Equal(t, v1alpha1.ErrorHandlerTypeRef, refErrorHandler.Type())
+	parameters, err := refErrorHandler.Configuration()
+	assert.Nil(t, err)
+	assert.Equal(t, "my-registry-ref", parameters[v1alpha1.ErrorHandlerRefName])
+}
diff --git a/pkg/trait/logging_test.go b/pkg/trait/logging_test.go
new file mode 100644
index 000000000..c8696d471
--- /dev/null
+++ b/pkg/trait/logging_test.go
@@ -0,0 +1,162 @@
+/*
+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 trait
+
+import (
+	"context"
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/pkg/util/camel"
+	"github.com/apache/camel-k/pkg/util/kubernetes"
+	"github.com/apache/camel-k/pkg/util/test"
+	"github.com/stretchr/testify/assert"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"testing"
+)
+
+func createLoggingTestEnv(t *testing.T, color bool, json bool, jsonPrettyPrint bool) *Environment {
+	c, err := camel.DefaultCatalog()
+	if err != nil {
+		panic(err)
+	}
+
+	res := &Environment{
+		C:            context.TODO(),
+		CamelCatalog: c,
+		Catalog:      NewCatalog(context.TODO(), nil),
+		Integration: &v1.Integration{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "test",
+				Namespace: "ns",
+			},
+			Status: v1.IntegrationStatus{
+				Phase: v1.IntegrationPhaseDeploying,
+			},
+			Spec: v1.IntegrationSpec{
+				Profile: v1.TraitProfileOpenShift,
+				Traits: map[string]v1.TraitSpec{
+					"logging": test.TraitSpecFromMap(t, map[string]interface{}{
+						"color":             color,
+						"json":              json,
+						"json-pretty-print": jsonPrettyPrint,
+					}),
+				},
+			},
+		},
+		IntegrationKit: &v1.IntegrationKit{
+			Status: v1.IntegrationKitStatus{
+				Phase: v1.IntegrationKitPhaseBuildSubmitted,
+			},
+		},
+		Platform: &v1.IntegrationPlatform{
+			ObjectMeta: metav1.ObjectMeta{
+				Namespace: "ns",
+			},
+			Spec: v1.IntegrationPlatformSpec{
+				Cluster: v1.IntegrationPlatformClusterOpenShift,
+			},
+		},
+		EnvVars:        make([]corev1.EnvVar, 0),
+		ExecutedTraits: make([]Trait, 0),
+		Resources:      kubernetes.NewCollection(),
+	}
+
+	return res
+}
+
+func createDefaultLoggingTestEnv(t *testing.T) *Environment {
+	return createLoggingTestEnv(t, true, false, false)
+}
+
+func NewLoggingTestCatalog() *Catalog {
+	return NewCatalog(context.TODO(), nil)
+}
+
+func TestEmptyLoggingTrait(t *testing.T) {
+	env := createDefaultLoggingTestEnv(t)
+	err := NewLoggingTestCatalog().apply(env)
+
+	assert.Nil(t, err)
+	assert.NotEmpty(t, env.ExecutedTraits)
+
+	quarkusConsoleColor := false
+	jsonFormat := false
+	jsonPrettyPrint := false
+
+	for _, e := range env.EnvVars {
+		if e.Name == envVarQuarkusLogConsoleColor {
+			if e.Value == "true" {
+				quarkusConsoleColor = true
+			}
+		}
+
+		if e.Name == envVarQuarkusLogConsoleJson {
+			if e.Value == "true" {
+				jsonFormat = true
+			}
+		}
+
+		if e.Name == envVarQuarkusLogConsoleJsonPrettyPrint {
+			if e.Value == "true" {
+				jsonPrettyPrint = true
+			}
+		}
+	}
+
+	assert.True(t, quarkusConsoleColor)
+	assert.False(t, jsonFormat)
+	assert.False(t, jsonPrettyPrint)
+	assert.NotEmpty(t, env.ExecutedTraits)
+}
+
+func TestJsonLoggingTrait(t *testing.T) {
+	env := createLoggingTestEnv(t, true, true, false)
+	err := NewLoggingTestCatalog().apply(env)
+
+	assert.Nil(t, err)
+	assert.NotEmpty(t, env.ExecutedTraits)
+
+	quarkusConsoleColor := false
+	jsonFormat := true
+	jsonPrettyPrint := false
+
+	for _, e := range env.EnvVars {
+		if e.Name == envVarQuarkusLogConsoleColor {
+			if e.Value == "true" {
+				quarkusConsoleColor = true
+			}
+		}
+
+		if e.Name == envVarQuarkusLogConsoleJson {
+			if e.Value == "true" {
+				jsonFormat = true
+			}
+		}
+
+		if e.Name == envVarQuarkusLogConsoleJsonPrettyPrint {
+			if e.Value == "true" {
+				jsonPrettyPrint = true
+			}
+		}
+	}
+
+	assert.False(t, quarkusConsoleColor)
+	assert.True(t, jsonFormat)
+	assert.False(t, jsonPrettyPrint)
+	assert.NotEmpty(t, env.ExecutedTraits)
+}
diff --git a/pkg/trait/trait_test.go b/pkg/trait/trait_test.go
index f8f75af80..e1bea3b04 100644
--- a/pkg/trait/trait_test.go
+++ b/pkg/trait/trait_test.go
@@ -507,7 +507,7 @@ func TestOnlySomeTraitsInfluenceBuild(t *testing.T) {
 
 func TestOnlySomeTraitsArePlatform(t *testing.T) {
 	c := NewTraitTestCatalog()
-	platformTraits := []string{"builder", "camel", "jvm", "container", "dependencies", "deployer", "deployment", "environment", "kamelets", "openapi", "owner", "platform", "quarkus"}
+	platformTraits := []string{"builder", "camel", "jvm", "container", "dependencies", "deployer", "deployment", "environment", "error-handler", "kamelets", "openapi", "owner", "platform", "quarkus"}
 
 	for _, trait := range c.allTraits() {
 		if trait.IsPlatformTrait() {