From 8e1385c4565dbeb9a55f82a371ca0c392e451081 Mon Sep 17 00:00:00 2001 From: cleverchuk Date: Mon, 20 Jul 2026 11:04:06 -0400 Subject: [PATCH 1/3] Prefer detected service name to service key one in azure app service --- build.gradle.kts | 2 +- .../config/ConfigurationLoader.java | 26 ---- .../config/ConfigurationLoaderTest.java | 23 ---- .../extensions/LambdaConfigurationLoader.java | 26 ---- .../extensions/ResourceCustomizer.java | 54 ++++++-- .../extensions/ResourceCustomizerTest.java | 120 ++++++++++++++++++ .../test/java/com/solarwinds/SmokeTest.java | 1 - .../test/java/com/solarwinds/SmokeTestV2.java | 1 - 8 files changed, 167 insertions(+), 86 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index b0026e93..8b433ef7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,7 +18,7 @@ plugins{ id("io.github.gradle-nexus.publish-plugin") version "2.0.0" } -val swoAgentVersion = "3.2.1" +val swoAgentVersion = "3.3.0" extra["swoAgentVersion"] = swoAgentVersion group = "com.solarwinds" version = if (System.getenv("SNAPSHOT_BUILD").toBoolean()) "$swoAgentVersion-SNAPSHOT" else swoAgentVersion diff --git a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/ConfigurationLoader.java b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/ConfigurationLoader.java index 0c6df7a4..b54eccab 100644 --- a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/ConfigurationLoader.java +++ b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/ConfigurationLoader.java @@ -165,32 +165,6 @@ private static void maybeFollowOtelConfigProperties(ConfigContainer configs) { logger.info("failed to follow Otel's log file config." + e.getMessage()); } } - - String serviceName = System.getProperty("otel.service.name"); - if (serviceName == null) { - serviceName = System.getenv("OTEL_SERVICE_NAME"); - } - - String serviceKey = (String) configs.get(ConfigProperty.AGENT_SERVICE_KEY); - if (serviceName == null) { - if (serviceKey != null) { - String name = ServiceKeyUtils.getServiceName(serviceKey); - if (name != null) { - System.setProperty("otel.service.name", name); - } - } - - } else { - if (serviceKey != null) { - try { - String key = String.format("%s:%s", ServiceKeyUtils.getApiKey(serviceKey), serviceName); - configs.put(ConfigProperty.AGENT_SERVICE_KEY, key, true); - } catch (InvalidConfigException e) { - LoggerFactory.getLogger() - .warn(String.format("Unable to update service name to %s", serviceName)); - } - } - } } static void configureOtel(ConfigContainer container) throws InvalidConfigException { diff --git a/custom/src/test/java/com/solarwinds/opentelemetry/extensions/config/ConfigurationLoaderTest.java b/custom/src/test/java/com/solarwinds/opentelemetry/extensions/config/ConfigurationLoaderTest.java index 28dd2379..2f574520 100644 --- a/custom/src/test/java/com/solarwinds/opentelemetry/extensions/config/ConfigurationLoaderTest.java +++ b/custom/src/test/java/com/solarwinds/opentelemetry/extensions/config/ConfigurationLoaderTest.java @@ -23,10 +23,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import com.solarwinds.joboe.config.ConfigContainer; -import com.solarwinds.joboe.config.ConfigManager; import com.solarwinds.joboe.config.ConfigProperty; import com.solarwinds.joboe.config.InvalidConfigException; -import com.solarwinds.joboe.config.ServiceKeyUtils; import com.solarwinds.opentelemetry.extensions.DefaultNamingScheme; import com.solarwinds.opentelemetry.extensions.NamingScheme; import com.solarwinds.opentelemetry.extensions.SpanAttributeNamingScheme; @@ -133,27 +131,6 @@ void testWindowsRootPath() { assertNull(ConfigurationLoader.getRuntimeConfigFilename()); } - @Test - @ClearSystemProperty(key = "otel.service.name") - void verifyThatOtelServiceNameSystemPropertyIsWhenNotExplicitlySet() - throws InvalidConfigException { - ConfigurationLoader.load(); - assertEquals( - "name" /*name is from custom/build.gradle test task*/, - System.getProperty("otel.service.name")); - } - - @Test - @SetSystemProperty(key = "otel.service.name", value = "test") - void verifyThatServiceKeyIsUpdatedWithOtelServiceNameWhenSystemPropertyIsSet() - throws InvalidConfigException { - ConfigurationLoader.load(); - String serviceKeyAfter = (String) ConfigManager.getConfig(ConfigProperty.AGENT_SERVICE_KEY); - - assertEquals("test", ServiceKeyUtils.getServiceName(serviceKeyAfter)); - assertEquals("token:test", serviceKeyAfter); - } - @Test @ClearSystemProperty(key = "otel.exporter.otlp.endpoint") @ClearSystemProperty(key = "otel.exporter.otlp.headers") diff --git a/libs/lambda/src/main/java/com/solarwinds/opentelemetry/extensions/LambdaConfigurationLoader.java b/libs/lambda/src/main/java/com/solarwinds/opentelemetry/extensions/LambdaConfigurationLoader.java index fb7f8d25..d2eafce9 100644 --- a/libs/lambda/src/main/java/com/solarwinds/opentelemetry/extensions/LambdaConfigurationLoader.java +++ b/libs/lambda/src/main/java/com/solarwinds/opentelemetry/extensions/LambdaConfigurationLoader.java @@ -110,32 +110,6 @@ private static void maybeFollowOtelConfigProperties(ConfigContainer configs) { logger.info("failed to follow Otel's log file config." + e.getMessage()); } } - - String serviceName = System.getProperty("otel.service.name"); - if (serviceName == null) { - serviceName = System.getenv("OTEL_SERVICE_NAME"); - } - - String serviceKey = (String) configs.get(ConfigProperty.AGENT_SERVICE_KEY); - if (serviceName == null) { - if (serviceKey != null) { - String name = ServiceKeyUtils.getServiceName(serviceKey); - if (name != null) { - System.setProperty("otel.service.name", name); - } - } - - } else { - if (serviceKey != null) { - try { - String key = String.format("%s:%s", ServiceKeyUtils.getApiKey(serviceKey), serviceName); - configs.put(ConfigProperty.AGENT_SERVICE_KEY, key, true); - } catch (InvalidConfigException e) { - LoggerFactory.getLogger() - .warn(String.format("Unable to update service name to %s", serviceName)); - } - } - } } static Map mergeEnvWithSysProperties(Map env, Properties props) { diff --git a/libs/shared/src/main/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizer.java b/libs/shared/src/main/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizer.java index a29efed1..44804802 100644 --- a/libs/shared/src/main/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizer.java +++ b/libs/shared/src/main/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizer.java @@ -16,18 +16,25 @@ package com.solarwinds.opentelemetry.extensions; +import com.solarwinds.joboe.config.ConfigManager; +import com.solarwinds.joboe.config.ConfigProperty; +import com.solarwinds.joboe.config.InvalidConfigException; +import com.solarwinds.joboe.config.ServiceKeyUtils; import com.solarwinds.joboe.logging.LoggerFactory; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.resources.ResourceBuilder; import io.opentelemetry.semconv.ServiceAttributes; +import io.opentelemetry.semconv.incubating.CloudIncubatingAttributes; import io.opentelemetry.semconv.incubating.ProcessIncubatingAttributes; import java.util.List; import java.util.function.BiFunction; import java.util.stream.Collectors; +import lombok.Getter; public class ResourceCustomizer implements BiFunction { - private static Resource resource; + + @Getter private static Resource resource; @Override public Resource apply(Resource resource, ConfigProperties configProperties) { @@ -51,16 +58,47 @@ public Resource apply(Resource resource, ConfigProperties configProperties) { resourceBuilder.put(ProcessIncubatingAttributes.PROCESS_COMMAND_ARGS, args); } + String serviceName = getServiceName(resource, configProperties); + updateServiceKey(serviceName); + resourceBuilder.put(ServiceAttributes.SERVICE_NAME, serviceName); + + LoggerFactory.getLogger().info("Resolved service name: " + serviceName); ResourceCustomizer.resource = resourceBuilder.build(); - LoggerFactory.getLogger() - .debug( - String.format( - "This log line is used for validation only: service.name: %s", - resource.getAttribute(ServiceAttributes.SERVICE_NAME))); return ResourceCustomizer.resource; } - public static Resource getResource() { - return resource; + private String getServiceName(Resource resource, ConfigProperties configProperties) { + String serviceKeyName = null; + String serviceKey = ConfigManager.getConfigOptional(ConfigProperty.AGENT_SERVICE_KEY, null); + if (serviceKey != null) { + serviceKeyName = ServiceKeyUtils.getServiceName(serviceKey); + } + + // Only allow detected name for azure app service + if (!"azure.app_service".equals(resource.getAttribute(CloudIncubatingAttributes.CLOUD_PLATFORM)) + && configProperties.getString("otel.service.name") == null) { + return serviceKeyName; + } + + String serviceName = resource.getAttribute(ServiceAttributes.SERVICE_NAME); + if (serviceKeyName != null && (serviceName == null || serviceName.startsWith("unknown_"))) { + serviceName = serviceKeyName; + } + + return serviceName; + } + + private void updateServiceKey(String serviceName) { + if (serviceName != null) { + String serviceKey = ConfigManager.getConfigOptional(ConfigProperty.AGENT_SERVICE_KEY, ":"); + String apiKey = ServiceKeyUtils.getApiKey(serviceKey); + + try { + ConfigManager.setConfig( + ConfigProperty.AGENT_SERVICE_KEY, String.format("%s:%s", apiKey, serviceName)); + } catch (InvalidConfigException ignore) { + LoggerFactory.getLogger().debug("Failed to update service key with name: " + serviceName); + } + } } } diff --git a/libs/shared/src/test/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizerTest.java b/libs/shared/src/test/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizerTest.java index 1851a382..b592d14c 100644 --- a/libs/shared/src/test/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizerTest.java +++ b/libs/shared/src/test/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizerTest.java @@ -18,14 +18,21 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import com.solarwinds.joboe.config.ConfigManager; +import com.solarwinds.joboe.config.ConfigProperty; +import com.solarwinds.joboe.config.InvalidConfigException; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.semconv.ServiceAttributes; +import io.opentelemetry.semconv.incubating.CloudIncubatingAttributes; import io.opentelemetry.semconv.incubating.ProcessIncubatingAttributes; import java.util.Arrays; import java.util.Collections; import java.util.Objects; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -36,6 +43,11 @@ class ResourceCustomizerTest { @InjectMocks private ResourceCustomizer tested; + @AfterEach + void tearDown() { + ConfigManager.reset(); + } + private final Resource resource = Resource.create( Attributes.builder() @@ -104,4 +116,112 @@ void verifyThatProcessCommandLineIsNotModifiedWhenServiceKeyIsNotPresentProcessC Arrays.asList("-Duser.country=US", "-Duser.language=en"), actual.getAttribute(ProcessIncubatingAttributes.PROCESS_COMMAND_ARGS)); } + + @Test + void verifyThatServiceKeyNameIsPreferredOverDetectedNameByDefault() + throws InvalidConfigException { + ConfigManager.setConfig(ConfigProperty.AGENT_SERVICE_KEY, "token:key-service"); + Resource resource = + Resource.create( + Attributes.builder().put(ServiceAttributes.SERVICE_NAME, "my-service").build()); + + Resource actual = + tested.apply(resource, DefaultConfigProperties.createFromMap(Collections.emptyMap())); + assertEquals("key-service", actual.getAttribute(ServiceAttributes.SERVICE_NAME)); + } + + @Test + void verifyThatDetectedServiceNameIsUsedForAzureAppService() throws InvalidConfigException { + ConfigManager.setConfig(ConfigProperty.AGENT_SERVICE_KEY, "token:key-service"); + Resource resource = + Resource.create( + Attributes.builder() + .put(CloudIncubatingAttributes.CLOUD_PLATFORM, "azure.app_service") + .put(ServiceAttributes.SERVICE_NAME, "my-service") + .build()); + + Resource actual = + tested.apply(resource, DefaultConfigProperties.createFromMap(Collections.emptyMap())); + assertEquals("my-service", actual.getAttribute(ServiceAttributes.SERVICE_NAME)); + } + + @Test + void verifyThatServiceKeyNameIsUsedForAzureAppServiceWhenDetectedNameIsUnknown() + throws InvalidConfigException { + ConfigManager.setConfig(ConfigProperty.AGENT_SERVICE_KEY, "token:key-service"); + Resource resource = + Resource.create( + Attributes.builder() + .put(CloudIncubatingAttributes.CLOUD_PLATFORM, "azure.app_service") + .put(ServiceAttributes.SERVICE_NAME, "unknown_service:java") + .build()); + + Resource actual = + tested.apply(resource, DefaultConfigProperties.createFromMap(Collections.emptyMap())); + assertEquals("key-service", actual.getAttribute(ServiceAttributes.SERVICE_NAME)); + } + + @Test + void verifyThatServiceKeyNameIsUsedForAzureAppServiceWhenDetectedNameIsNull() + throws InvalidConfigException { + ConfigManager.setConfig(ConfigProperty.AGENT_SERVICE_KEY, "token:key-service"); + Resource resource = + Resource.create( + Attributes.builder() + .put(CloudIncubatingAttributes.CLOUD_PLATFORM, "azure.app_service") + .build()); + + Resource actual = + tested.apply(resource, DefaultConfigProperties.createFromMap(Collections.emptyMap())); + assertEquals("key-service", actual.getAttribute(ServiceAttributes.SERVICE_NAME)); + } + + @Test + void verifyThatServiceKeyNameIsUsedByDefaultWhenResourceHasNoServiceName() + throws InvalidConfigException { + ConfigManager.setConfig(ConfigProperty.AGENT_SERVICE_KEY, "token:key-service"); + Resource resource = Resource.create(Attributes.empty()); + + Resource actual = + tested.apply(resource, DefaultConfigProperties.createFromMap(Collections.emptyMap())); + assertEquals("key-service", actual.getAttribute(ServiceAttributes.SERVICE_NAME)); + } + + @Test + void verifyThatServiceNameIsNullWhenNotInResourceAndNoServiceKeyConfigured() { + Resource resource = Resource.create(Attributes.empty()); + Resource actual = + tested.apply(resource, DefaultConfigProperties.createFromMap(Collections.emptyMap())); + + assertNull(actual.getAttribute(ServiceAttributes.SERVICE_NAME)); + } + + @Test + void verifyThatServiceKeyIsUpdatedWithServiceName() throws InvalidConfigException { + ConfigManager.setConfig(ConfigProperty.AGENT_SERVICE_KEY, "token:old-name"); + Resource resource = + Resource.create( + Attributes.builder().put(ServiceAttributes.SERVICE_NAME, "new-name").build()); + + tested.apply( + resource, + DefaultConfigProperties.createFromMap( + Collections.singletonMap("otel.service.name", "new-name"))); + assertEquals("token:new-name", ConfigManager.getConfig(ConfigProperty.AGENT_SERVICE_KEY)); + } + + @Test + void verifyThatServiceKeyIsUpdatedWithServiceNameWhenOnAppService() + throws InvalidConfigException { + ConfigManager.setConfig(ConfigProperty.AGENT_SERVICE_KEY, "token:old-name"); + Resource resource = + Resource.create( + Attributes.builder() + .put(CloudIncubatingAttributes.CLOUD_PLATFORM, "azure.app_service") + .put(ServiceAttributes.SERVICE_NAME, "new-name") + .build()); + + tested.apply(resource, DefaultConfigProperties.createFromMap(Collections.emptyMap())); + assertEquals("token:new-name", ConfigManager.getConfig(ConfigProperty.AGENT_SERVICE_KEY)); + } } diff --git a/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java b/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java index 044baa0f..f5a0ebc7 100644 --- a/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java +++ b/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java @@ -60,7 +60,6 @@ public class SmokeTest { "hostId:.*[0-9a-z-]+", "Extension attached!", "trace_id=[a-z0-9]+\\s+span_id=[a-z0-9]+\\s+trace_flags=[0-9a-f]{2}", - "This log line is used for validation only: service.name: java-apm-smoke-test", "Applying instrumentation: sw-jdbc", "Clearing transaction name buffer. Unique transaction count: \\d+", "CONNECT otel.collector.na-01.st-ssp.solarwinds.com:443") diff --git a/smoke-tests/src/test/java/com/solarwinds/SmokeTestV2.java b/smoke-tests/src/test/java/com/solarwinds/SmokeTestV2.java index 9d8b6096..3ef3fb16 100644 --- a/smoke-tests/src/test/java/com/solarwinds/SmokeTestV2.java +++ b/smoke-tests/src/test/java/com/solarwinds/SmokeTestV2.java @@ -60,7 +60,6 @@ public class SmokeTestV2 { "hostId:.*[0-9a-z-]+", "Extension attached!", "trace_id=[a-z0-9]+\\s+span_id=[a-z0-9]+\\s+trace_flags=[0-9a-f]{2}", - "This log line is used for validation only: service.name: java-apm-smoke-test", "Applying instrumentation: sw-jdbc", "Clearing transaction name buffer. Unique transaction count: \\d+") , new Slf4jLogConsumer(LoggerFactory.getLogger("k6"))); From ebc3a74145a84680610584d63e3e10ca5070f031 Mon Sep 17 00:00:00 2001 From: cleverchuk Date: Thu, 23 Jul 2026 14:39:38 -0400 Subject: [PATCH 2/3] remove version bump --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 8b433ef7..b0026e93 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,7 +18,7 @@ plugins{ id("io.github.gradle-nexus.publish-plugin") version "2.0.0" } -val swoAgentVersion = "3.3.0" +val swoAgentVersion = "3.2.1" extra["swoAgentVersion"] = swoAgentVersion group = "com.solarwinds" version = if (System.getenv("SNAPSHOT_BUILD").toBoolean()) "$swoAgentVersion-SNAPSHOT" else swoAgentVersion From 135f7d42cf4062558dcb59f5026530bc19bcfaa8 Mon Sep 17 00:00:00 2001 From: cleverchuk Date: Thu, 23 Jul 2026 15:07:09 -0400 Subject: [PATCH 3/3] rename test case to a more descriptive name --- .../opentelemetry/extensions/ResourceCustomizerTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/shared/src/test/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizerTest.java b/libs/shared/src/test/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizerTest.java index b592d14c..831aab38 100644 --- a/libs/shared/src/test/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizerTest.java +++ b/libs/shared/src/test/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizerTest.java @@ -197,7 +197,8 @@ void verifyThatServiceNameIsNullWhenNotInResourceAndNoServiceKeyConfigured() { } @Test - void verifyThatServiceKeyIsUpdatedWithServiceName() throws InvalidConfigException { + void verifyThatServiceKeyIsUpdatedWithConfiguredServiceNameWhenNotOnAppService() + throws InvalidConfigException { ConfigManager.setConfig(ConfigProperty.AGENT_SERVICE_KEY, "token:old-name"); Resource resource = Resource.create(