diff --git a/components/camel-observation/src/main/resources/META-INF/services/org.apache.camel.tracing.SpanDecorator b/components/camel-observation/src/main/resources/META-INF/services/org.apache.camel.tracing.SpanDecorator index 36bdfa6d8f1aa..5a13187e27719 100644 --- a/components/camel-observation/src/main/resources/META-INF/services/org.apache.camel.tracing.SpanDecorator +++ b/components/camel-observation/src/main/resources/META-INF/services/org.apache.camel.tracing.SpanDecorator @@ -18,6 +18,7 @@ org.apache.camel.tracing.decorators.AhcSpanDecorator org.apache.camel.tracing.decorators.AmqpSpanDecorator org.apache.camel.tracing.decorators.AzureServiceBusSpanDecorator +org.apache.camel.tracing.decorators.AzureStorageDataLakeSpanDecorator org.apache.camel.tracing.decorators.CometdSpanDecorator org.apache.camel.tracing.decorators.CometdsSpanDecorator org.apache.camel.tracing.decorators.CqlSpanDecorator diff --git a/components/camel-opentelemetry/src/main/resources/META-INF/services/org.apache.camel.tracing.SpanDecorator b/components/camel-opentelemetry/src/main/resources/META-INF/services/org.apache.camel.tracing.SpanDecorator index 36bdfa6d8f1aa..5a13187e27719 100644 --- a/components/camel-opentelemetry/src/main/resources/META-INF/services/org.apache.camel.tracing.SpanDecorator +++ b/components/camel-opentelemetry/src/main/resources/META-INF/services/org.apache.camel.tracing.SpanDecorator @@ -18,6 +18,7 @@ org.apache.camel.tracing.decorators.AhcSpanDecorator org.apache.camel.tracing.decorators.AmqpSpanDecorator org.apache.camel.tracing.decorators.AzureServiceBusSpanDecorator +org.apache.camel.tracing.decorators.AzureStorageDataLakeSpanDecorator org.apache.camel.tracing.decorators.CometdSpanDecorator org.apache.camel.tracing.decorators.CometdsSpanDecorator org.apache.camel.tracing.decorators.CqlSpanDecorator diff --git a/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/AzureStorageDataLakeSpanDecorator.java b/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/AzureStorageDataLakeSpanDecorator.java new file mode 100644 index 0000000000000..01e607fd13ac2 --- /dev/null +++ b/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/AzureStorageDataLakeSpanDecorator.java @@ -0,0 +1,133 @@ +/* + * 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.tracing.decorators; + +import java.time.Duration; +import java.time.OffsetDateTime; +import java.util.Map; + +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; +import org.apache.camel.tracing.SpanAdapter; +import org.apache.camel.tracing.TagConstants; + +public class AzureStorageDataLakeSpanDecorator extends AbstractSpanDecorator { + + static final String STORAGE_DATALAKE_DIRECTORY_NAME = "directoryName"; + static final String STORAGE_DATALAKE_FILE_NAME = "fileName"; + static final String STORAGE_DATALAKE_PATH = "path"; + static final String STORAGE_DATALAKE_TIMEOUT = "timeout"; + static final String STORAGE_DATALAKE_CONTENT_TYPE = "contentType"; + static final String STORAGE_DATALAKE_METADATA = "metadata"; + static final String STORAGE_DATALAKE_LAST_MODIFIED = "lastModified"; + static final String STORAGE_DATALAKE_POSITION = "position"; + static final String STORAGE_DATALAKE_EXPRESSION = "expression"; + + /** + * Constants copied from {@link org.apache.camel.component.azure.storage.datalake.DataLakeConstants} + */ + static final String OPERATION = "CamelAzureStorageDataLakeOperation"; + static final String FILESYSTEM_NAME = "CamelAzureStorageDataLakeFileSystemName"; + static final String DIRECTORY_NAME = "CamelAzureStorageDataLakeDirectoryName"; + static final String FILE_NAME = "CamelAzureStorageDataLakeFileName"; + static final String PATH = "CamelAzureStorageDataLakePath"; + static final String TIMEOUT = "CamelAzureStorageDataLakeTimeout"; + static final String CONTENT_TYPE = "CamelAzureStorageDataLakeContentType"; + static final String METADATA = "CamelAzureStorageDataLakeMetadata"; + static final String LAST_MODIFIED = "CamelAzureStorageDataLakeLastModified"; + static final String POSITION = "CamelAzureStorageDataLakePosition"; + static final String EXPRESSION = "CamelAzureStorageDataLakeExpression"; + + @Override + public String getComponent() { + return "azure-storage-datalake"; + } + + @Override + public String getComponentClassName() { + return "org.apache.camel.component.azure.storage.datalake.DataLakeComponent"; + } + + @Override + public String getOperationName(Exchange exchange, Endpoint endpoint) { + String operation = exchange.getIn().getHeader(OPERATION, String.class); + if (operation == null) { + Map queryParameters = toQueryParameters(endpoint.getEndpointUri()); + return queryParameters.containsKey("operation") + ? queryParameters.get("operation") + : super.getOperationName(exchange, endpoint); + } + return operation; + } + + @Override + public void pre(SpanAdapter span, Exchange exchange, Endpoint endpoint) { + super.pre(span, exchange, endpoint); + span.setTag(TagConstants.DB_SYSTEM, getComponent()); + + String fileSystemName = exchange.getIn().getHeader(FILESYSTEM_NAME, String.class); + if (fileSystemName != null) { + span.setTag(TagConstants.DB_NAME, fileSystemName); + } + + String directoryName = exchange.getIn().getHeader(DIRECTORY_NAME, String.class); + if (directoryName != null) { + span.setTag(STORAGE_DATALAKE_DIRECTORY_NAME, directoryName); + } + + String fileName = exchange.getIn().getHeader(FILE_NAME, String.class); + if (fileName != null) { + span.setTag(STORAGE_DATALAKE_FILE_NAME, fileName); + } + + String path = exchange.getIn().getHeader(PATH, String.class); + if (path != null) { + span.setTag(STORAGE_DATALAKE_PATH, path); + } + + Duration timeout = exchange.getIn().getHeader(TIMEOUT, Duration.class); + if (timeout != null) { + span.setTag(STORAGE_DATALAKE_TIMEOUT, timeout.toString()); + } + + String contentType = exchange.getIn().getHeader(CONTENT_TYPE, String.class); + if (contentType != null) { + span.setTag(STORAGE_DATALAKE_CONTENT_TYPE, contentType); + } + + Map metadata = exchange.getIn().getHeader(METADATA, Map.class); + if (metadata != null) { + span.setTag(STORAGE_DATALAKE_METADATA, metadata.toString()); + } + + OffsetDateTime lastModified = exchange.getIn().getHeader(LAST_MODIFIED, OffsetDateTime.class); + if (lastModified != null) { + span.setTag(STORAGE_DATALAKE_LAST_MODIFIED, lastModified.toString()); + } + + Long position = exchange.getIn().getHeader(POSITION, Long.class); + if (position != null) { + span.setTag(STORAGE_DATALAKE_POSITION, position); + } + + String expression = exchange.getIn().getHeader(EXPRESSION, String.class); + if (expression != null) { + span.setTag(STORAGE_DATALAKE_EXPRESSION, expression); + } + } + +} diff --git a/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/AzureStorageDataLakeSpanDecoratorTest.java b/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/AzureStorageDataLakeSpanDecoratorTest.java new file mode 100644 index 0000000000000..5629774c0e8f4 --- /dev/null +++ b/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/AzureStorageDataLakeSpanDecoratorTest.java @@ -0,0 +1,136 @@ +/* + * 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.tracing.decorators; + +import java.time.Duration; +import java.time.OffsetDateTime; +import java.util.Map; + +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.tracing.MockSpanAdapter; +import org.apache.camel.tracing.TagConstants; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class AzureStorageDataLakeSpanDecoratorTest { + + @Test + public void testGetOperationNameFromHeader() { + String operation = "upload"; + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(message.getHeader(AzureStorageDataLakeSpanDecorator.OPERATION, String.class)).thenReturn(operation); + + AbstractSpanDecorator decorator = new AzureStorageDataLakeSpanDecorator(); + + assertEquals(operation, decorator.getOperationName(exchange, null)); + } + + @Test + public void testGetOperationNameFromHeaderWithEnum() { + operationEnum operation = operationEnum.upload; + + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(message.getHeader(AzureStorageDataLakeSpanDecorator.OPERATION, String.class)) + .thenReturn(operation.toString()); + + AbstractSpanDecorator decorator = new AzureStorageDataLakeSpanDecorator(); + + assertEquals(operation.toString(), decorator.getOperationName(exchange, null)); + } + + @Test + public void testGetOperationNameFromQueryParameter() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("azure-storage-datalake:myAccount/myFileSystem?operation=upload"); + Mockito.when(exchange.getIn()).thenReturn(message); + + AbstractSpanDecorator decorator = new AzureStorageDataLakeSpanDecorator(); + + assertEquals("upload", decorator.getOperationName(exchange, endpoint)); + } + + @Test + public void testPre() { + String fileSystemName = "myFileSystem"; + String directoryName = "myDirectory"; + String fileName = "myFile"; + String path = "myPath"; + String expression = "myExpression"; + String contentType = "myContentType"; + Duration timeout = Duration.ofDays(7); + Map metadata = Map.of("key1", "value1", "key2", "value2"); + OffsetDateTime lastModified = OffsetDateTime.now(); + Long position = 21L; + + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("azure-storage-datalake:account/myFileSystem"); + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(message.getHeader(AzureStorageDataLakeSpanDecorator.FILESYSTEM_NAME, String.class)) + .thenReturn(fileSystemName); + Mockito.when(message.getHeader(AzureStorageDataLakeSpanDecorator.DIRECTORY_NAME, String.class)) + .thenReturn(directoryName); + Mockito.when(message.getHeader(AzureStorageDataLakeSpanDecorator.FILE_NAME, String.class)).thenReturn(fileName); + Mockito.when(message.getHeader(AzureStorageDataLakeSpanDecorator.PATH, String.class)).thenReturn(path); + Mockito.when(message.getHeader(AzureStorageDataLakeSpanDecorator.EXPRESSION, String.class)).thenReturn(expression); + Mockito.when(message.getHeader(AzureStorageDataLakeSpanDecorator.CONTENT_TYPE, String.class)).thenReturn(contentType); + Mockito.when(message.getHeader(AzureStorageDataLakeSpanDecorator.TIMEOUT, Duration.class)).thenReturn(timeout); + Mockito.when(message.getHeader(AzureStorageDataLakeSpanDecorator.METADATA, Map.class)) + .thenReturn(metadata); + Mockito.when(message.getHeader(AzureStorageDataLakeSpanDecorator.LAST_MODIFIED, OffsetDateTime.class)) + .thenReturn(lastModified); + Mockito.when(message.getHeader(AzureStorageDataLakeSpanDecorator.POSITION, Long.class)).thenReturn(position); + + AbstractSpanDecorator decorator = new AzureStorageDataLakeSpanDecorator(); + + MockSpanAdapter span = new MockSpanAdapter(); + + decorator.pre(span, exchange, endpoint); + + assertEquals("azure-storage-datalake", span.tags().get(TagConstants.DB_SYSTEM)); + assertEquals(fileSystemName, span.tags().get(TagConstants.DB_NAME)); + assertEquals(directoryName, span.tags().get(AzureStorageDataLakeSpanDecorator.STORAGE_DATALAKE_DIRECTORY_NAME)); + assertEquals(fileName, span.tags().get(AzureStorageDataLakeSpanDecorator.STORAGE_DATALAKE_FILE_NAME)); + assertEquals(path, span.tags().get(AzureStorageDataLakeSpanDecorator.STORAGE_DATALAKE_PATH)); + assertEquals(expression, span.tags().get(AzureStorageDataLakeSpanDecorator.STORAGE_DATALAKE_EXPRESSION)); + assertEquals(contentType, span.tags().get(AzureStorageDataLakeSpanDecorator.STORAGE_DATALAKE_CONTENT_TYPE)); + assertEquals(timeout.toString(), span.tags().get(AzureStorageDataLakeSpanDecorator.STORAGE_DATALAKE_TIMEOUT)); + assertEquals(metadata.toString(), span.tags().get(AzureStorageDataLakeSpanDecorator.STORAGE_DATALAKE_METADATA)); + assertEquals(lastModified.toString(), + span.tags().get(AzureStorageDataLakeSpanDecorator.STORAGE_DATALAKE_LAST_MODIFIED)); + assertEquals(position, span.tags().get(AzureStorageDataLakeSpanDecorator.STORAGE_DATALAKE_POSITION)); + } + + enum operationEnum { + upload + } + +}