feat(trait): Add telemetry trait example
diff --git a/generic-examples/traits/telemetry/InventoryService.java b/generic-examples/traits/telemetry/InventoryService.java
new file mode 100644
index 0000000..be194fc
--- /dev/null
+++ b/generic-examples/traits/telemetry/InventoryService.java
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+
+/*
+
+kamel run InventoryService.java --name inventory -d camel-opentracing -d mvn:io.jaegertracing:jaeger-client:1.2.0 -d rest-api -d camel-jackson --property-file application.properties
+
+*/
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.apache.camel.component.jackson.JacksonDataFormat;
+import java.text.SimpleDateFormat;
+import org.apache.camel.Exchange;
+import java.util.Date;
+import java.util.Map;
+
+
+public class InventoryService extends RouteBuilder {
+
+
+ @Override
+ public void configure() throws Exception {
+ restConfiguration()
+ .enableCORS(true)
+ .bindingMode(RestBindingMode.json);
+
+ rest()
+ .post("/notify/order/place")
+ .to("direct:notify");
+
+
+ JacksonDataFormat invDataFormat = new JacksonDataFormat();
+ invDataFormat.setUnmarshalType(InventoryNotification.class);
+
+ from("direct:notify")
+ .log("notifyorder--> ${body}")
+ .setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
+ .bean(InventoryNotification.class, "getInventoryNotification(${body['orderId']},${body['itemId']},${body['quantity']} )")
+ .marshal(invDataFormat)
+ .log("Inventory Notified ${body}")
+ .convertBodyTo(String.class)
+ ;
+ }
+
+ private static class InventoryNotification {
+ private Integer orderId;
+ private Integer itemId;
+ private Integer quantity;
+ private String department;
+ private Date datetime;
+
+ public static InventoryNotification getInventoryNotification(Integer orderId, Integer itemId, Integer quantity ){
+ InventoryNotification invenNotification = new InventoryNotification();
+ invenNotification.setOrderId(orderId);
+ invenNotification.setItemId(itemId);
+ invenNotification.setQuantity(quantity);
+ invenNotification.setDepartment("inventory");
+ SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z");
+ invenNotification.setDatetime(new Date(System.currentTimeMillis()));
+ return invenNotification;
+ }
+
+
+ public void setOrderId(Integer orderId){
+ this.orderId=orderId;
+ }
+ public void setItemId(Integer itemId){
+ this.itemId=itemId;
+ }
+ public void setQuantity(Integer quantity){
+ this.quantity=quantity;
+ }
+ public Integer getOrderId(){
+ return this.orderId;
+ }
+ public Integer getItemId(){
+ return this.itemId;
+ }
+ public Integer getQuantity(){
+ return this.quantity;
+ }
+ public String getDepartment() {
+ return department;
+ }
+ public void setDepartment(String department) {
+ this.department = department;
+ }
+ public Date getDatetime() {
+ return datetime;
+ }
+
+ public void setDatetime(Date datetime) {
+ this.datetime = datetime;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/generic-examples/traits/telemetry/OrderService.java b/generic-examples/traits/telemetry/OrderService.java
new file mode 100644
index 0000000..f706927
--- /dev/null
+++ b/generic-examples/traits/telemetry/OrderService.java
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+
+/*
+
+kamel run --name=order-service-api -d camel-swagger-java -d camel-jackson -d camel-undertow OrderService.java --dev
+
+*/
+
+import java.util.HashMap;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.apache.camel.Exchange;
+import org.apache.camel.component.jackson.JacksonDataFormat;
+import org.apache.camel.processor.aggregate.GroupedBodyAggregationStrategy;
+
+public class OrderService extends RouteBuilder {
+
+ @Override
+ public void configure() throws Exception {
+
+ restConfiguration()
+ .enableCORS(true)
+ .bindingMode(RestBindingMode.json);
+
+ rest()
+ .post("/place")
+ .to("direct:placeorder");
+
+ JacksonDataFormat jacksonDataFormat = new JacksonDataFormat();
+ jacksonDataFormat.setUnmarshalType(Order.class);
+
+ from("direct:placeorder")
+ .log("-----IN ${headers}")
+ .marshal(jacksonDataFormat)
+ .log("inputBody --> ${body}")
+ .to("http://inventory/notify/order?bridgeEndpoint=true")
+ .removeHeaders("*")
+ .log("responseBody from inventory --> ${body}")
+ .setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
+ .setBody(simple("{\"inventory\":${body}}"))
+ .unmarshal().json()
+ ;
+ }
+
+ private static class Order implements java.io.Serializable{
+ private static final long serialVersionUID = 1L;
+
+ private Integer orderId;
+ private Integer itemId;
+ private Integer quantity;
+
+ private String orderItemName;
+ private Integer price;
+
+ public void setOrderId(Integer orderId){
+ this.orderId=orderId;
+ }
+ public void setItemId(Integer itemId){
+ this.itemId=itemId;
+ }
+ public void setQuantity(Integer quantity){
+ this.quantity=quantity;
+ }
+
+ public void setOrderItemName(String orderItemName){
+ this.orderItemName=orderItemName;
+ }
+ public void setPrice(Integer price){
+ this.price=price;
+ }
+
+ public Integer getOrderId(){
+ return this.orderId;
+ }
+ public Integer getItemId(){
+ return this.itemId;
+ }
+ public Integer getQuantity(){
+ return this.quantity;
+ }
+
+ public String getOrderItemName(){
+ return this.orderItemName;
+ }
+ public Integer getPrice(){
+ return this.price;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/generic-examples/traits/telemetry/README.md b/generic-examples/traits/telemetry/README.md
new file mode 100644
index 0000000..4770e71
--- /dev/null
+++ b/generic-examples/traits/telemetry/README.md
@@ -0,0 +1,230 @@
+# Camel K Telemetry Trait
+
+In this section you will find examples about fine tuning your `Integration` using **Telemetry** `trait` capability.
+
+The Telemetry trait can be used to automatically publish tracing information of interactions to an OTLP compatible collector.
+
+## Configure and Setup OTLP collector
+
+You can choose which distributed tracing tool you want to use as long as it offers a OTLP compatible collector.
+
+
+### Configure and Setup Jaeger
+
+Telemetry is compatible with Jaeger version 1.35+.
+
+1. Enable Ingress addon in Minikube
+
+```sh
+$ minikube addons enable ingress
+```
+
+2. Add Minikube IP to /etc/hosts:
+
+```sh
+$ echo "$(minikube ip) example.com" | sudo tee -a /etc/hosts
+```
+
+3. Make sure Jaeger operator is available (see https://www.jaegertracing.io/docs for installation details)
+
+4. To use Jaeger, you can install the AllInOne image:
+
+```sh
+$ kubetcl apply -f jaeger-instance.yaml
+```
+
+5. Check the presence of the Jaeger instance
+
+```sh
+$ kubectl get jaeger
+NAME STATUS VERSION STRATEGY STORAGE AGE
+instance Running 1.40.0 allinone memory 9m16s
+```
+
+### Configure and Setup OpenTelemetry
+
+1. Enable Ingress addon in Minikube
+
+```sh
+$ minikube addons enable ingress
+```
+
+2. Add Minikube IP to /etc/hosts:
+
+```sh
+$ echo "$(minikube ip) example.com" | sudo tee -a /etc/hosts
+```
+
+3. Make sure OpenTelemetry operator is available (see https://github.com/open-telemetry/opentelemetry-operator for installation details)
+
+4. To use OpenTelemetry, you can deploy the OpenTelemetry Collector (otelcol) instance:
+
+```sh
+$ kubetcl apply -f otelcol-instance.yaml
+```
+
+5. Check the presence of the OTEL instance
+
+```sh
+$ kubectl get otelcol
+NAME MODE VERSION AGE
+instance deployment 0.67.0 37s
+```
+
+### Configure and Setup Grafana Tempo
+
+1. Enable Ingress addon in Minikube
+
+```sh
+$ minikube addons enable ingress
+```
+
+2. Add Minikube IP to /etc/hosts:
+
+```sh
+$ echo "$(minikube ip) example.com" | sudo tee -a /etc/hosts
+```
+
+3. Install Grafana
+
+```sh
+$ helm repo add grafana https://grafana.github.io/helm-charts
+$ helm repo update
+$ helm install grafana grafana/grafana
+```
+
+4. Install Grafana Tempo
+
+```sh
+$ helm install tempo grafana/tempo-distributed --set traces.otlp.grpc.enabled=true --set search.enabled=true --set traces.otlp.http.enabled=true
+```
+
+5. Check the presence of Tempo
+
+```sh
+$ kubectl get pods -l app.kubernetes.io/instance=tempo
+NAME READY STATUS RESTARTS AGE
+tempo-compactor-dcb77bcd8-89768 1/1 Running 0 8m48s
+tempo-distributor-6d7fc99b57-tqph9 1/1 Running 0 8m48s
+tempo-ingester-0 1/1 Running 0 8m48s
+tempo-ingester-1 1/1 Running 0 8m48s
+tempo-ingester-2 1/1 Running 0 8m48s
+tempo-memcached-0 1/1 Running 0 8m48s
+tempo-querier-75c4cc6587-8rtdv 1/1 Running 0 8m48s
+tempo-query-frontend-748b58485d-hbkpb 1/1 Running 0 8m48s
+```
+
+The result may be different on your deployment.
+
+6. Get your admin password and be sure to keep it :
+```sh
+kubectl get secret --namespace default grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
+```
+
+## Enable Telemetry and trace a REST API call in Camel K Route
+
+Tracing is an important approach for controlling and monitoring the experience of users. We will be creating two distributed services: `Order` which is a rest service, and `Inventory` which is also a rest service.
+
+Quarkus OpenTelemetry extension in Camel automatically creates a Camel OpenTelemetry tracer and binds it to the Camel registry. Simply declare the traits to enable telemetry tracing.
+
+* On **Jaeger** or **Opentelemetry**:
+
+```sh
+kamel run InventoryService.java --name inventory \
+ -d camel-jackson \
+ -t telemetry.enabled=true \
+ -t telemetry.sampler=on \
+ -t telemetry.endpoint=http://instance-collector:4317
+```
+
+* On **Grafana Tempo**:
+
+```sh
+kamel run InventoryService.java --name inventory \
+ -d camel-jackson \
+ -t telemetry.enabled=true \
+ -t telemetry.sampler=on \
+ -t telemetry.endpoint=http://tempo-distributor:4317
+```
+
+This will :
+* enable tracing
+* send traces to OTLP API endpoint
+* sample all traces
+
+
+Let's inject the OpenTelemetry Tracer to the camel OrderService.java application. Let's start the inventory service.
+
+
+* On **Jaeger** or **Opentelemetry**:
+
+```sh
+kamel run OrderService.java --name order \
+ -d camel-jackson \
+ -t telemetry.enabled=true \
+ -t telemetry.sampler=on \
+ -t telemetry.service-name=external-order \
+ -t telemetry.endpoint=http://instance-collector:4317
+```
+
+* On **Grafana Tempo**:
+
+```sh
+kamel run OrderService.java --name order \
+ -d camel-jackson \
+ -t telemetry.enabled=true \
+ -t telemetry.sampler=on \
+ -t telemetry.service-name=external-order \
+ -t telemetry.endpoint=http://tempo-distributor:4317
+```
+
+
+If you are using Jaeger, you can omit the `telemetry.endpoint` parameter since camel-k automaticly discover Jaeger OTLP API endpoint.
+
+
+You can make a few requests the REST Service with custom transaction values defined by curl, provided you made the `order` and `inventory` services available (using the **Service** trait is an easy way).
+
+```sh
+curl http://<order-service-external>/place -d '
+{
+ "orderId":58,
+ "itemId":12,
+ "quantity":1,
+ "orderItemName":"awesome item",
+ "price":99
+}' -v -H "Content-Type: application/json"
+```
+
+## View the traces
+
+### Jaeger UI
+
+If you installed the Jaeger Operator as describred, you should be able to access Jaeger interface on minikube : http://example.com.
+
+In the Jaeger interface we can see the details as:
+
+![Jeager Tracing Interface](interface/jaegerInterface.png)
+
+### OpenTelemetry collector logs
+
+If you installed the OpenTelemetry Operator as described, you should be able to see the traces in the collector logs :
+
+```sh
+kubectl logs -l app.kubernetes.io/name=instance-collector
+```
+
+### Grafana UI
+
+If you installed Grafana as descruved, you should be able to access Grafana interface easily on minikube :
+
+```sh
+$ kubectl expose service grafana --type=NodePort --target-port=3000 --name=grafana-np
+service/grafana-np exposed
+$ minikube service grafana-np
+```
+
+You need to add **Tempo** as a datasource. To configure it you need to define a URL in the datasource `http://tempo-query-frontend:3100`
+
+In the Grafana interface we can see the details as:
+
+![Grafana Interface](interface/grafanaInterface.png)
\ No newline at end of file
diff --git a/generic-examples/traits/telemetry/interface/grafanaInterface.png b/generic-examples/traits/telemetry/interface/grafanaInterface.png
new file mode 100644
index 0000000..342c814
--- /dev/null
+++ b/generic-examples/traits/telemetry/interface/grafanaInterface.png
Binary files differ
diff --git a/generic-examples/traits/telemetry/interface/jaegerInterface.png b/generic-examples/traits/telemetry/interface/jaegerInterface.png
new file mode 100644
index 0000000..1dbdbff
--- /dev/null
+++ b/generic-examples/traits/telemetry/interface/jaegerInterface.png
Binary files differ
diff --git a/generic-examples/traits/telemetry/jaeger-instance.yaml b/generic-examples/traits/telemetry/jaeger-instance.yaml
new file mode 100644
index 0000000..3bdc323
--- /dev/null
+++ b/generic-examples/traits/telemetry/jaeger-instance.yaml
@@ -0,0 +1,4 @@
+apiVersion: jaegertracing.io/v1
+kind: Jaeger
+metadata:
+ name: instance
\ No newline at end of file
diff --git a/generic-examples/traits/telemetry/otelcol-instance.yaml b/generic-examples/traits/telemetry/otelcol-instance.yaml
new file mode 100644
index 0000000..0d762e5
--- /dev/null
+++ b/generic-examples/traits/telemetry/otelcol-instance.yaml
@@ -0,0 +1,30 @@
+apiVersion: opentelemetry.io/v1alpha1
+kind: OpenTelemetryCollector
+metadata:
+ name: instance
+spec:
+ config: |
+ receivers:
+ otlp:
+ protocols:
+ grpc:
+ http:
+ processors:
+ memory_limiter:
+ check_interval: 1s
+ limit_percentage: 75
+ spike_limit_percentage: 15
+ batch:
+ send_batch_size: 10000
+ timeout: 10s
+
+ exporters:
+ logging:
+ verbosity: detailed
+
+ service:
+ pipelines:
+ traces:
+ receivers: [otlp]
+ processors: []
+ exporters: [logging]
\ No newline at end of file
diff --git a/generic-examples/traits/tracing/README.md b/generic-examples/traits/tracing/README.md
index 274af50..27e3875 100644
--- a/generic-examples/traits/tracing/README.md
+++ b/generic-examples/traits/tracing/README.md
@@ -1,5 +1,8 @@
# Camel K Tracing Trait
+> **Warning**
+> The Tracing Trait the trait has been deprecated in favor of the Telemetry Trait in camel-k 1.12+.
+
In this section you will find examples about fine tuning your `Integration` using **Tracing** `trait` capability.
The Tracing trait can be used to automatically publish tracing information of interactions to an OpenTracing compatible collector.