diff --git a/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/AzureMonitorExporterBuilder.java b/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/AzureMonitorExporterBuilder.java index c8d1c6c43fd67..078a1be1d9c80 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/AzureMonitorExporterBuilder.java +++ b/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/AzureMonitorExporterBuilder.java @@ -128,7 +128,7 @@ private BiConsumer createDefaultsPopulator() builder.setResource(resource); builder.addTag(ContextTagKeys.AI_INTERNAL_SDK_VERSION.toString(), VersionGenerator.getSdkVersion()); // TODO (trask) unify these - resourceParser.updateRoleNameAndInstance(builder, resource); + resourceParser.updateRoleNameAndInstanceAndVersion(builder, resource); }; } diff --git a/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/utils/ResourceParser.java b/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/utils/ResourceParser.java index 1bba437593e22..65e4e43dce3fd 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/utils/ResourceParser.java +++ b/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/utils/ResourceParser.java @@ -32,15 +32,7 @@ public ResourceParser() { } // visible for testing - public void updateRoleNameAndInstance(AbstractTelemetryBuilder builder, Resource resource) { - - // update AKS role name and role instance - if (AksResourceAttributes.isAks(resource)) { - builder.addTag(ContextTagKeys.AI_CLOUD_ROLE.toString(), AksResourceAttributes.getAksRoleName(resource)); - builder.addTag(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString(), - AksResourceAttributes.getAksRoleInstance(resource)); - return; - } + public void updateRoleNameAndInstanceAndVersion(AbstractTelemetryBuilder builder, Resource resource) { Map tags = builder.build().getTags(); if (tags == null || !tags.containsKey(ContextTagKeys.AI_CLOUD_ROLE.toString())) { @@ -50,9 +42,20 @@ public void updateRoleNameAndInstance(AbstractTelemetryBuilder builder, Resource if (tags == null || !tags.containsKey(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString())) { builder.addTag(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString(), getRoleInstance(resource)); } + + if (tags == null || !tags.containsKey(ContextTagKeys.AI_APPLICATION_VER.toString())) { + String applicationVersion = resource.getAttribute(ServiceAttributes.SERVICE_VERSION); + if (applicationVersion != null) { + builder.addTag(ContextTagKeys.AI_APPLICATION_VER.toString(), applicationVersion); + } + } } private String getRoleName(Resource resource) { + if (AksResourceAttributes.isAks(resource)) { + return AksResourceAttributes.getAksRoleName(resource); + } + String serviceName = resource.getAttribute(ServiceAttributes.SERVICE_NAME); if (serviceName == null || DEFAULT_SERVICE_NAME.equals(serviceName)) { if (websiteSiteName != null) { @@ -71,6 +74,10 @@ private String getRoleName(Resource resource) { } private String getRoleInstance(Resource resource) { + if (AksResourceAttributes.isAks(resource)) { + return AksResourceAttributes.getAksRoleInstance(resource); + } + String roleInstance = resource.getAttribute(ServiceIncubatingAttributes.SERVICE_INSTANCE_ID); if (roleInstance != null) { return roleInstance; @@ -79,7 +86,11 @@ private String getRoleInstance(Resource resource) { if (roleInstance != null) { return roleInstance; } - return HostName.get(); // default hostname + roleInstance = HostName.get(); // default hostname + if (roleInstance != null) { + return roleInstance; + } + return "unknown"; // this is for backwards compatibility in the Java agent } public static String getWebsiteSiteNameEnvVar(Function envVars) { diff --git a/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/test/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/utils/AksResourceAttributesTest.java b/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/test/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/utils/AksResourceAttributesTest.java index ed388e4190695..5d124bd0f66dc 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/test/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/utils/AksResourceAttributesTest.java +++ b/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/test/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/utils/AksResourceAttributesTest.java @@ -33,7 +33,7 @@ void testDefault() { "cloud.provider=Azure,cloud.platform=azure_aks,service.name=unknown_service:java")); Resource resource = ResourceConfiguration.createEnvironmentResource(config); - new ResourceParser().updateRoleNameAndInstance(builder, resource); + new ResourceParser().updateRoleNameAndInstanceAndVersion(builder, resource); Map map = new HashMap<>(2); map.put(ContextTagKeys.AI_CLOUD_ROLE.toString(), "unknown_service:java"); map.put(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString(), HostName.get()); @@ -46,7 +46,7 @@ void testServiceNameAndK8sPodName() { "cloud.provider=Azure,cloud.platform=azure_aks,service.name=test-service-name,k8s.pod.name=test-pod-name")); Resource resource = ResourceConfiguration.createEnvironmentResource(config); - new ResourceParser().updateRoleNameAndInstance(builder, resource); + new ResourceParser().updateRoleNameAndInstanceAndVersion(builder, resource); Map tags = builder.build().getTags(); assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE.toString())).isEqualTo("test-service-name"); assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString())).isEqualTo("test-pod-name"); @@ -58,7 +58,7 @@ void testK8sDeploymentName() { "cloud.provider=Azure,cloud.platform=azure_aks,service.name=unknown_service:java,k8s.deployment.name=test-deployment-name,k8s.pod.name=test-pod-name")); Resource resource = ResourceConfiguration.createEnvironmentResource(config); - new ResourceParser().updateRoleNameAndInstance(builder, resource); + new ResourceParser().updateRoleNameAndInstanceAndVersion(builder, resource); Map tags = builder.build().getTags(); assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE.toString())).isEqualTo("test-deployment-name"); assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString())).isEqualTo("test-pod-name"); @@ -70,7 +70,7 @@ void testK8sReplicaSetName() { "cloud.provider=Azure,cloud.platform=azure_aks,service.name=unknown_service:java,k8s.replicaset.name=test-replicaset-name,k8s.pod.name=test-pod-name")); Resource resource = ResourceConfiguration.createEnvironmentResource(config); - new ResourceParser().updateRoleNameAndInstance(builder, resource); + new ResourceParser().updateRoleNameAndInstanceAndVersion(builder, resource); Map tags = builder.build().getTags(); assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE.toString())).isEqualTo("test-replicaset-name"); assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString())).isEqualTo("test-pod-name"); @@ -82,7 +82,7 @@ void testK8sStatefulSetName() { "cloud.provider=Azure,cloud.platform=azure_aks,service.name=unknown_service:java,k8s.statefulset.name=test-statefulset-name,k8s.pod.name=test-pod-name")); Resource resource = ResourceConfiguration.createEnvironmentResource(config); - new ResourceParser().updateRoleNameAndInstance(builder, resource); + new ResourceParser().updateRoleNameAndInstanceAndVersion(builder, resource); Map tags = builder.build().getTags(); assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE.toString())).isEqualTo("test-statefulset-name"); assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString())).isEqualTo("test-pod-name"); @@ -94,7 +94,7 @@ void testKsJobName() { "cloud.provider=Azure,cloud.platform=azure_aks,service.name=unknown_service:java,k8s.job.name=test-job-name,k8s.pod.name=test-pod-name")); Resource resource = ResourceConfiguration.createEnvironmentResource(config); - new ResourceParser().updateRoleNameAndInstance(builder, resource); + new ResourceParser().updateRoleNameAndInstanceAndVersion(builder, resource); Map tags = builder.build().getTags(); assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE.toString())).isEqualTo("test-job-name"); assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString())).isEqualTo("test-pod-name"); @@ -106,7 +106,7 @@ void testK8sCronJobName() { "cloud.provider=Azure,cloud.platform=azure_aks,service.name=unknown_service:java,k8s.cronjob.name=test-cronjob-name,k8s.pod.name=test-pod-name")); Resource resource = ResourceConfiguration.createEnvironmentResource(config); - new ResourceParser().updateRoleNameAndInstance(builder, resource); + new ResourceParser().updateRoleNameAndInstanceAndVersion(builder, resource); Map tags = builder.build().getTags(); assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE.toString())).isEqualTo("test-cronjob-name"); assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString())).isEqualTo("test-pod-name"); @@ -118,7 +118,7 @@ void testK8sDaemonSetName() { "cloud.provider=Azure,cloud.platform=azure_aks,service.name=unknown_service:java,k8s.daemonset.name=test-daemonset-name,k8s.pod.name=test-pod-name")); Resource resource = ResourceConfiguration.createEnvironmentResource(config); - new ResourceParser().updateRoleNameAndInstance(builder, resource); + new ResourceParser().updateRoleNameAndInstanceAndVersion(builder, resource); Map tags = builder.build().getTags(); assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE.toString())).isEqualTo("test-daemonset-name"); assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString())).isEqualTo("test-pod-name"); diff --git a/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/test/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/utils/ResourceParserTest.java b/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/test/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/utils/ResourceParserTest.java index 880293f4f7d93..08e3db61e55a3 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/test/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/utils/ResourceParserTest.java +++ b/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/test/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/utils/ResourceParserTest.java @@ -7,8 +7,6 @@ import com.azure.monitor.opentelemetry.autoconfigure.implementation.models.ContextTagKeys; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; -import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; -import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.semconv.ServiceAttributes; import io.opentelemetry.semconv.incubating.ServiceIncubatingAttributes; @@ -16,7 +14,6 @@ import org.junit.jupiter.api.Test; import reactor.util.annotation.Nullable; -import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -25,6 +22,7 @@ class ResourceParserTest { + private static final String DEFAULT_ROLE_NAME = "unknown_service:java"; private static final String DEFAULT_ROLE_INSTANCE = HostName.get(); private MetricTelemetryBuilder builder; @@ -35,54 +33,92 @@ void setup() { @Test void testDefaultResource() { - new ResourceParser().updateRoleNameAndInstance(builder, Resource.create(Attributes.empty())); - assertThat(builder.build().getTags()) - .contains(entry(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString(), DEFAULT_ROLE_INSTANCE)); + new ResourceParser().updateRoleNameAndInstanceAndVersion(builder, Resource.create(Attributes.empty())); + + Map tags = builder.build().getTags(); + assertThat(tags) + .contains(entry(ContextTagKeys.AI_CLOUD_ROLE.toString(), DEFAULT_ROLE_NAME), + entry(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString(), DEFAULT_ROLE_INSTANCE)) + .hasSize(2); } @Test void testServiceNameFromResource() { Resource resource = createTestResource("fake-service-name", null, null); - new ResourceParser().updateRoleNameAndInstance(builder, resource); + + new ResourceParser().updateRoleNameAndInstanceAndVersion(builder, resource); + Map tags = builder.build().getTags(); - assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE.toString())).isEqualTo("fake-service-name"); - assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString())).isEqualTo(DEFAULT_ROLE_INSTANCE); + assertThat(tags) + .contains(entry(ContextTagKeys.AI_CLOUD_ROLE.toString(), "fake-service-name"), + entry(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString(), DEFAULT_ROLE_INSTANCE)) + .hasSize(2); } @Test void testServiceInstanceFromResource() { Resource resource = createTestResource(null, null, "fake-service-instance"); - new ResourceParser().updateRoleNameAndInstance(builder, resource); - assertThat(builder.build().getTags()) - .contains(entry(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString(), "fake-service-instance")); + + new ResourceParser().updateRoleNameAndInstanceAndVersion(builder, resource); + + Map tags = builder.build().getTags(); + assertThat(tags) + .contains(entry(ContextTagKeys.AI_CLOUD_ROLE.toString(), DEFAULT_ROLE_NAME), + entry(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString(), "fake-service-instance")) + .hasSize(2); + } + + @Test + void testVersionFromResource() { + Resource resource = Resource.create(Attributes.of(ServiceAttributes.SERVICE_VERSION, "fake-service-version")); + + new ResourceParser().updateRoleNameAndInstanceAndVersion(builder, resource); + + Map tags = builder.build().getTags(); + assertThat(tags) + .contains(entry(ContextTagKeys.AI_CLOUD_ROLE.toString(), DEFAULT_ROLE_NAME), + entry(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString(), DEFAULT_ROLE_INSTANCE), + entry(ContextTagKeys.AI_APPLICATION_VER.toString(), "fake-service-version")) + .hasSize(3); } @Test void testServiceNamespaceFromResource() { Resource resource = createTestResource(null, "fake-service-namespace", null); - new ResourceParser().updateRoleNameAndInstance(builder, resource); + + new ResourceParser().updateRoleNameAndInstanceAndVersion(builder, resource); + Map tags = builder.build().getTags(); - assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE.toString())).isEqualTo("[fake-service-namespace]"); - assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString())).isEqualTo(DEFAULT_ROLE_INSTANCE); + assertThat(tags) + .contains(entry(ContextTagKeys.AI_CLOUD_ROLE.toString(), "[fake-service-namespace]"), + entry(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString(), DEFAULT_ROLE_INSTANCE)) + .hasSize(2); } @Test void testServiceNameAndInstanceFromResource() { Resource resource = createTestResource("fake-service-name", null, "fake-instance"); - new ResourceParser().updateRoleNameAndInstance(builder, resource); + + new ResourceParser().updateRoleNameAndInstanceAndVersion(builder, resource); + Map tags = builder.build().getTags(); - assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE.toString())).isEqualTo("fake-service-name"); - assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString())).isEqualTo("fake-instance"); + assertThat(tags) + .contains(entry(ContextTagKeys.AI_CLOUD_ROLE.toString(), "fake-service-name"), + entry(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString(), "fake-instance")) + .hasSize(2); } @Test void testServiceNameAndInstanceAndNamespaceFromResource() { Resource resource = createTestResource("fake-service-name", "fake-service-namespace", "fake-instance"); - new ResourceParser().updateRoleNameAndInstance(builder, resource); + + new ResourceParser().updateRoleNameAndInstanceAndVersion(builder, resource); + Map tags = builder.build().getTags(); - assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE.toString())) - .isEqualTo("[fake-service-namespace]/fake-service-name"); - assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString())).isEqualTo("fake-instance"); + assertThat(tags) + .contains(entry(ContextTagKeys.AI_CLOUD_ROLE.toString(), "[fake-service-namespace]/fake-service-name"), + entry(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString(), "fake-instance")) + .hasSize(2); } @Test @@ -91,14 +127,14 @@ void testWebsiteSiteNameAndWebsiteInstanceId() { envVars.put("WEBSITE_SITE_NAME", "test_website_site_name"); envVars.put("WEBSITE_INSTANCE_ID", "test_website_instance_id"); Resource resource = createTestResource(null, null, null); - new ResourceParser(envVars).updateRoleNameAndInstance(builder, resource); - Map tags = builder.build().getTags(); - assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE.toString())).isEqualTo("test_website_site_name"); - assertThat(tags.get(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString())).isEqualTo("test_website_instance_id"); - } - private static ConfigProperties getConfiguration() { - return DefaultConfigProperties.create(Collections.singletonMap("HOSTNAME", DEFAULT_ROLE_INSTANCE)); + new ResourceParser(envVars).updateRoleNameAndInstanceAndVersion(builder, resource); + + Map tags = builder.build().getTags(); + assertThat(tags) + .contains(entry(ContextTagKeys.AI_CLOUD_ROLE.toString(), "test_website_site_name"), + entry(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString(), "test_website_instance_id")) + .hasSize(2); } private static Resource createTestResource(@Nullable String serviceName, @Nullable String serviceNameSpace,