You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2023/03/27 14:32:06 UTC
[camel-spring-boot] branch camel-spring-boot-3.x updated: Micrometer observation (#784)
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch camel-spring-boot-3.x
in repository https://gitbox.apache.org/repos/asf/camel-spring-boot.git
The following commit(s) were added to refs/heads/camel-spring-boot-3.x by this push:
new 7433f484b6a Micrometer observation (#784)
7433f484b6a is described below
commit 7433f484b6a6a8020c46c2d9bfff85a99312b941
Author: Marcin Grzejszczak <ma...@grzejszczak.pl>
AuthorDate: Mon Mar 27 16:31:58 2023 +0200
Micrometer observation (#784)
* WIP
* Added Spring Boot setup
* Removed authors
---
.../camel/springboot/catalog/components/as2.json | 23 +-
.../springboot/catalog/components/milo-client.json | 2 +-
.../camel/springboot/catalog/components/minio.json | 9 +-
.../camel/springboot/catalog/others.properties | 1 +
.../springboot/catalog/others/observation.json | 15 ++
.../camel-observation-starter/pom.xml | 135 +++++++++++
.../src/main/docs/observation.json | 125 ++++++++++
.../observation/starter/CamelObservation.java | 34 +++
.../starter/ObservationAutoConfiguration.java | 57 +++++
.../ObservationConditionalAutoConfiguration.java | 31 +++
.../ObservationConfigurationProperties.java | 52 +++++
.../observation/ObservationAutoConfiguration.java | 134 +++++++++++
.../observation/ObservationHandlerGrouping.java | 70 ++++++
.../observation/ObservationRegistryConfigurer.java | 93 ++++++++
.../observation/ObservationRegistryCustomizer.java | 30 +++
.../ObservationRegistryPostProcessor.java | 77 ++++++
.../starter/observation/package-info.java | 20 ++
.../starter/tracing/BraveAutoConfiguration.java | 258 +++++++++++++++++++++
.../tracing/ConditionalOnEnabledTracing.java | 39 ++++
.../MicrometerTracingAutoConfiguration.java | 86 +++++++
.../tracing/OpenTelemetryAutoConfiguration.java | 257 ++++++++++++++++++++
.../starter/tracing/TracingProperties.java | 194 ++++++++++++++++
.../observation/starter/tracing/package-info.java | 20 ++
.../PrometheusExemplarsAutoConfiguration.java | 94 ++++++++
.../starter/tracing/prometheus/package-info.java | 20 ++
.../starter/tracing/zipkin/HttpSender.java | 149 ++++++++++++
.../tracing/zipkin/ZipkinAutoConfiguration.java | 56 +++++
.../tracing/zipkin/ZipkinConfigurations.java | 152 ++++++++++++
.../starter/tracing/zipkin/ZipkinProperties.java | 68 ++++++
.../ZipkinRestTemplateBuilderCustomizer.java | 35 +++
.../tracing/zipkin/ZipkinRestTemplateSender.java | 82 +++++++
.../zipkin/ZipkinWebClientBuilderCustomizer.java | 35 +++
.../tracing/zipkin/ZipkinWebClientSender.java | 89 +++++++
.../starter/tracing/zipkin/package-info.java | 20 ++
.../src/main/resources/META-INF/LICENSE.txt | 203 ++++++++++++++++
.../src/main/resources/META-INF/NOTICE.txt | 11 +
.../src/main/resources/META-INF/spring.factories | 24 ++
.../src/main/resources/META-INF/spring.provides | 17 ++
.../camel-stax-starter/src/main/docs/stax.json | 3 +-
.../XMLTokenizeLanguageConfiguration.java | 2 +-
components-starter/pom.xml | 1 +
tooling/camel-spring-boot-bom/pom.xml | 5 +
tooling/camel-spring-boot-dependencies/pom.xml | 5 +
43 files changed, 2810 insertions(+), 23 deletions(-)
diff --git a/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components/as2.json b/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components/as2.json
index 69249337ec3..cc1141ce4af 100644
--- a/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components/as2.json
+++ b/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components/as2.json
@@ -39,35 +39,30 @@
"attachedFileName": { "kind": "parameter", "displayName": "Attached File Name", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The name of the attached file" },
"clientFqdn": { "kind": "parameter", "displayName": "Client Fqdn", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "camel.apache.org", "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The Client Fully Qualified Domain Name (FQDN). Used in message ids sent by endpoint." },
"compressionAlgorithm": { "kind": "parameter", "displayName": "Compression Algorithm", "group": "common", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.as2.api.AS2CompressionAlgorithm", "enum": [ "ZLIB" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The algorithm used to compress EDI message." },
+ "decryptingPrivateKey": { "kind": "parameter", "displayName": "Decrypting Private Key", "group": "common", "label": "", "required": false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The key used to encrypt the EDI message." },
"dispositionNotificationTo": { "kind": "parameter", "displayName": "Disposition Notification To", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The value of the Disposition-Notification-To header. Assigning a value to this parameter requests a mes [...]
"ediMessageTransferEncoding": { "kind": "parameter", "displayName": "Edi Message Transfer Encoding", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The transfer encoding of EDI message." },
"ediMessageType": { "kind": "parameter", "displayName": "Edi Message Type", "group": "common", "label": "", "required": false, "type": "object", "javaType": "org.apache.http.entity.ContentType", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The content type of EDI message. One of application\/edifact, application\/edi-x12, application\/edi-consent" },
+ "encryptingAlgorithm": { "kind": "parameter", "displayName": "Encrypting Algorithm", "group": "common", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.as2.api.AS2EncryptionAlgorithm", "enum": [ "AES128_CBC", "AES192_CBC", "AES256_CBC", "AES128_CCM", "AES192_CCM", "AES256_CCM", "AES128_GCM", "AES192_GCM", "AES256_GCM", "CAMELLIA128_CBC", "CAMELLIA192_CBC", "CAMELLIA256_CBC", "CAST5_CBC", "DES_CBC", "DES_EDE3_CBC", "GOST28147_GCFB", "IDEA_CBC" [...]
+ "encryptingCertificateChain": { "kind": "parameter", "displayName": "Encrypting Certificate Chain", "group": "common", "label": "", "required": false, "type": "object", "javaType": "java.security.cert.Certificate[]", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The chain of certificates used to encrypt EDI message." },
"from": { "kind": "parameter", "displayName": "From", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The value of the From header of AS2 message." },
- "httpConnectionPoolSize": { "kind": "parameter", "displayName": "Http Connection Pool Size", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "5", "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The maximum size of the connection pool for http connections (client only)" },
- "httpConnectionPoolTtl": { "kind": "parameter", "displayName": "Http Connection Pool Ttl", "group": "common", "label": "", "required": false, "type": "object", "javaType": "java.time.Duration", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "15m", "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The time to live for connections in the connection pool (client only)" },
- "httpConnectionTimeout": { "kind": "parameter", "displayName": "Http Connection Timeout", "group": "common", "label": "", "required": false, "type": "object", "javaType": "java.time.Duration", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "5s", "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The timeout of the http connection (client only)" },
- "httpSocketTimeout": { "kind": "parameter", "displayName": "Http Socket Timeout", "group": "common", "label": "", "required": false, "type": "object", "javaType": "java.time.Duration", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "5s", "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The timeout of the underlying http socket (client only)" },
"inBody": { "kind": "parameter", "displayName": "In Body", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the name of a parameter to be passed in the exchange In Body" },
"mdnMessageTemplate": { "kind": "parameter", "displayName": "Mdn Message Template", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The template used to format MDN message" },
"requestUri": { "kind": "parameter", "displayName": "Request Uri", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "\/", "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The request URI of EDI message." },
"server": { "kind": "parameter", "displayName": "Server", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "Camel AS2 Server Endpoint", "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The value included in the Server message header identifying the AS2 Server." },
"serverFqdn": { "kind": "parameter", "displayName": "Server Fqdn", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "camel.apache.org", "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The Server Fully Qualified Domain Name (FQDN). Used in message ids sent by endpoint." },
"serverPortNumber": { "kind": "parameter", "displayName": "Server Port Number", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The port number of server." },
+ "signedReceiptMicAlgorithms": { "kind": "parameter", "displayName": "Signed Receipt Mic Algorithms", "group": "common", "label": "", "required": false, "type": "array", "javaType": "java.lang.String[]", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The list of algorithms, in order of preference, requested to generate a message integrity check (MI [...]
+ "signingAlgorithm": { "kind": "parameter", "displayName": "Signing Algorithm", "group": "common", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.as2.api.AS2SignatureAlgorithm", "enum": [ "SHA3_224WITHRSA", "SHA3_256WITHRSA", "SHA3_384withRSA", "SHA3_512WITHRSA", "MD5WITHRSA", "SHA1WITHRSA", "MD2WITHRSA", "SHA224WITHRSA", "SHA256WITHRSA", "SHA384WITHRSA", "SHA512WITHRSA", "RIPEMD128WITHRSA", "RIPEMD160WITHRSA", "RIPEMD256WITHRSA", "SHA224WITH [...]
+ "signingCertificateChain": { "kind": "parameter", "displayName": "Signing Certificate Chain", "group": "common", "label": "", "required": false, "type": "object", "javaType": "java.security.cert.Certificate[]", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The chain of certificates used to sign EDI message." },
+ "signingPrivateKey": { "kind": "parameter", "displayName": "Signing Private Key", "group": "common", "label": "", "required": false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The key used to sign the EDI message." },
"subject": { "kind": "parameter", "displayName": "Subject", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The value of Subject header of AS2 message." },
"targetHostname": { "kind": "parameter", "displayName": "Target Hostname", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The host name (IP or DNS name) of target host." },
- "targetPortNumber": { "kind": "parameter", "displayName": "Target Port Number", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "80", "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The port number of target host. -1 indicates the scheme default port." },
+ "targetPortNumber": { "kind": "parameter", "displayName": "Target Port Number", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The port number of target host. -1 indicates the scheme default port." },
"userAgent": { "kind": "parameter", "displayName": "User Agent", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "Camel AS2 Client Endpoint", "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The value included in the User-Agent message header identifying the AS2 user agent." },
"exceptionHandler": { "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the con [...]
"exchangePattern": { "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut", "InOptionalOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." },
- "lazyStartProducer": { "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may other [...]
- "decryptingPrivateKey": { "kind": "parameter", "displayName": "Decrypting Private Key", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The key used to encrypt the EDI message." },
- "encryptingAlgorithm": { "kind": "parameter", "displayName": "Encrypting Algorithm", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.component.as2.api.AS2EncryptionAlgorithm", "enum": [ "AES128_CBC", "AES192_CBC", "AES256_CBC", "AES128_CCM", "AES192_CCM", "AES256_CCM", "AES128_GCM", "AES192_GCM", "AES256_GCM", "CAMELLIA128_CBC", "CAMELLIA192_CBC", "CAMELLIA256_CBC", "CAST5_CBC", "DES_CBC", "DES_EDE3_CBC", "GOST28147_GCFB", [...]
- "encryptingCertificateChain": { "kind": "parameter", "displayName": "Encrypting Certificate Chain", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "java.security.cert.Certificate[]", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The chain of certificates used to encrypt EDI message." },
- "signedReceiptMicAlgorithms": { "kind": "parameter", "displayName": "Signed Receipt Mic Algorithms", "group": "security", "label": "security", "required": false, "type": "array", "javaType": "java.lang.String[]", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The list of algorithms, in order of preference, requested to generate a message integrity [...]
- "signingAlgorithm": { "kind": "parameter", "displayName": "Signing Algorithm", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.component.as2.api.AS2SignatureAlgorithm", "enum": [ "SHA3_224WITHRSA", "SHA3_256WITHRSA", "SHA3_384withRSA", "SHA3_512WITHRSA", "MD5WITHRSA", "SHA1WITHRSA", "MD2WITHRSA", "SHA224WITHRSA", "SHA256WITHRSA", "SHA384WITHRSA", "SHA512WITHRSA", "RIPEMD128WITHRSA", "RIPEMD160WITHRSA", "RIPEMD256WITHRSA", " [...]
- "signingCertificateChain": { "kind": "parameter", "displayName": "Signing Certificate Chain", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "java.security.cert.Certificate[]", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The chain of certificates used to sign EDI message." },
- "signingPrivateKey": { "kind": "parameter", "displayName": "Signing Private Key", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "The key used to sign the EDI message." },
- "validateSigningCertificateChain": { "kind": "parameter", "displayName": "Validate Signing Certificate Chain", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "java.security.cert.Certificate[]", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", "configurationField": "configuration", "description": "Certifiates to validate the messages signature against. If not s [...]
+ "lazyStartProducer": { "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may other [...]
},
"apis": {
"client": { "consumerOnly": false, "producerOnly": true, "description": "Sends EDI Messages over HTTP", "methods": { "send": { "description": "Send ediMessage to trading partner", "signatures": [ "org.apache.http.protocol.HttpCoreContext send(String ediMessage, String requestUri, String subject, String from, String as2From, String as2To, org.apache.camel.component.as2.api.AS2MessageStructure as2MessageStructure, org.apache.http.entity.ContentType ediMessageContentType, String ediMess [...]
diff --git a/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components/milo-client.json b/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components/milo-client.json
index ae53dbec195..4b72152bd49 100644
--- a/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components/milo-client.json
+++ b/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components/milo-client.json
@@ -57,7 +57,7 @@
"clientId": { "kind": "parameter", "displayName": "Client Id", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "A virtual client id to force the creation of a new connection instance" },
"dataChangeFilterDeadbandType": { "kind": "parameter", "displayName": "Data Change Filter Deadband Type", "group": "common", "label": "", "required": false, "type": "object", "javaType": "org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "0", "configurationClass": "org.apache.camel.component.milo.client.MonitorFilterConfiguration", "configurationField": "monitorFilterConfiguration", "descripti [...]
"dataChangeFilterDeadbandValue": { "kind": "parameter", "displayName": "Data Change Filter Deadband Value", "group": "common", "label": "", "required": false, "type": "number", "javaType": "java.lang.Double", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "0.0", "configurationClass": "org.apache.camel.component.milo.client.MonitorFilterConfiguration", "configurationField": "monitorFilterConfiguration", "description": "Deadband value for MonitorFilterType Da [...]
- "dataChangeFilterTrigger": { "kind": "parameter", "displayName": "Data Change Filter Trigger", "group": "common", "label": "", "required": false, "type": "object", "javaType": "org.eclipse.milo.opcua.stack.core.types.enumerated.DataChangeTrigger", "enum": [ "Status", "StatusValue", "StatusValueTimestamp" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "StatusValueTimestamp", "configurationClass": "org.apache.camel.component.milo.client.MonitorFilterConfig [...]
+ "dataChangeFilterTrigger": { "kind": "parameter", "displayName": "Data Change Filter Trigger", "group": "common", "label": "", "required": false, "type": "object", "javaType": "org.eclipse.milo.opcua.stack.core.types.enumerated.DataChangeTrigger", "enum": [ "Status", "StatusValue", "StatusValueTimestamp" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MonitorFilterConfiguration", "configurationField": "monitor [...]
"defaultAwaitWrites": { "kind": "parameter", "displayName": "Default Await Writes", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Default await setting for writes" },
"discoveryEndpointSuffix": { "kind": "parameter", "displayName": "Discovery Endpoint Suffix", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "A suffix for endpoint URI when discovering" },
"discoveryEndpointUri": { "kind": "parameter", "displayName": "Discovery Endpoint Uri", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "An alternative discovery URI" },
diff --git a/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components/minio.json b/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components/minio.json
index 4668d431b4e..c8049992a01 100644
--- a/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components/minio.json
+++ b/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components/minio.json
@@ -63,7 +63,7 @@
"deleteAfterWrite": { "kind": "property", "displayName": "Delete After Write", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.minio.MinioConfiguration", "configurationField": "configuration", "description": "Delete file object after the Minio file has been uploaded." },
"keyName": { "kind": "property", "displayName": "Key Name", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.minio.MinioConfiguration", "configurationField": "configuration", "description": "Setting the key name for an element in the bucket through endpoint parameter." },
"lazyStartProducer": { "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during star [...]
- "operation": { "kind": "property", "displayName": "Operation", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.minio.MinioOperations", "enum": [ "copyObject", "listObjects", "deleteObject", "deleteObjects", "deleteBucket", "listBuckets", "getObject", "getObjectRange", "createDownloadLink", "createUploadLink" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.compon [...]
+ "operation": { "kind": "property", "displayName": "Operation", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.minio.MinioOperations", "enum": [ "copyObject", "listObjects", "deleteObject", "deleteObjects", "deleteBucket", "listBuckets", "getObject", "getObjectRange" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.minio.MinioConfiguration", "configurat [...]
"pojoRequest": { "kind": "property", "displayName": "Pojo Request", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.minio.MinioConfiguration", "configurationField": "configuration", "description": "If we want to use a POJO request as body or not." },
"storageClass": { "kind": "property", "displayName": "Storage Class", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.minio.MinioConfiguration", "configurationField": "configuration", "description": "The storage class to set in the request." },
"autowiredEnabled": { "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which t [...]
@@ -86,13 +86,12 @@
"CamelMinioStorageClass": { "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The storage class of this object.", "constantName": "org.apache.camel.component.minio.MinioConstants#STORAGE_CLASS" },
"CamelMinioVersionId": { "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Producer: The version Id of the object to be stored or returned from the current operation. Consumer: The version ID of the associated Minio object if available. Version IDs are only assigned to objects when an object is uploaded to an Minio bucket that ha [...]
"CamelMinioCannedAcl": { "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The canned acl that will be applied to the object. see com.amazonaws.services.s3.model.CannedAccessControlList for allowed values.", "constantName": "org.apache.camel.component.minio.MinioConstants#CANNED_ACL" },
- "CamelMinioOperation": { "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "org.apache.camel.component.minio.MinioOperations", "enum": [ "copyObject", "listObjects", "deleteObject", "deleteObjects", "deleteBucket", "listBuckets", "getObject", "getPartialObject", "createDownloadLink", "createUploadLink" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The operation to perform [...]
+ "CamelMinioOperation": { "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "org.apache.camel.component.minio.MinioOperations", "enum": [ "copyObject", "listObjects", "deleteObject", "deleteObjects", "deleteBucket", "listBuckets", "getObject", "getPartialObject" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The operation to perform.", "constantName": "org.apache.camel.comp [...]
"CamelMinioServerSideEncryption": { "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Producer: Sets the server-side encryption algorithm when encrypting the object using Minio-managed keys. For example use AES256. Consumer: The server-side encryption algorithm when encrypting the object using Minio-managed keys.", "constantName" [...]
"CamelMinioExpirationTime": { "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The expiration time", "constantName": "org.apache.camel.component.minio.MinioConstants#EXPIRATION_TIME" },
"CamelMinioReplicationStatus": { "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The replication status", "constantName": "org.apache.camel.component.minio.MinioConstants#REPLICATION_STATUS" },
"CamelMinioOffset": { "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The offset", "constantName": "org.apache.camel.component.minio.MinioConstants#OFFSET" },
- "CamelMinioLength": { "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The length", "constantName": "org.apache.camel.component.minio.MinioConstants#LENGTH" },
- "CamelMinioPresignedURLExpirationTime": { "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Expiration of minio presigned url in Seconds", "constantName": "org.apache.camel.component.minio.MinioConstants#PRESIGNED_URL_EXPIRATION_TIME" }
+ "CamelMinioLength": { "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The length", "constantName": "org.apache.camel.component.minio.MinioConstants#LENGTH" }
},
"properties": {
"bucketName": { "kind": "path", "displayName": "Bucket Name", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.minio.MinioConfiguration", "configurationField": "configuration", "description": "Bucket name" },
@@ -139,7 +138,7 @@
"pollStrategy": { "kind": "parameter", "displayName": "Poll Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "A pluggable org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your custom implementation to control error handling usually occurred during the poll operation [...]
"deleteAfterWrite": { "kind": "parameter", "displayName": "Delete After Write", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.minio.MinioConfiguration", "configurationField": "configuration", "description": "Delete file object after the Minio file has been uploaded." },
"keyName": { "kind": "parameter", "displayName": "Key Name", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.minio.MinioConfiguration", "configurationField": "configuration", "description": "Setting the key name for an element in the bucket through endpoint parameter." },
- "operation": { "kind": "parameter", "displayName": "Operation", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.minio.MinioOperations", "enum": [ "copyObject", "listObjects", "deleteObject", "deleteObjects", "deleteBucket", "listBuckets", "getObject", "getObjectRange", "createDownloadLink", "createUploadLink" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.compo [...]
+ "operation": { "kind": "parameter", "displayName": "Operation", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.minio.MinioOperations", "enum": [ "copyObject", "listObjects", "deleteObject", "deleteObjects", "deleteBucket", "listBuckets", "getObject", "getObjectRange" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.minio.MinioConfiguration", "configura [...]
"pojoRequest": { "kind": "parameter", "displayName": "Pojo Request", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.minio.MinioConfiguration", "configurationField": "configuration", "description": "If we want to use a POJO request as body or not." },
"storageClass": { "kind": "parameter", "displayName": "Storage Class", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.minio.MinioConfiguration", "configurationField": "configuration", "description": "The storage class to set in the request." },
"lazyStartProducer": { "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may other [...]
diff --git a/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/others.properties b/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/others.properties
index f305fb98f07..e321276d645 100644
--- a/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/others.properties
+++ b/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/others.properties
@@ -23,6 +23,7 @@ leveldb
lra
mail-microsoft-oauth
management
+observation
openapi-java
opentelemetry
opentracing
diff --git a/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/others/observation.json b/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/others/observation.json
new file mode 100644
index 00000000000..32ac28b0e74
--- /dev/null
+++ b/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/others/observation.json
@@ -0,0 +1,15 @@
+{
+ "other": {
+ "kind": "other",
+ "name": "observation",
+ "title": "Micrometer Observability",
+ "description": "Observability using Micrometer Observation",
+ "deprecated": false,
+ "firstVersion": "3.21.0",
+ "label": "monitoring,microservice",
+ "supportLevel": "Preview",
+ "groupId": "org.apache.camel.springboot",
+ "artifactId": "camel-observation-starter",
+ "version": "3.21.0-SNAPSHOT"
+ }
+}
diff --git a/components-starter/camel-observation-starter/pom.xml b/components-starter/camel-observation-starter/pom.xml
new file mode 100644
index 00000000000..97f49dccbd8
--- /dev/null
+++ b/components-starter/camel-observation-starter/pom.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>components-starter</artifactId>
+ <version>3.21.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>camel-observation-starter</artifactId>
+ <packaging>jar</packaging>
+ <name>Camel SB Starters :: Micrometer Observation</name>
+ <description>Spring-Boot Starter for Camel Support for Micrometer Observation</description>
+ <properties>
+ <brave.version>5.15.0</brave.version>
+ <opentelemetry.version>1.24.0</opentelemetry.version>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter</artifactId>
+ <version>${spring-boot-version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-actuator-autoconfigure</artifactId>
+ <version>${spring-boot-version}</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-observation</artifactId>
+ <version>${camel-version}</version>
+ </dependency>
+ <!-- The following can be removed for Spring Boot 3.x -->
+ <dependency>
+ <groupId>io.micrometer</groupId>
+ <artifactId>micrometer-tracing-bridge-brave</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>io.micrometer</groupId>
+ <artifactId>micrometer-tracing-bridge-otel</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>io.zipkin.reporter2</groupId>
+ <artifactId>zipkin-reporter-brave</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>io.opentelemetry</groupId>
+ <artifactId>opentelemetry-exporter-zipkin</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>io.zipkin.reporter2</groupId>
+ <artifactId>zipkin-sender-urlconnection</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ <version>${spring-boot-version}</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-webflux</artifactId>
+ <version>${spring-boot-version}</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>io.micrometer</groupId>
+ <artifactId>micrometer-registry-prometheus</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <!--START OF GENERATED CODE-->
+ <dependency>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>camel-core-starter</artifactId>
+ </dependency>
+ <!--END OF GENERATED CODE-->
+ </dependencies>
+ <dependencyManagement>
+ <dependencies>
+ <!-- For some reason camel-observation takes in Micrometer 1.9.8 (that doesn't make any sense) -->
+ <dependency>
+ <groupId>io.micrometer</groupId>
+ <artifactId>micrometer-bom</artifactId>
+ <version>${micrometer-version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.micrometer</groupId>
+ <artifactId>micrometer-tracing-bom</artifactId>
+ <version>${micrometer-tracing-version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.zipkin.brave</groupId>
+ <artifactId>brave-bom</artifactId>
+ <version>${brave.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.opentelemetry</groupId>
+ <artifactId>opentelemetry-bom</artifactId>
+ <version>${opentelemetry.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+</project>
diff --git a/components-starter/camel-observation-starter/src/main/docs/observation.json b/components-starter/camel-observation-starter/src/main/docs/observation.json
new file mode 100644
index 00000000000..127f9811da6
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/docs/observation.json
@@ -0,0 +1,125 @@
+{
+ "groups": [
+ {
+ "name": "camel.observation",
+ "type": "org.apache.camel.observation.starter.ObservationConfigurationProperties",
+ "sourceType": "org.apache.camel.observation.starter.ObservationConfigurationProperties"
+ },
+ {
+ "name": "management.tracing",
+ "type": "org.apache.camel.observation.starter.tracing.TracingProperties",
+ "sourceType": "org.apache.camel.observation.starter.tracing.TracingProperties"
+ },
+ {
+ "name": "management.tracing.baggage",
+ "type": "org.apache.camel.observation.starter.tracing.TracingProperties$Baggage",
+ "sourceType": "org.apache.camel.observation.starter.tracing.TracingProperties",
+ "sourceMethod": "getBaggage()"
+ },
+ {
+ "name": "management.tracing.baggage.correlation",
+ "type": "org.apache.camel.observation.starter.tracing.TracingProperties$Baggage$Correlation",
+ "sourceType": "org.apache.camel.observation.starter.tracing.TracingProperties$Baggage",
+ "sourceMethod": "getCorrelation()"
+ },
+ {
+ "name": "management.tracing.propagation",
+ "type": "org.apache.camel.observation.starter.tracing.TracingProperties$Propagation",
+ "sourceType": "org.apache.camel.observation.starter.tracing.TracingProperties",
+ "sourceMethod": "getPropagation()"
+ },
+ {
+ "name": "management.tracing.sampling",
+ "type": "org.apache.camel.observation.starter.tracing.TracingProperties$Sampling",
+ "sourceType": "org.apache.camel.observation.starter.tracing.TracingProperties",
+ "sourceMethod": "getSampling()"
+ },
+ {
+ "name": "management.zipkin.tracing",
+ "type": "org.apache.camel.observation.starter.tracing.zipkin.ZipkinProperties",
+ "sourceType": "org.apache.camel.observation.starter.tracing.zipkin.ZipkinProperties"
+ }
+ ],
+ "properties": [
+ {
+ "name": "camel.observation.encoding",
+ "type": "java.lang.Boolean",
+ "description": "Activate or deactivate dash encoding in headers (required by JMS) for messaging",
+ "sourceType": "org.apache.camel.observation.starter.ObservationConfigurationProperties"
+ },
+ {
+ "name": "camel.observation.exclude-patterns",
+ "type": "java.util.Set<java.lang.String>",
+ "description": "Sets exclude pattern(s) that will disable observability for Camel messages that matches the pattern.",
+ "sourceType": "org.apache.camel.observation.starter.ObservationConfigurationProperties"
+ },
+ {
+ "name": "management.tracing.baggage.correlation.enabled",
+ "type": "java.lang.Boolean",
+ "description": "Whether to enable correlation of the baggage context with logging contexts.",
+ "sourceType": "org.apache.camel.observation.starter.tracing.TracingProperties$Baggage$Correlation",
+ "defaultValue": true
+ },
+ {
+ "name": "management.tracing.baggage.correlation.fields",
+ "type": "java.util.List<java.lang.String>",
+ "description": "List of fields that should be correlated with the logging context. That means that these fields would end up as key-value pairs in e.g. MDC.",
+ "sourceType": "org.apache.camel.observation.starter.tracing.TracingProperties$Baggage$Correlation"
+ },
+ {
+ "name": "management.tracing.baggage.enabled",
+ "type": "java.lang.Boolean",
+ "description": "Whether to enable Micrometer Tracing baggage propagation.",
+ "sourceType": "org.apache.camel.observation.starter.tracing.TracingProperties$Baggage",
+ "defaultValue": true
+ },
+ {
+ "name": "management.tracing.baggage.remote-fields",
+ "type": "java.util.List<java.lang.String>",
+ "description": "List of fields that are referenced the same in-process as it is on the wire. For example, the field \"x-vcap-request-id\" would be set as-is including the prefix.",
+ "sourceType": "org.apache.camel.observation.starter.tracing.TracingProperties$Baggage"
+ },
+ {
+ "name": "management.tracing.enabled",
+ "type": "java.lang.Boolean",
+ "description": "Whether auto-configuration of tracing is enabled.",
+ "sourceType": "org.apache.camel.observation.starter.tracing.TracingProperties",
+ "defaultValue": true
+ },
+ {
+ "name": "management.tracing.propagation.type",
+ "type": "org.apache.camel.observation.starter.tracing.TracingProperties$Propagation$PropagationType",
+ "description": "Tracing context propagation type.",
+ "sourceType": "org.apache.camel.observation.starter.tracing.TracingProperties$Propagation"
+ },
+ {
+ "name": "management.tracing.sampling.probability",
+ "type": "java.lang.Float",
+ "description": "Probability in the range from 0.0 to 1.0 that a trace will be sampled.",
+ "sourceType": "org.apache.camel.observation.starter.tracing.TracingProperties$Sampling",
+ "defaultValue": 0.1
+ },
+ {
+ "name": "management.zipkin.tracing.connect-timeout",
+ "type": "java.time.Duration",
+ "description": "Connection timeout for requests to Zipkin.",
+ "sourceType": "org.apache.camel.observation.starter.tracing.zipkin.ZipkinProperties",
+ "defaultValue": "1s"
+ },
+ {
+ "name": "management.zipkin.tracing.endpoint",
+ "type": "java.lang.String",
+ "description": "URL to the Zipkin API.",
+ "sourceType": "org.apache.camel.observation.starter.tracing.zipkin.ZipkinProperties",
+ "defaultValue": "http:\/\/localhost:9411\/api\/v2\/spans"
+ },
+ {
+ "name": "management.zipkin.tracing.read-timeout",
+ "type": "java.time.Duration",
+ "description": "Read timeout for requests to Zipkin.",
+ "sourceType": "org.apache.camel.observation.starter.tracing.zipkin.ZipkinProperties",
+ "defaultValue": "10s"
+ }
+ ],
+ "hints": []
+}
\ No newline at end of file
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/CamelObservation.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/CamelObservation.java
new file mode 100644
index 00000000000..611b26325e5
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/CamelObservation.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.observation.starter;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.context.annotation.Import;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@Import(ObservationAutoConfiguration.class)
+public @interface CamelObservation {
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/ObservationAutoConfiguration.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/ObservationAutoConfiguration.java
new file mode 100644
index 00000000000..167904a9398
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/ObservationAutoConfiguration.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.observation.starter;
+
+import io.micrometer.observation.ObservationRegistry;
+import io.micrometer.tracing.Tracer;
+import org.apache.camel.CamelContext;
+import org.apache.camel.observation.MicrometerObservationTracer;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration(proxyBeanMethods = false)
+@EnableConfigurationProperties(ObservationConfigurationProperties.class)
+@ConditionalOnProperty(value = "camel.observation.enabled", matchIfMissing = true)
+public class ObservationAutoConfiguration {
+
+ @Bean(initMethod = "", destroyMethod = "")
+ // Camel handles the lifecycle of this bean
+ @ConditionalOnMissingBean(MicrometerObservationTracer.class)
+ MicrometerObservationTracer micrometerObservationTracer(CamelContext camelContext,
+ ObservationConfigurationProperties config,
+ ObjectProvider<Tracer> tracer,
+ ObjectProvider<ObservationRegistry> observationRegistry) {
+ MicrometerObservationTracer micrometerObservationTracer = new MicrometerObservationTracer();
+ tracer.ifAvailable(micrometerObservationTracer::setTracer);
+ observationRegistry.ifAvailable(micrometerObservationTracer::setObservationRegistry);
+
+ if (config.getExcludePatterns() != null) {
+ micrometerObservationTracer.setExcludePatterns(config.getExcludePatterns());
+ }
+ if (config.getEncoding() != null) {
+ micrometerObservationTracer.setEncoding(config.getEncoding().booleanValue());
+ }
+ micrometerObservationTracer.init(camelContext);
+
+ return micrometerObservationTracer;
+ }
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/ObservationConditionalAutoConfiguration.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/ObservationConditionalAutoConfiguration.java
new file mode 100644
index 00000000000..cbf5c3a7492
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/ObservationConditionalAutoConfiguration.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.observation.starter;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+/**
+ * A configuration controller to enable Micrometer Observation via the configuration property.
+ * Useful to bootstrap Micrometer Observation when not using the {@link CamelObservation} annotation.
+ */
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnProperty(value = "camel.observation.enabled")
+@Import(ObservationAutoConfiguration.class)
+public class ObservationConditionalAutoConfiguration {
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/ObservationConfigurationProperties.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/ObservationConfigurationProperties.java
new file mode 100644
index 00000000000..2ab4198b6fe
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/ObservationConfigurationProperties.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.observation.starter;
+
+import java.util.Set;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@ConfigurationProperties(prefix = "camel.observation")
+public class ObservationConfigurationProperties {
+
+ /**
+ * Sets exclude pattern(s) that will disable observability for Camel messages that
+ * matches the pattern.
+ */
+ private Set<String> excludePatterns;
+ /**
+ * Activate or deactivate dash encoding in headers (required by JMS) for
+ * messaging
+ */
+ private Boolean encoding;
+
+ public Set<String> getExcludePatterns() {
+ return excludePatterns;
+ }
+
+ public void setExcludePatterns(Set<String> excludePatterns) {
+ this.excludePatterns = excludePatterns;
+ }
+
+ public Boolean getEncoding() {
+ return encoding;
+ }
+
+ public void setEncoding(Boolean encoding) {
+ this.encoding = encoding;
+ }
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/ObservationAutoConfiguration.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/ObservationAutoConfiguration.java
new file mode 100644
index 00000000000..6d0e29ea71d
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/ObservationAutoConfiguration.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2012-2023 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.observation;
+
+import java.util.List;
+
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;
+import io.micrometer.core.instrument.observation.MeterObservationHandler;
+import io.micrometer.observation.GlobalObservationConvention;
+import io.micrometer.observation.Observation;
+import io.micrometer.observation.ObservationFilter;
+import io.micrometer.observation.ObservationHandler;
+import io.micrometer.observation.ObservationPredicate;
+import io.micrometer.observation.ObservationRegistry;
+import io.micrometer.tracing.Tracer;
+import io.micrometer.tracing.handler.TracingAwareMeterObservationHandler;
+import io.micrometer.tracing.handler.TracingObservationHandler;
+import org.apache.camel.observation.starter.tracing.MicrometerTracingAutoConfiguration;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@AutoConfiguration(after = MicrometerTracingAutoConfiguration.class, before = org.apache.camel.observation.starter.ObservationAutoConfiguration.class, afterName = "org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration")
+@ConditionalOnClass(ObservationRegistry.class)
+@ConditionalOnMissingBean(ObservationRegistry.class)
+public class ObservationAutoConfiguration {
+
+ @Bean
+ static ObservationRegistryPostProcessor camelObservationRegistryPostProcessor(
+ ObjectProvider<ObservationRegistryCustomizer<?>> observationRegistryCustomizers,
+ ObjectProvider<ObservationPredicate> observationPredicates,
+ ObjectProvider<GlobalObservationConvention<?>> observationConventions,
+ ObjectProvider<ObservationHandler<?>> observationHandlers,
+ ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping,
+ ObjectProvider<ObservationFilter> observationFilters) {
+ return new ObservationRegistryPostProcessor(observationRegistryCustomizers, observationPredicates,
+ observationConventions, observationHandlers, observationHandlerGrouping, observationFilters);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ ObservationRegistry camelObservationRegistry() {
+ return ObservationRegistry.create();
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass(MeterRegistry.class)
+ @ConditionalOnMissingClass("io.micrometer.tracing.Tracer")
+ static class CamelOnlyMetricsConfiguration {
+
+ @Bean
+ ObservationHandlerGrouping camelMetricsObservationHandlerGrouping() {
+ return new ObservationHandlerGrouping(MeterObservationHandler.class);
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass(Tracer.class)
+ @ConditionalOnMissingClass("io.micrometer.core.instrument.MeterRegistry")
+ static class CamelOnlyTracingConfiguration {
+
+ @Bean
+ ObservationHandlerGrouping camelTracingObservationHandlerGrouping() {
+ return new ObservationHandlerGrouping(TracingObservationHandler.class);
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass({ MeterRegistry.class, Tracer.class })
+ static class CamelMetricsWithTracingConfiguration {
+
+ @Bean
+ ObservationHandlerGrouping camelMetricsAndTracingObservationHandlerGrouping() {
+ return new ObservationHandlerGrouping(
+ List.of(TracingObservationHandler.class, MeterObservationHandler.class));
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnBean(MeterRegistry.class)
+ @ConditionalOnMissingBean(MeterObservationHandler.class)
+ static class CamelMeterObservationHandlerConfiguration {
+
+ @ConditionalOnMissingBean(type = "io.micrometer.tracing.Tracer")
+ @Configuration(proxyBeanMethods = false)
+ static class CamelOnlyMetricsMeterObservationHandlerConfiguration {
+
+ @Bean
+ DefaultMeterObservationHandler camelDefaultMeterObservationHandler(MeterRegistry meterRegistry) {
+ return new DefaultMeterObservationHandler(meterRegistry);
+ }
+
+ }
+
+ @ConditionalOnBean(Tracer.class)
+ @Configuration(proxyBeanMethods = false)
+ static class CamelTracingAndMetricsObservationHandlerConfiguration {
+
+ @Bean
+ TracingAwareMeterObservationHandler<Observation.Context> cameltracingAwareMeterObservationHandler(
+ MeterRegistry meterRegistry, Tracer tracer) {
+ DefaultMeterObservationHandler delegate = new DefaultMeterObservationHandler(meterRegistry);
+ return new TracingAwareMeterObservationHandler<>(delegate, tracer);
+ }
+
+ }
+
+ }
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/ObservationHandlerGrouping.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/ObservationHandlerGrouping.java
new file mode 100644
index 00000000000..c82fa38df4f
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/ObservationHandlerGrouping.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.observation;
+
+import java.util.List;
+
+import io.micrometer.observation.ObservationHandler;
+import io.micrometer.observation.ObservationHandler.FirstMatchingCompositeObservationHandler;
+import io.micrometer.observation.ObservationRegistry.ObservationConfig;
+
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+
+@SuppressWarnings("rawtypes")
+class ObservationHandlerGrouping {
+
+ private final List<Class<? extends ObservationHandler>> categories;
+
+ ObservationHandlerGrouping(Class<? extends ObservationHandler> category) {
+ this(List.of(category));
+ }
+
+ ObservationHandlerGrouping(List<Class<? extends ObservationHandler>> categories) {
+ this.categories = categories;
+ }
+
+ void apply(List<ObservationHandler<?>> handlers, ObservationConfig config) {
+ MultiValueMap<Class<? extends ObservationHandler>, ObservationHandler<?>> groupings = new LinkedMultiValueMap<>();
+ for (ObservationHandler<?> handler : handlers) {
+ Class<? extends ObservationHandler> category = findCategory(handler);
+ if (category != null) {
+ groupings.add(category, handler);
+ }
+ else {
+ config.observationHandler(handler);
+ }
+ }
+ for (Class<? extends ObservationHandler> category : this.categories) {
+ List<ObservationHandler<?>> handlerGroup = groupings.get(category);
+ if (!CollectionUtils.isEmpty(handlerGroup)) {
+ config.observationHandler(new FirstMatchingCompositeObservationHandler(handlerGroup));
+ }
+ }
+ }
+
+ private Class<? extends ObservationHandler> findCategory(ObservationHandler<?> handler) {
+ for (Class<? extends ObservationHandler> category : this.categories) {
+ if (category.isInstance(handler)) {
+ return category;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/ObservationRegistryConfigurer.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/ObservationRegistryConfigurer.java
new file mode 100644
index 00000000000..134ffdc697b
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/ObservationRegistryConfigurer.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012-2023 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.observation;
+
+import java.util.List;
+
+import io.micrometer.observation.GlobalObservationConvention;
+import io.micrometer.observation.ObservationFilter;
+import io.micrometer.observation.ObservationHandler;
+import io.micrometer.observation.ObservationPredicate;
+import io.micrometer.observation.ObservationRegistry;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.util.LambdaSafe;
+
+class ObservationRegistryConfigurer {
+
+ private final ObjectProvider<ObservationRegistryCustomizer<?>> customizers;
+
+ private final ObjectProvider<ObservationPredicate> observationPredicates;
+
+ private final ObjectProvider<GlobalObservationConvention<?>> observationConventions;
+
+ private final ObjectProvider<ObservationHandler<?>> observationHandlers;
+
+ private final ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping;
+
+ private final ObjectProvider<ObservationFilter> observationFilters;
+
+ ObservationRegistryConfigurer(ObjectProvider<ObservationRegistryCustomizer<?>> customizers,
+ ObjectProvider<ObservationPredicate> observationPredicates,
+ ObjectProvider<GlobalObservationConvention<?>> observationConventions,
+ ObjectProvider<ObservationHandler<?>> observationHandlers,
+ ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping,
+ ObjectProvider<ObservationFilter> observationFilters) {
+ this.customizers = customizers;
+ this.observationPredicates = observationPredicates;
+ this.observationConventions = observationConventions;
+ this.observationHandlers = observationHandlers;
+ this.observationHandlerGrouping = observationHandlerGrouping;
+ this.observationFilters = observationFilters;
+ }
+
+ void configure(ObservationRegistry registry) {
+ registerObservationPredicates(registry);
+ registerGlobalObservationConventions(registry);
+ registerHandlers(registry);
+ registerFilters(registry);
+ customize(registry);
+ }
+
+ private void registerHandlers(ObservationRegistry registry) {
+ this.observationHandlerGrouping.ifAvailable(
+ (grouping) -> grouping.apply(asOrderedList(this.observationHandlers), registry.observationConfig()));
+ }
+
+ private void registerObservationPredicates(ObservationRegistry registry) {
+ this.observationPredicates.orderedStream().forEach(registry.observationConfig()::observationPredicate);
+ }
+
+ private void registerGlobalObservationConventions(ObservationRegistry registry) {
+ this.observationConventions.orderedStream().forEach(registry.observationConfig()::observationConvention);
+ }
+
+ private void registerFilters(ObservationRegistry registry) {
+ this.observationFilters.orderedStream().forEach(registry.observationConfig()::observationFilter);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void customize(ObservationRegistry registry) {
+ LambdaSafe.callbacks(ObservationRegistryCustomizer.class, asOrderedList(this.customizers), registry)
+ .withLogger(ObservationRegistryConfigurer.class).invoke((customizer) -> customizer.customize(registry));
+ }
+
+ private <T> List<T> asOrderedList(ObjectProvider<T> provider) {
+ return provider.orderedStream().toList();
+ }
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/ObservationRegistryCustomizer.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/ObservationRegistryCustomizer.java
new file mode 100644
index 00000000000..a834fc042cd
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/ObservationRegistryCustomizer.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.observation;
+
+import io.micrometer.observation.ObservationRegistry;
+
+@FunctionalInterface
+public interface ObservationRegistryCustomizer<T extends ObservationRegistry> {
+
+ /**
+ * Customize the given {@code registry}.
+ * @param registry the registry to customize
+ */
+ void customize(T registry);
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/ObservationRegistryPostProcessor.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/ObservationRegistryPostProcessor.java
new file mode 100644
index 00000000000..9eb3f17c836
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/ObservationRegistryPostProcessor.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2012-2023 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.observation;
+
+import io.micrometer.observation.GlobalObservationConvention;
+import io.micrometer.observation.ObservationFilter;
+import io.micrometer.observation.ObservationHandler;
+import io.micrometer.observation.ObservationPredicate;
+import io.micrometer.observation.ObservationRegistry;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+class ObservationRegistryPostProcessor implements BeanPostProcessor {
+
+ private final ObjectProvider<ObservationRegistryCustomizer<?>> observationRegistryCustomizers;
+
+ private final ObjectProvider<ObservationPredicate> observationPredicates;
+
+ private final ObjectProvider<GlobalObservationConvention<?>> observationConventions;
+
+ private final ObjectProvider<ObservationHandler<?>> observationHandlers;
+
+ private final ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping;
+
+ private final ObjectProvider<ObservationFilter> observationFilters;
+
+ private volatile ObservationRegistryConfigurer configurer;
+
+ ObservationRegistryPostProcessor(ObjectProvider<ObservationRegistryCustomizer<?>> observationRegistryCustomizers,
+ ObjectProvider<ObservationPredicate> observationPredicates,
+ ObjectProvider<GlobalObservationConvention<?>> observationConventions,
+ ObjectProvider<ObservationHandler<?>> observationHandlers,
+ ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping,
+ ObjectProvider<ObservationFilter> observationFilters) {
+ this.observationRegistryCustomizers = observationRegistryCustomizers;
+ this.observationPredicates = observationPredicates;
+ this.observationConventions = observationConventions;
+ this.observationHandlers = observationHandlers;
+ this.observationHandlerGrouping = observationHandlerGrouping;
+ this.observationFilters = observationFilters;
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+ if (bean instanceof ObservationRegistry) {
+ ObservationRegistry registry = (ObservationRegistry) bean;
+ getConfigurer().configure(registry);
+ }
+ return bean;
+ }
+
+ private ObservationRegistryConfigurer getConfigurer() {
+ if (this.configurer == null) {
+ this.configurer = new ObservationRegistryConfigurer(this.observationRegistryCustomizers,
+ this.observationPredicates, this.observationConventions, this.observationHandlers,
+ this.observationHandlerGrouping, this.observationFilters);
+ }
+ return this.configurer;
+ }
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/package-info.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/package-info.java
new file mode 100644
index 00000000000..ec6fa4131b1
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/observation/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://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.
+ */
+
+/**
+ * The whole package is taken from https://github.com/spring-projects/spring-boot/tree/v3.0.2/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation and should be deleted for versions using Spring Boot 3.x. We're copying these classes to allow Micrometer Observation usage together with Boot 2.7.
+ */
+package org.apache.camel.observation.starter.observation;
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/BraveAutoConfiguration.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/BraveAutoConfiguration.java
new file mode 100644
index 00000000000..5749c3806ed
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/BraveAutoConfiguration.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2012-2023 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.tracing;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import brave.CurrentSpanCustomizer;
+import brave.SpanCustomizer;
+import brave.Tracer;
+import brave.Tracing;
+import brave.Tracing.Builder;
+import brave.TracingCustomizer;
+import brave.baggage.BaggageField;
+import brave.baggage.BaggagePropagation;
+import brave.baggage.BaggagePropagation.FactoryBuilder;
+import brave.baggage.BaggagePropagationConfig;
+import brave.baggage.BaggagePropagationCustomizer;
+import brave.baggage.CorrelationScopeConfig;
+import brave.baggage.CorrelationScopeCustomizer;
+import brave.baggage.CorrelationScopeDecorator;
+import brave.context.slf4j.MDCScopeDecorator;
+import brave.handler.SpanHandler;
+import brave.propagation.B3Propagation;
+import brave.propagation.CurrentTraceContext;
+import brave.propagation.CurrentTraceContext.ScopeDecorator;
+import brave.propagation.CurrentTraceContextCustomizer;
+import brave.propagation.Propagation.Factory;
+import brave.propagation.ThreadLocalCurrentTraceContext;
+import brave.sampler.Sampler;
+import io.micrometer.tracing.brave.bridge.BraveBaggageManager;
+import io.micrometer.tracing.brave.bridge.BraveCurrentTraceContext;
+import io.micrometer.tracing.brave.bridge.BravePropagator;
+import io.micrometer.tracing.brave.bridge.BraveSpanCustomizer;
+import io.micrometer.tracing.brave.bridge.BraveTracer;
+import io.micrometer.tracing.brave.bridge.CompositeSpanHandler;
+import io.micrometer.tracing.brave.bridge.W3CPropagation;
+import io.micrometer.tracing.exporter.SpanExportingPredicate;
+import io.micrometer.tracing.exporter.SpanFilter;
+import io.micrometer.tracing.exporter.SpanReporter;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.core.env.Environment;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for Brave.
+ */
+@AutoConfiguration(before = MicrometerTracingAutoConfiguration.class)
+@ConditionalOnClass({ Tracer.class, BraveTracer.class })
+@EnableConfigurationProperties(TracingProperties.class)
+@ConditionalOnEnabledTracing
+public class BraveAutoConfiguration {
+
+ private static final BraveBaggageManager BRAVE_BAGGAGE_MANAGER = new BraveBaggageManager();
+
+ /**
+ * Default value for application name if {@code spring.application.name} is not set.
+ */
+ private static final String DEFAULT_APPLICATION_NAME = "application";
+
+ @Bean
+ @ConditionalOnMissingBean
+ @Order(Ordered.HIGHEST_PRECEDENCE)
+ CompositeSpanHandler compositeSpanHandler(ObjectProvider<SpanExportingPredicate> predicates,
+ ObjectProvider<SpanReporter> reporters, ObjectProvider<SpanFilter> filters) {
+ return new CompositeSpanHandler(predicates.orderedStream().collect(Collectors.toList()), reporters.orderedStream().collect(Collectors.toList()),
+ filters.orderedStream().collect(Collectors.toList()));
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public Tracing braveTracing(Environment environment, List<SpanHandler> spanHandlers,
+ List<TracingCustomizer> tracingCustomizers, CurrentTraceContext currentTraceContext,
+ Factory propagationFactory, Sampler sampler) {
+ String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
+ Builder builder = Tracing.newBuilder()
+ .currentTraceContext(currentTraceContext)
+ .traceId128Bit(true)
+ .supportsJoin(false)
+ .propagationFactory(propagationFactory)
+ .sampler(sampler)
+ .localServiceName(applicationName);
+ spanHandlers.forEach(builder::addSpanHandler);
+ for (TracingCustomizer tracingCustomizer : tracingCustomizers) {
+ tracingCustomizer.customize(builder);
+ }
+ return builder.build();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public brave.Tracer braveTracer(Tracing tracing) {
+ return tracing.tracer();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public CurrentTraceContext braveCurrentTraceContext(List<CurrentTraceContext.ScopeDecorator> scopeDecorators,
+ List<CurrentTraceContextCustomizer> currentTraceContextCustomizers) {
+ ThreadLocalCurrentTraceContext.Builder builder = ThreadLocalCurrentTraceContext.newBuilder();
+ scopeDecorators.forEach(builder::addScopeDecorator);
+ for (CurrentTraceContextCustomizer currentTraceContextCustomizer : currentTraceContextCustomizers) {
+ currentTraceContextCustomizer.customize(builder);
+ }
+ return builder.build();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public Sampler braveSampler(TracingProperties properties) {
+ return Sampler.create(properties.getSampling().getProbability());
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(io.micrometer.tracing.Tracer.class)
+ BraveTracer braveTracerBridge(brave.Tracer tracer, CurrentTraceContext currentTraceContext) {
+ return new BraveTracer(tracer, new BraveCurrentTraceContext(currentTraceContext), BRAVE_BAGGAGE_MANAGER);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ BravePropagator bravePropagator(Tracing tracing) {
+ return new BravePropagator(tracing);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(SpanCustomizer.class)
+ CurrentSpanCustomizer currentSpanCustomizer(Tracing tracing) {
+ return CurrentSpanCustomizer.create(tracing);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(io.micrometer.tracing.SpanCustomizer.class)
+ BraveSpanCustomizer braveSpanCustomizer(SpanCustomizer spanCustomizer) {
+ return new BraveSpanCustomizer(spanCustomizer);
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnProperty(value = "management.tracing.baggage.enabled", havingValue = "false")
+ static class BraveNoBaggageConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ Factory propagationFactory(TracingProperties tracing) {
+ switch (tracing.getPropagation().getType()) {
+ case B3:
+ return B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build();
+ case W3C:
+ return new W3CPropagation();
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnProperty(value = "management.tracing.baggage.enabled", matchIfMissing = true)
+ static class BraveBaggageConfiguration {
+
+ private final TracingProperties tracingProperties;
+
+ BraveBaggageConfiguration(TracingProperties tracingProperties) {
+ this.tracingProperties = tracingProperties;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ BaggagePropagation.FactoryBuilder propagationFactoryBuilder(
+ ObjectProvider<BaggagePropagationCustomizer> baggagePropagationCustomizers) {
+ Factory delegate = delegate();
+ FactoryBuilder builder = BaggagePropagation.newFactoryBuilder(delegate);
+ baggagePropagationCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
+ return builder;
+ }
+
+ private Factory delegate() {
+ if (this.tracingProperties.getPropagation().getType() == TracingProperties.Propagation.PropagationType.B3) {
+ return B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build();
+ }
+ return new W3CPropagation(BRAVE_BAGGAGE_MANAGER, Collections.emptyList());
+ }
+
+ @Bean
+ @Order(0)
+ BaggagePropagationCustomizer remoteFieldsBaggagePropagationCustomizer() {
+ return (builder) -> {
+ List<String> remoteFields = this.tracingProperties.getBaggage().getRemoteFields();
+ for (String fieldName : remoteFields) {
+ builder.add(BaggagePropagationConfig.SingleBaggageField.remote(BaggageField.create(fieldName)));
+ }
+ };
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ Factory propagationFactory(BaggagePropagation.FactoryBuilder factoryBuilder) {
+ return factoryBuilder.build();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ CorrelationScopeDecorator.Builder mdcCorrelationScopeDecoratorBuilder(
+ ObjectProvider<CorrelationScopeCustomizer> correlationScopeCustomizers) {
+ CorrelationScopeDecorator.Builder builder = MDCScopeDecorator.newBuilder();
+ correlationScopeCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
+ return builder;
+ }
+
+ @Bean
+ @Order(0)
+ @ConditionalOnProperty(prefix = "management.tracing.baggage.correlation", name = "enabled",
+ matchIfMissing = true)
+ CorrelationScopeCustomizer correlationFieldsCorrelationScopeCustomizer() {
+ return (builder) -> {
+ List<String> correlationFields = this.tracingProperties.getBaggage().getCorrelation().getFields();
+ for (String field : correlationFields) {
+ builder.add(CorrelationScopeConfig.SingleCorrelationField.newBuilder(BaggageField.create(field))
+ .flushOnUpdate()
+ .build());
+ }
+ };
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(CorrelationScopeDecorator.class)
+ ScopeDecorator correlationScopeDecorator(CorrelationScopeDecorator.Builder builder) {
+ return builder.build();
+ }
+
+ }
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/ConditionalOnEnabledTracing.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/ConditionalOnEnabledTracing.java
new file mode 100644
index 00000000000..3dce042bb94
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/ConditionalOnEnabledTracing.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.tracing;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Conditional;
+
+/**
+ * {@link Conditional @Conditional} that checks whether tracing is enabled. It matches if
+ * the value of the {@code management.tracing.enabled} property is {@code true} or if it
+ * is not configured.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@Documented
+@ConditionalOnProperty(prefix = "management.tracing", name = "enabled", matchIfMissing = true)
+public @interface ConditionalOnEnabledTracing {
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/MicrometerTracingAutoConfiguration.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/MicrometerTracingAutoConfiguration.java
new file mode 100644
index 00000000000..209b431bb75
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/MicrometerTracingAutoConfiguration.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.tracing;
+
+import io.micrometer.tracing.Tracer;
+import io.micrometer.tracing.handler.DefaultTracingObservationHandler;
+import io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler;
+import io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler;
+import io.micrometer.tracing.propagation.Propagator;
+import org.apache.camel.observation.starter.ObservationAutoConfiguration;
+
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for the Micrometer Tracing API.
+ */
+@AutoConfiguration(before = ObservationAutoConfiguration.class)
+@ConditionalOnClass(Tracer.class)
+@ConditionalOnEnabledTracing
+public class MicrometerTracingAutoConfiguration {
+
+ /**
+ * {@code @Order} value of {@link #defaultTracingObservationHandler(Tracer)}.
+ */
+ public static final int DEFAULT_TRACING_OBSERVATION_HANDLER_ORDER = Ordered.LOWEST_PRECEDENCE - 1000;
+
+ /**
+ * {@code @Order} value of
+ * {@link #propagatingReceiverTracingObservationHandler(Tracer, Propagator)}.
+ */
+ public static final int RECEIVER_TRACING_OBSERVATION_HANDLER_ORDER = 1000;
+
+ /**
+ * {@code @Order} value of
+ * {@link #propagatingSenderTracingObservationHandler(Tracer, Propagator)}.
+ */
+ public static final int SENDER_TRACING_OBSERVATION_HANDLER_ORDER = 2000;
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnBean(Tracer.class)
+ @Order(DEFAULT_TRACING_OBSERVATION_HANDLER_ORDER)
+ public DefaultTracingObservationHandler defaultTracingObservationHandler(Tracer tracer) {
+ return new DefaultTracingObservationHandler(tracer);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnBean({ Tracer.class, Propagator.class })
+ @Order(SENDER_TRACING_OBSERVATION_HANDLER_ORDER)
+ public PropagatingSenderTracingObservationHandler<?> propagatingSenderTracingObservationHandler(Tracer tracer,
+ Propagator propagator) {
+ return new PropagatingSenderTracingObservationHandler<>(tracer, propagator);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnBean({ Tracer.class, Propagator.class })
+ @Order(RECEIVER_TRACING_OBSERVATION_HANDLER_ORDER)
+ public PropagatingReceiverTracingObservationHandler<?> propagatingReceiverTracingObservationHandler(Tracer tracer,
+ Propagator propagator) {
+ return new PropagatingReceiverTracingObservationHandler<>(tracer, propagator);
+ }
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/OpenTelemetryAutoConfiguration.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/OpenTelemetryAutoConfiguration.java
new file mode 100644
index 00000000000..3bd68618961
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/OpenTelemetryAutoConfiguration.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2012-2023 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.tracing;
+
+import java.util.Collections;
+import java.util.List;
+
+import io.micrometer.tracing.SpanCustomizer;
+import io.micrometer.tracing.exporter.SpanExportingPredicate;
+import io.micrometer.tracing.exporter.SpanFilter;
+import io.micrometer.tracing.exporter.SpanReporter;
+import io.micrometer.tracing.otel.bridge.CompositeSpanExporter;
+import io.micrometer.tracing.otel.bridge.EventListener;
+import io.micrometer.tracing.otel.bridge.EventPublishingContextWrapper;
+import io.micrometer.tracing.otel.bridge.OtelBaggageManager;
+import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;
+import io.micrometer.tracing.otel.bridge.OtelPropagator;
+import io.micrometer.tracing.otel.bridge.OtelSpanCustomizer;
+import io.micrometer.tracing.otel.bridge.OtelTracer;
+import io.micrometer.tracing.otel.bridge.OtelTracer.EventPublisher;
+import io.micrometer.tracing.otel.bridge.Slf4JBaggageEventListener;
+import io.micrometer.tracing.otel.bridge.Slf4JEventListener;
+import io.micrometer.tracing.otel.propagation.BaggageTextMapPropagator;
+import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.trace.Tracer;
+import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
+import io.opentelemetry.context.ContextStorage;
+import io.opentelemetry.context.propagation.ContextPropagators;
+import io.opentelemetry.context.propagation.TextMapPropagator;
+import io.opentelemetry.extension.trace.propagation.B3Propagator;
+import io.opentelemetry.sdk.OpenTelemetrySdk;
+import io.opentelemetry.sdk.resources.Resource;
+import io.opentelemetry.sdk.trace.SdkTracerProvider;
+import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
+import io.opentelemetry.sdk.trace.SpanProcessor;
+import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
+import io.opentelemetry.sdk.trace.export.SpanExporter;
+import io.opentelemetry.sdk.trace.samplers.Sampler;
+import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.SpringBootVersion;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry.
+ */
+@AutoConfiguration(before = MicrometerTracingAutoConfiguration.class)
+@ConditionalOnEnabledTracing
+@ConditionalOnClass({ OtelTracer.class, SdkTracerProvider.class, OpenTelemetry.class })
+@EnableConfigurationProperties(TracingProperties.class)
+public class OpenTelemetryAutoConfiguration {
+
+ /**
+ * Default value for application name if {@code spring.application.name} is not set.
+ */
+ private static final String DEFAULT_APPLICATION_NAME = "application";
+
+ private final TracingProperties tracingProperties;
+
+ OpenTelemetryAutoConfiguration(TracingProperties tracingProperties) {
+ this.tracingProperties = tracingProperties;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ OpenTelemetry openTelemetry(SdkTracerProvider sdkTracerProvider, ContextPropagators contextPropagators) {
+ return OpenTelemetrySdk.builder()
+ .setTracerProvider(sdkTracerProvider)
+ .setPropagators(contextPropagators)
+ .build();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ SdkTracerProvider otelSdkTracerProvider(Environment environment, ObjectProvider<SpanProcessor> spanProcessors,
+ Sampler sampler) {
+ String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
+ SdkTracerProviderBuilder builder = SdkTracerProvider.builder()
+ .setSampler(sampler)
+ .setResource(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName)));
+ spanProcessors.orderedStream().forEach(builder::addSpanProcessor);
+ return builder.build();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ ContextPropagators otelContextPropagators(ObjectProvider<TextMapPropagator> textMapPropagators) {
+ return ContextPropagators.create(TextMapPropagator.composite(textMapPropagators.orderedStream().toList()));
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ Sampler otelSampler() {
+ Sampler rootSampler = Sampler.traceIdRatioBased(this.tracingProperties.getSampling().getProbability());
+ return Sampler.parentBased(rootSampler);
+ }
+
+ @Bean
+ SpanProcessor otelSpanProcessor(ObjectProvider<SpanExporter> spanExporters,
+ ObjectProvider<SpanExportingPredicate> spanExportingPredicates, ObjectProvider<SpanReporter> spanReporters,
+ ObjectProvider<SpanFilter> spanFilters) {
+ return BatchSpanProcessor
+ .builder(new CompositeSpanExporter(spanExporters.orderedStream().toList(),
+ spanExportingPredicates.orderedStream().toList(), spanReporters.orderedStream().toList(),
+ spanFilters.orderedStream().toList()))
+ .build();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ Tracer otelTracer(OpenTelemetry openTelemetry) {
+ return openTelemetry.getTracer("org.springframework.boot", SpringBootVersion.getVersion());
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(io.micrometer.tracing.Tracer.class)
+ OtelTracer micrometerOtelTracer(Tracer tracer, EventPublisher eventPublisher,
+ OtelCurrentTraceContext otelCurrentTraceContext) {
+ return new OtelTracer(tracer, otelCurrentTraceContext, eventPublisher,
+ new OtelBaggageManager(otelCurrentTraceContext, this.tracingProperties.getBaggage().getRemoteFields(),
+ Collections.emptyList()));
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ OtelPropagator otelPropagator(ContextPropagators contextPropagators, Tracer tracer) {
+ return new OtelPropagator(contextPropagators, tracer);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ EventPublisher otelTracerEventPublisher(List<EventListener> eventListeners) {
+ return new OTelEventPublisher(eventListeners);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ OtelCurrentTraceContext otelCurrentTraceContext(EventPublisher publisher) {
+ ContextStorage.addWrapper(new EventPublishingContextWrapper(publisher));
+ return new OtelCurrentTraceContext();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ Slf4JEventListener otelSlf4JEventListener() {
+ return new Slf4JEventListener();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(SpanCustomizer.class)
+ OtelSpanCustomizer otelSpanCustomizer() {
+ return new OtelSpanCustomizer();
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnProperty(prefix = "management.tracing.baggage", name = "enabled", matchIfMissing = true)
+ static class BaggageConfiguration {
+
+ private final TracingProperties tracingProperties;
+
+ BaggageConfiguration(TracingProperties tracingProperties) {
+ this.tracingProperties = tracingProperties;
+ }
+
+ @Bean
+ @ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "W3C",
+ matchIfMissing = true)
+ TextMapPropagator w3cTextMapPropagatorWithBaggage(OtelCurrentTraceContext otelCurrentTraceContext) {
+ List<String> remoteFields = this.tracingProperties.getBaggage().getRemoteFields();
+ return TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(),
+ W3CBaggagePropagator.getInstance(), new BaggageTextMapPropagator(remoteFields,
+ new OtelBaggageManager(otelCurrentTraceContext, remoteFields, Collections.emptyList())));
+ }
+
+ @Bean
+ @ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "B3")
+ TextMapPropagator b3BaggageTextMapPropagator(OtelCurrentTraceContext otelCurrentTraceContext) {
+ List<String> remoteFields = this.tracingProperties.getBaggage().getRemoteFields();
+ return TextMapPropagator.composite(B3Propagator.injectingSingleHeader(),
+ new BaggageTextMapPropagator(remoteFields,
+ new OtelBaggageManager(otelCurrentTraceContext, remoteFields, Collections.emptyList())));
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(prefix = "management.tracing.baggage.correlation", name = "enabled",
+ matchIfMissing = true)
+ Slf4JBaggageEventListener otelSlf4JBaggageEventListener() {
+ return new Slf4JBaggageEventListener(this.tracingProperties.getBaggage().getCorrelation().getFields());
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnProperty(prefix = "management.tracing.baggage", name = "enabled", havingValue = "false")
+ static class NoBaggageConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "B3")
+ B3Propagator b3TextMapPropagator() {
+ return B3Propagator.injectingSingleHeader();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "W3C",
+ matchIfMissing = true)
+ W3CTraceContextPropagator w3cTextMapPropagatorWithoutBaggage() {
+ return W3CTraceContextPropagator.getInstance();
+ }
+
+ }
+
+ static class OTelEventPublisher implements EventPublisher {
+
+ private final List<EventListener> listeners;
+
+ OTelEventPublisher(List<EventListener> listeners) {
+ this.listeners = listeners;
+ }
+
+ @Override
+ public void publishEvent(Object event) {
+ for (EventListener listener : this.listeners) {
+ listener.onEvent(event);
+ }
+ }
+
+ }
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/TracingProperties.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/TracingProperties.java
new file mode 100644
index 00000000000..e82a06770fc
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/TracingProperties.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.tracing;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * Configuration properties for tracing.
+ */
+@ConfigurationProperties("management.tracing")
+public class TracingProperties {
+
+ /**
+ * Whether auto-configuration of tracing is enabled.
+ */
+ private boolean enabled = true;
+
+ /**
+ * Sampling configuration.
+ */
+ private final Sampling sampling = new Sampling();
+
+ /**
+ * Baggage configuration.
+ */
+ private final Baggage baggage = new Baggage();
+
+ /**
+ * Propagation configuration.
+ */
+ private final Propagation propagation = new Propagation();
+
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public Sampling getSampling() {
+ return this.sampling;
+ }
+
+ public Baggage getBaggage() {
+ return this.baggage;
+ }
+
+ public Propagation getPropagation() {
+ return this.propagation;
+ }
+
+ public static class Sampling {
+
+ /**
+ * Probability in the range from 0.0 to 1.0 that a trace will be sampled.
+ */
+ private float probability = 0.10f;
+
+ public float getProbability() {
+ return this.probability;
+ }
+
+ public void setProbability(float probability) {
+ this.probability = probability;
+ }
+
+ }
+
+ public static class Baggage {
+
+ /**
+ * Whether to enable Micrometer Tracing baggage propagation.
+ */
+ private boolean enabled = true;
+
+ /**
+ * Correlation configuration.
+ */
+ private Correlation correlation = new Correlation();
+
+ /**
+ * List of fields that are referenced the same in-process as it is on the wire.
+ * For example, the field "x-vcap-request-id" would be set as-is including the
+ * prefix.
+ */
+ private List<String> remoteFields = new ArrayList<>();
+
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public Correlation getCorrelation() {
+ return this.correlation;
+ }
+
+ public void setCorrelation(Correlation correlation) {
+ this.correlation = correlation;
+ }
+
+ public List<String> getRemoteFields() {
+ return this.remoteFields;
+ }
+
+ public void setRemoteFields(List<String> remoteFields) {
+ this.remoteFields = remoteFields;
+ }
+
+ public static class Correlation {
+
+ /**
+ * Whether to enable correlation of the baggage context with logging contexts.
+ */
+ private boolean enabled = true;
+
+ /**
+ * List of fields that should be correlated with the logging context. That
+ * means that these fields would end up as key-value pairs in e.g. MDC.
+ */
+ private List<String> fields = new ArrayList<>();
+
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public List<String> getFields() {
+ return this.fields;
+ }
+
+ public void setFields(List<String> fields) {
+ this.fields = fields;
+ }
+
+ }
+
+ }
+
+ public static class Propagation {
+
+ /**
+ * Tracing context propagation type.
+ */
+ private PropagationType type = PropagationType.W3C;
+
+ public PropagationType getType() {
+ return this.type;
+ }
+
+ public void setType(PropagationType type) {
+ this.type = type;
+ }
+
+ enum PropagationType {
+
+ /**
+ * B3 propagation type.
+ */
+ B3,
+
+ /**
+ * W3C propagation type.
+ */
+ W3C
+
+ }
+
+ }
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/package-info.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/package-info.java
new file mode 100644
index 00000000000..a2ac950a07b
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://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.
+ */
+
+/**
+ * The whole package is taken from https://github.com/spring-projects/spring-boot/tree/v3.0.2/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing and should be deleted for versions using Spring Boot 3.x. We're copying these classes to allow Micrometer Observation usage together with Boot 2.7.
+ */
+package org.apache.camel.observation.starter.tracing;
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/prometheus/PrometheusExemplarsAutoConfiguration.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/prometheus/PrometheusExemplarsAutoConfiguration.java
new file mode 100644
index 00000000000..d4c82461ac6
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/prometheus/PrometheusExemplarsAutoConfiguration.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.tracing.prometheus;
+
+import io.micrometer.tracing.Span;
+import io.micrometer.tracing.Tracer;
+import io.prometheus.client.exemplars.tracer.common.SpanContextSupplier;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusMetricsExportAutoConfiguration;
+import org.apache.camel.observation.starter.tracing.ConditionalOnEnabledTracing;
+import org.apache.camel.observation.starter.tracing.MicrometerTracingAutoConfiguration;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.util.function.SingletonSupplier;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for Prometheus Exemplars with
+ * Micrometer Tracing.
+ */
+@AutoConfiguration(before = PrometheusMetricsExportAutoConfiguration.class,
+ after = MicrometerTracingAutoConfiguration.class)
+@ConditionalOnBean(Tracer.class)
+@ConditionalOnClass({ Tracer.class, SpanContextSupplier.class })
+@ConditionalOnEnabledTracing
+public class PrometheusExemplarsAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ SpanContextSupplier spanContextSupplier(ObjectProvider<Tracer> tracerProvider) {
+ return new LazyTracingSpanContextSupplier(tracerProvider);
+ }
+
+ /**
+ * Since the MeterRegistry can depend on the {@link Tracer} (Exemplars) and the
+ * {@link Tracer} can depend on the MeterRegistry (recording metrics), this
+ * {@link SpanContextSupplier} breaks the cycle by lazily loading the {@link Tracer}.
+ */
+ static class LazyTracingSpanContextSupplier implements SpanContextSupplier {
+
+ private final SingletonSupplier<Tracer> tracer;
+
+ LazyTracingSpanContextSupplier(ObjectProvider<Tracer> tracerProvider) {
+ this.tracer = SingletonSupplier.of(tracerProvider::getObject);
+ }
+
+ @Override
+ public String getTraceId() {
+ Span currentSpan = currentSpan();
+ return (currentSpan != null) ? currentSpan.context().traceId() : null;
+ }
+
+ @Override
+ public String getSpanId() {
+ Span currentSpan = currentSpan();
+ return (currentSpan != null) ? currentSpan.context().spanId() : null;
+ }
+
+ // Will be applicable for 0.16.0
+// @Override
+// public boolean isSampled() {
+// Span currentSpan = currentSpan();
+// if (currentSpan == null) {
+// return false;
+// }
+// Boolean sampled = currentSpan.context().sampled();
+// return sampled != null && sampled;
+// }
+
+ private Span currentSpan() {
+ return this.tracer.obtain().currentSpan();
+ }
+
+ }
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/prometheus/package-info.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/prometheus/package-info.java
new file mode 100644
index 00000000000..dda38bf6f7c
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/prometheus/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://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.
+ */
+
+/**
+ * The whole package is taken from https://github.com/spring-projects/spring-boot/tree/v3.0.2/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/prometheus and should be deleted for versions using Spring Boot 3.x. We're copying these classes to allow Micrometer Observation usage together with Boot 2.7.
+ */
+package org.apache.camel.observation.starter.tracing.prometheus;
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/HttpSender.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/HttpSender.java
new file mode 100644
index 00000000000..030c3c98e91
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/HttpSender.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.tracing.zipkin;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.zip.GZIPOutputStream;
+
+import zipkin2.Call;
+import zipkin2.CheckResult;
+import zipkin2.codec.Encoding;
+import zipkin2.reporter.BytesMessageEncoder;
+import zipkin2.reporter.ClosedSenderException;
+import zipkin2.reporter.Sender;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.util.unit.DataSize;
+
+/**
+ * A Zipkin {@link Sender} that uses an HTTP client to send JSON spans. Supports automatic
+ * compression with gzip.
+ */
+abstract class HttpSender extends Sender {
+
+ private static final DataSize MESSAGE_MAX_SIZE = DataSize.ofKilobytes(512);
+
+ private volatile boolean closed;
+
+ @Override
+ public Encoding encoding() {
+ return Encoding.JSON;
+ }
+
+ @Override
+ public int messageMaxBytes() {
+ return (int) MESSAGE_MAX_SIZE.toBytes();
+ }
+
+ @Override
+ public int messageSizeInBytes(List<byte[]> encodedSpans) {
+ return encoding().listSizeInBytes(encodedSpans);
+ }
+
+ @Override
+ public int messageSizeInBytes(int encodedSizeInBytes) {
+ return encoding().listSizeInBytes(encodedSizeInBytes);
+ }
+
+ @Override
+ public CheckResult check() {
+ try {
+ sendSpans(Collections.emptyList()).execute();
+ return CheckResult.OK;
+ }
+ catch (IOException | RuntimeException ex) {
+ return CheckResult.failed(ex);
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ this.closed = true;
+ }
+
+ /**
+ * The returned {@link HttpPostCall} will send span(s) as a POST to a zipkin endpoint
+ * when executed.
+ * @param batchedEncodedSpans list of encoded spans as a byte array
+ * @return an instance of a Zipkin {@link Call} which can be executed
+ */
+ protected abstract HttpPostCall sendSpans(byte[] batchedEncodedSpans);
+
+ @Override
+ public Call<Void> sendSpans(List<byte[]> encodedSpans) {
+ if (this.closed) {
+ throw new ClosedSenderException();
+ }
+ return sendSpans(BytesMessageEncoder.JSON.encode(encodedSpans));
+ }
+
+ abstract static class HttpPostCall extends Call.Base<Void> {
+
+ /**
+ * Only use gzip compression on data which is bigger than this in bytes.
+ */
+ private static final DataSize COMPRESSION_THRESHOLD = DataSize.ofKilobytes(1);
+
+ private final byte[] body;
+
+ HttpPostCall(byte[] body) {
+ this.body = body;
+ }
+
+ protected byte[] getBody() {
+ if (needsCompression()) {
+ return compress(this.body);
+ }
+ return this.body;
+ }
+
+ protected byte[] getUncompressedBody() {
+ return this.body;
+ }
+
+ protected HttpHeaders getDefaultHeaders() {
+ HttpHeaders headers = new HttpHeaders();
+ headers.set("b3", "0");
+ headers.set("Content-Type", "application/json");
+ if (needsCompression()) {
+ headers.set("Content-Encoding", "gzip");
+ }
+ return headers;
+ }
+
+ private boolean needsCompression() {
+ return this.body.length > COMPRESSION_THRESHOLD.toBytes();
+ }
+
+ private byte[] compress(byte[] input) {
+ ByteArrayOutputStream result = new ByteArrayOutputStream();
+ try (GZIPOutputStream gzip = new GZIPOutputStream(result)) {
+ gzip.write(input);
+ }
+ catch (IOException ex) {
+ throw new UncheckedIOException(ex);
+ }
+ return result.toByteArray();
+ }
+
+ }
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinAutoConfiguration.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinAutoConfiguration.java
new file mode 100644
index 00000000000..0828c7937aa
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinAutoConfiguration.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.tracing.zipkin;
+
+import zipkin2.Span;
+import zipkin2.codec.BytesEncoder;
+import zipkin2.codec.SpanBytesEncoder;
+import zipkin2.reporter.Sender;
+
+import org.apache.camel.observation.starter.tracing.ConditionalOnEnabledTracing;
+import org.apache.camel.observation.starter.tracing.zipkin.ZipkinConfigurations.BraveConfiguration;
+import org.apache.camel.observation.starter.tracing.zipkin.ZipkinConfigurations.OpenTelemetryConfiguration;
+import org.apache.camel.observation.starter.tracing.zipkin.ZipkinConfigurations.ReporterConfiguration;
+import org.apache.camel.observation.starter.tracing.zipkin.ZipkinConfigurations.SenderConfiguration;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Import;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for Zipkin.
+ *
+ * It uses imports on {@link ZipkinConfigurations} to guarantee the correct configuration
+ * ordering.
+ */
+@AutoConfiguration(after = RestTemplateAutoConfiguration.class)
+@ConditionalOnClass(Sender.class)
+@Import({ SenderConfiguration.class, ReporterConfiguration.class, BraveConfiguration.class,
+ OpenTelemetryConfiguration.class })
+@ConditionalOnEnabledTracing
+public class ZipkinAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public BytesEncoder<Span> spanBytesEncoder() {
+ return SpanBytesEncoder.JSON_V2;
+ }
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinConfigurations.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinConfigurations.java
new file mode 100644
index 00000000000..69e484fa4d7
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinConfigurations.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2012-2023 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.tracing.zipkin;
+
+import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;
+import zipkin2.Span;
+import zipkin2.codec.BytesEncoder;
+import zipkin2.reporter.AsyncReporter;
+import zipkin2.reporter.Reporter;
+import zipkin2.reporter.Sender;
+import zipkin2.reporter.brave.ZipkinSpanHandler;
+import zipkin2.reporter.urlconnection.URLConnectionSender;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.reactive.function.client.WebClient;
+
+/**
+ * Configurations for Zipkin. Those are imported by {@link ZipkinAutoConfiguration}.=
+ */
+class ZipkinConfigurations {
+
+ @Configuration(proxyBeanMethods = false)
+ @Import({ UrlConnectionSenderConfiguration.class, WebClientSenderConfiguration.class,
+ RestTemplateSenderConfiguration.class })
+ static class SenderConfiguration {
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass(URLConnectionSender.class)
+ @EnableConfigurationProperties(ZipkinProperties.class)
+ static class UrlConnectionSenderConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean(Sender.class)
+ URLConnectionSender urlConnectionSender(ZipkinProperties properties) {
+ URLConnectionSender.Builder builder = URLConnectionSender.newBuilder();
+ builder.connectTimeout((int) properties.getConnectTimeout().toMillis());
+ builder.readTimeout((int) properties.getReadTimeout().toMillis());
+ builder.endpoint(properties.getEndpoint());
+ return builder.build();
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass(RestTemplate.class)
+ @EnableConfigurationProperties(ZipkinProperties.class)
+ static class RestTemplateSenderConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean(Sender.class)
+ ZipkinRestTemplateSender restTemplateSender(ZipkinProperties properties,
+ ObjectProvider<ZipkinRestTemplateBuilderCustomizer> customizers) {
+ RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder()
+ .setConnectTimeout(properties.getConnectTimeout())
+ .setReadTimeout(properties.getReadTimeout());
+ restTemplateBuilder = applyCustomizers(restTemplateBuilder, customizers);
+ return new ZipkinRestTemplateSender(properties.getEndpoint(), restTemplateBuilder.build());
+ }
+
+ private RestTemplateBuilder applyCustomizers(RestTemplateBuilder restTemplateBuilder,
+ ObjectProvider<ZipkinRestTemplateBuilderCustomizer> customizers) {
+ Iterable<ZipkinRestTemplateBuilderCustomizer> orderedCustomizers = () -> customizers.orderedStream()
+ .iterator();
+ RestTemplateBuilder currentBuilder = restTemplateBuilder;
+ for (ZipkinRestTemplateBuilderCustomizer customizer : orderedCustomizers) {
+ currentBuilder = customizer.customize(currentBuilder);
+ }
+ return currentBuilder;
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass(WebClient.class)
+ @EnableConfigurationProperties(ZipkinProperties.class)
+ static class WebClientSenderConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean(Sender.class)
+ ZipkinWebClientSender webClientSender(ZipkinProperties properties,
+ ObjectProvider<ZipkinWebClientBuilderCustomizer> customizers) {
+ WebClient.Builder builder = WebClient.builder();
+ customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
+ return new ZipkinWebClientSender(properties.getEndpoint(), builder.build());
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ static class ReporterConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnBean(Sender.class)
+ AsyncReporter<Span> spanReporter(Sender sender, BytesEncoder<Span> encoder) {
+ return AsyncReporter.builder(sender).build(encoder);
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass(ZipkinSpanHandler.class)
+ static class BraveConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnBean(Reporter.class)
+ ZipkinSpanHandler zipkinSpanHandler(Reporter<Span> spanReporter) {
+ return (ZipkinSpanHandler) ZipkinSpanHandler.newBuilder(spanReporter).build();
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass(ZipkinSpanExporter.class)
+ static class OpenTelemetryConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnBean(Sender.class)
+ ZipkinSpanExporter zipkinSpanExporter(BytesEncoder<Span> encoder, Sender sender) {
+ return ZipkinSpanExporter.builder().setEncoder(encoder).setSender(sender).build();
+ }
+
+ }
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinProperties.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinProperties.java
new file mode 100644
index 00000000000..d1f9b1dd1b1
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinProperties.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.tracing.zipkin;
+
+import java.time.Duration;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * Configuration properties for {@link ZipkinAutoConfiguration}.=
+ */
+@ConfigurationProperties("management.zipkin.tracing")
+public class ZipkinProperties {
+
+ /**
+ * URL to the Zipkin API.
+ */
+ private String endpoint = "http://localhost:9411/api/v2/spans";
+
+ /**
+ * Connection timeout for requests to Zipkin.
+ */
+ private Duration connectTimeout = Duration.ofSeconds(1);
+
+ /**
+ * Read timeout for requests to Zipkin.
+ */
+ private Duration readTimeout = Duration.ofSeconds(10);
+
+ public String getEndpoint() {
+ return this.endpoint;
+ }
+
+ public void setEndpoint(String endpoint) {
+ this.endpoint = endpoint;
+ }
+
+ public Duration getConnectTimeout() {
+ return this.connectTimeout;
+ }
+
+ public void setConnectTimeout(Duration connectTimeout) {
+ this.connectTimeout = connectTimeout;
+ }
+
+ public Duration getReadTimeout() {
+ return this.readTimeout;
+ }
+
+ public void setReadTimeout(Duration readTimeout) {
+ this.readTimeout = readTimeout;
+ }
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinRestTemplateBuilderCustomizer.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinRestTemplateBuilderCustomizer.java
new file mode 100644
index 00000000000..de5a66b95b5
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinRestTemplateBuilderCustomizer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.tracing.zipkin;
+
+import org.springframework.boot.web.client.RestTemplateBuilder;
+
+/**
+ * Callback interface that can be implemented by beans wishing to customize the
+ * {@link RestTemplateBuilder} used to send spans to Zipkin.=
+ */
+@FunctionalInterface
+public interface ZipkinRestTemplateBuilderCustomizer {
+
+ /**
+ * Customize the rest template builder.
+ * @param restTemplateBuilder the {@code RestTemplateBuilder} to customize
+ * @return the customized {@code RestTemplateBuilder}
+ */
+ RestTemplateBuilder customize(RestTemplateBuilder restTemplateBuilder);
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinRestTemplateSender.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinRestTemplateSender.java
new file mode 100644
index 00000000000..8a6603b8e19
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinRestTemplateSender.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.tracing.zipkin;
+
+import zipkin2.Call;
+import zipkin2.Callback;
+
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * An {@link HttpSender} which uses {@link RestTemplate} for HTTP communication.=
+ */
+class ZipkinRestTemplateSender extends HttpSender {
+
+ private final String endpoint;
+
+ private final RestTemplate restTemplate;
+
+ ZipkinRestTemplateSender(String endpoint, RestTemplate restTemplate) {
+ this.endpoint = endpoint;
+ this.restTemplate = restTemplate;
+ }
+
+ @Override
+ public HttpPostCall sendSpans(byte[] batchedEncodedSpans) {
+ return new RestTemplateHttpPostCall(this.endpoint, batchedEncodedSpans, this.restTemplate);
+ }
+
+ private static class RestTemplateHttpPostCall extends HttpPostCall {
+
+ private final String endpoint;
+
+ private final RestTemplate restTemplate;
+
+ RestTemplateHttpPostCall(String endpoint, byte[] body, RestTemplate restTemplate) {
+ super(body);
+ this.endpoint = endpoint;
+ this.restTemplate = restTemplate;
+ }
+
+ @Override
+ public Call<Void> clone() {
+ return new RestTemplateHttpPostCall(this.endpoint, getUncompressedBody(), this.restTemplate);
+ }
+
+ @Override
+ protected Void doExecute() {
+ HttpEntity<byte[]> request = new HttpEntity<>(getBody(), getDefaultHeaders());
+ this.restTemplate.exchange(this.endpoint, HttpMethod.POST, request, Void.class);
+ return null;
+ }
+
+ @Override
+ protected void doEnqueue(Callback<Void> callback) {
+ try {
+ doExecute();
+ callback.onSuccess(null);
+ }
+ catch (Exception ex) {
+ callback.onError(ex);
+ }
+ }
+
+ }
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinWebClientBuilderCustomizer.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinWebClientBuilderCustomizer.java
new file mode 100644
index 00000000000..542d226bc38
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinWebClientBuilderCustomizer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.tracing.zipkin;
+
+import org.springframework.web.reactive.function.client.WebClient;
+import org.springframework.web.reactive.function.client.WebClient.Builder;
+
+/**
+ * Callback interface that can be implemented by beans wishing to customize the
+ * {@link Builder} used to send spans to Zipkin.
+ */
+@FunctionalInterface
+public interface ZipkinWebClientBuilderCustomizer {
+
+ /**
+ * Customize the web client builder.
+ * @param webClientBuilder the {@code WebClient.Builder} to customize
+ */
+ void customize(WebClient.Builder webClientBuilder);
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinWebClientSender.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinWebClientSender.java
new file mode 100644
index 00000000000..8986af26dac
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/ZipkinWebClientSender.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2012-2023 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.observation.starter.tracing.zipkin;
+
+import reactor.core.publisher.Mono;
+import zipkin2.Call;
+import zipkin2.Callback;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.reactive.function.client.WebClient;
+
+/**
+ * An {@link HttpSender} which uses {@link WebClient} for HTTP communication.
+ */
+class ZipkinWebClientSender extends HttpSender {
+
+ private final String endpoint;
+
+ private final WebClient webClient;
+
+ ZipkinWebClientSender(String endpoint, WebClient webClient) {
+ this.endpoint = endpoint;
+ this.webClient = webClient;
+ }
+
+ @Override
+ public HttpPostCall sendSpans(byte[] batchedEncodedSpans) {
+ return new WebClientHttpPostCall(this.endpoint, batchedEncodedSpans, this.webClient);
+ }
+
+ private static class WebClientHttpPostCall extends HttpPostCall {
+
+ private final String endpoint;
+
+ private final WebClient webClient;
+
+ WebClientHttpPostCall(String endpoint, byte[] body, WebClient webClient) {
+ super(body);
+ this.endpoint = endpoint;
+ this.webClient = webClient;
+ }
+
+ @Override
+ public Call<Void> clone() {
+ return new WebClientHttpPostCall(this.endpoint, getUncompressedBody(), this.webClient);
+ }
+
+ @Override
+ protected Void doExecute() {
+ sendRequest().block();
+ return null;
+ }
+
+ @Override
+ protected void doEnqueue(Callback<Void> callback) {
+ sendRequest().subscribe((entity) -> callback.onSuccess(null), callback::onError);
+ }
+
+ private Mono<ResponseEntity<Void>> sendRequest() {
+ return this.webClient.post()
+ .uri(this.endpoint)
+ .headers(this::addDefaultHeaders)
+ .bodyValue(getBody())
+ .retrieve()
+ .toBodilessEntity();
+ }
+
+ private void addDefaultHeaders(HttpHeaders headers) {
+ headers.addAll(getDefaultHeaders());
+ }
+
+ }
+
+}
diff --git a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/package-info.java b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/package-info.java
new file mode 100644
index 00000000000..fc9318fa5c0
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/tracing/zipkin/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://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.
+ */
+
+/**
+ * The whole package is taken from https://github.com/spring-projects/spring-boot/tree/v3.0.2/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/zipkin and should be deleted for versions using Spring Boot 3.x. We're copying these classes to allow Micrometer Observation usage together with Boot 2.7.
+ */
+package org.apache.camel.observation.starter.tracing.zipkin;
diff --git a/components-starter/camel-observation-starter/src/main/resources/META-INF/LICENSE.txt b/components-starter/camel-observation-starter/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 00000000000..6b0b1270ff0
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
+
diff --git a/components-starter/camel-observation-starter/src/main/resources/META-INF/NOTICE.txt b/components-starter/camel-observation-starter/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 00000000000..2e215bf2e6b
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+ =========================================================================
+ == NOTICE file corresponding to the section 4 d of ==
+ == the Apache License, Version 2.0, ==
+ == in this case for the Apache Camel distribution. ==
+ =========================================================================
+
+ This product includes software developed by
+ The Apache Software Foundation (http://www.apache.org/).
+
+ Please read the different LICENSE files present in the licenses directory of
+ this distribution.
diff --git a/components-starter/camel-observation-starter/src/main/resources/META-INF/spring.factories b/components-starter/camel-observation-starter/src/main/resources/META-INF/spring.factories
new file mode 100644
index 00000000000..1deca6da6c2
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,24 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.apache.camel.observation.starter.ObservationAutoConfiguration,\
+org.apache.camel.observation.starter.observation.ObservationAutoConfiguration,\
+org.apache.camel.observation.starter.tracing.BraveAutoConfiguration,\
+org.apache.camel.observation.starter.tracing.MicrometerTracingAutoConfiguration,\
+org.apache.camel.observation.starter.tracing.OpenTelemetryAutoConfiguration,\
+org.apache.camel.observation.starter.tracing.prometheus.PrometheusExemplarsAutoConfiguration,\
+org.apache.camel.observation.starter.tracing.zipkin.ZipkinAutoConfiguration
diff --git a/components-starter/camel-observation-starter/src/main/resources/META-INF/spring.provides b/components-starter/camel-observation-starter/src/main/resources/META-INF/spring.provides
new file mode 100644
index 00000000000..27fc71819a7
--- /dev/null
+++ b/components-starter/camel-observation-starter/src/main/resources/META-INF/spring.provides
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+provides: camel-observation
diff --git a/components-starter/camel-stax-starter/src/main/docs/stax.json b/components-starter/camel-stax-starter/src/main/docs/stax.json
index e0a86f4c9a2..4b131b06158 100644
--- a/components-starter/camel-stax-starter/src/main/docs/stax.json
+++ b/components-starter/camel-stax-starter/src/main/docs/stax.json
@@ -64,8 +64,7 @@
"name": "camel.language.xtokenize.mode",
"type": "java.lang.String",
"description": "The extraction mode. The available extraction modes are: i - injecting the contextual namespace bindings into the extracted token (default) w - wrapping the extracted token in its ancestor context u - unwrapping the extracted token to its child content t - extracting the text content of the specified element",
- "sourceType": "org.apache.camel.language.xtokenizer.springboot.XMLTokenizeLanguageConfiguration",
- "defaultValue": "i"
+ "sourceType": "org.apache.camel.language.xtokenizer.springboot.XMLTokenizeLanguageConfiguration"
},
{
"name": "camel.language.xtokenize.namespace",
diff --git a/components-starter/camel-stax-starter/src/main/java/org/apache/camel/language/xtokenizer/springboot/XMLTokenizeLanguageConfiguration.java b/components-starter/camel-stax-starter/src/main/java/org/apache/camel/language/xtokenizer/springboot/XMLTokenizeLanguageConfiguration.java
index 978784541ff..56506cf39cb 100644
--- a/components-starter/camel-stax-starter/src/main/java/org/apache/camel/language/xtokenizer/springboot/XMLTokenizeLanguageConfiguration.java
+++ b/components-starter/camel-stax-starter/src/main/java/org/apache/camel/language/xtokenizer/springboot/XMLTokenizeLanguageConfiguration.java
@@ -45,7 +45,7 @@ public class XMLTokenizeLanguageConfiguration
* extracted token to its child content t - extracting the text content of
* the specified element
*/
- private String mode = "i";
+ private String mode;
/**
* Injects the XML Namespaces of prefix - uri mappings
*/
diff --git a/components-starter/pom.xml b/components-starter/pom.xml
index fcd2c825097..7e1dba98ac4 100644
--- a/components-starter/pom.xml
+++ b/components-starter/pom.xml
@@ -335,6 +335,7 @@
<module>camel-netty-starter</module>
<module>camel-nitrite-starter</module>
<module>camel-oaipmh-starter</module>
+ <module>camel-observation-starter</module>
<module>camel-ognl-starter</module>
<module>camel-olingo2-starter</module>
<module>camel-olingo4-starter</module>
diff --git a/tooling/camel-spring-boot-bom/pom.xml b/tooling/camel-spring-boot-bom/pom.xml
index 4689553f92e..562f4d2f364 100644
--- a/tooling/camel-spring-boot-bom/pom.xml
+++ b/tooling/camel-spring-boot-bom/pom.xml
@@ -1208,6 +1208,11 @@
<artifactId>camel-oaipmh-starter</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>camel-observation-starter</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-ognl-starter</artifactId>
diff --git a/tooling/camel-spring-boot-dependencies/pom.xml b/tooling/camel-spring-boot-dependencies/pom.xml
index fdec3ca824c..9bd0e946836 100644
--- a/tooling/camel-spring-boot-dependencies/pom.xml
+++ b/tooling/camel-spring-boot-dependencies/pom.xml
@@ -1421,6 +1421,11 @@
<artifactId>camel-oaipmh-starter</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>camel-observation-starter</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-ognl-starter</artifactId>