diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3eca0aa9..ff9d1b6b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -20,6 +20,15 @@ on: schedule: - cron: '0 7 * * 1' +permissions: + packages: read + contents: read + id-token: write + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_USERNAME: ${{ github.actor }} + jobs: analyze: name: Analyze diff --git a/custom/shared/src/main/java/com/solarwinds/opentelemetry/extensions/ApmResourceProvider.java b/custom/shared/src/main/java/com/solarwinds/opentelemetry/extensions/ApmResourceProvider.java new file mode 100644 index 00000000..19cfab90 --- /dev/null +++ b/custom/shared/src/main/java/com/solarwinds/opentelemetry/extensions/ApmResourceProvider.java @@ -0,0 +1,38 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * 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. + */ + +package com.solarwinds.opentelemetry.extensions; + +import com.google.auto.service.AutoService; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider; +import io.opentelemetry.sdk.resources.Resource; + +@AutoService(ResourceProvider.class) +public class ApmResourceProvider implements ResourceProvider { + public static final AttributeKey moduleKey = AttributeKey.stringKey("sw.data.module"); + + public static final AttributeKey versionKey = AttributeKey.stringKey("sw.apm.version"); + + @Override + public Resource createResource(ConfigProperties configProperties) { + Attributes resourceAttributes = + Attributes.of(moduleKey, "apm", versionKey, BuildConfig.SOLARWINDS_AGENT_VERSION); + return Resource.create(resourceAttributes); + } +} diff --git a/custom/shared/src/main/java/com/solarwinds/opentelemetry/extensions/InboundMeasurementMetricsGenerator.java b/custom/shared/src/main/java/com/solarwinds/opentelemetry/extensions/InboundMeasurementMetricsGenerator.java index ca1a878b..f9710a66 100644 --- a/custom/shared/src/main/java/com/solarwinds/opentelemetry/extensions/InboundMeasurementMetricsGenerator.java +++ b/custom/shared/src/main/java/com/solarwinds/opentelemetry/extensions/InboundMeasurementMetricsGenerator.java @@ -16,10 +16,12 @@ package com.solarwinds.opentelemetry.extensions; +import static com.solarwinds.opentelemetry.extensions.SharedNames.LAYER_NAME_PLACEHOLDER; import static com.solarwinds.opentelemetry.extensions.SharedNames.TRANSACTION_NAME_KEY; import com.solarwinds.joboe.logging.Logger; import com.solarwinds.joboe.logging.LoggerFactory; +import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.api.metrics.LongHistogram; @@ -116,7 +118,13 @@ public void onEnding(ReadWriteSpan span) { final SpanContext parentSpanContext = spanData.getParentSpanContext(); if (!parentSpanContext.isValid() || parentSpanContext.isRemote()) { span.setAttribute(TRANSACTION_NAME_KEY, TransactionNameManager.getTransactionName(spanData)); + span.setAttribute( + AttributeKey.stringKey("TransactionName"), + TransactionNameManager.getTransactionName(spanData)); } + + span.setAttribute( + "Layer", String.format(LAYER_NAME_PLACEHOLDER, span.getKind(), span.getName().trim())); } @Override diff --git a/custom/shared/src/main/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizer.java b/custom/shared/src/main/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizer.java index fcba9955..7b1a7837 100644 --- a/custom/shared/src/main/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizer.java +++ b/custom/shared/src/main/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizer.java @@ -30,10 +30,7 @@ public class ResourceCustomizer implements BiFunction processArgs = resource.getAttribute(ResourceAttributes.PROCESS_COMMAND_ARGS); diff --git a/custom/shared/src/test/java/com/solarwinds/opentelemetry/extensions/ApmResourceProviderTest.java b/custom/shared/src/test/java/com/solarwinds/opentelemetry/extensions/ApmResourceProviderTest.java new file mode 100644 index 00000000..0d316a22 --- /dev/null +++ b/custom/shared/src/test/java/com/solarwinds/opentelemetry/extensions/ApmResourceProviderTest.java @@ -0,0 +1,44 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * 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. + */ + +package com.solarwinds.opentelemetry.extensions; + +import static com.solarwinds.opentelemetry.extensions.ApmResourceProvider.moduleKey; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; +import io.opentelemetry.sdk.resources.Resource; +import java.util.Collections; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class ApmResourceProviderTest { + @InjectMocks private ApmResourceProvider apmResourceProvider; + + @Test + void testCreateResource() { + Resource resource = + apmResourceProvider.createResource(DefaultConfigProperties.create(Collections.emptyMap())); + String module = resource.getAttribute(moduleKey); + String version = resource.getAttribute(moduleKey); + + assertNotNull(module); + assertNotNull(version); + } +} diff --git a/custom/shared/src/test/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizerTest.java b/custom/shared/src/test/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizerTest.java index f14e67e3..1a99297e 100644 --- a/custom/shared/src/test/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizerTest.java +++ b/custom/shared/src/test/java/com/solarwinds/opentelemetry/extensions/ResourceCustomizerTest.java @@ -18,7 +18,6 @@ import static org.junit.jupiter.api.Assertions.*; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; import io.opentelemetry.sdk.resources.Resource; @@ -100,19 +99,4 @@ void verifyThatProcessCommandLineIsNotModifiedWhenServiceKeyIsNotPresentProcessC Arrays.asList("-Duser.country=US", "-Duser.language=en"), actual.getAttribute(ResourceAttributes.PROCESS_COMMAND_ARGS)); } - - @Test - void verifyAgentVersionIsAddedToResource() { - Resource resource = - Resource.create( - Attributes.builder() - .put( - ResourceAttributes.PROCESS_COMMAND_ARGS, - Arrays.asList("-Duser.country=US", "-Duser.language=en")) - .build()); - Resource actual = - tested.apply(resource, DefaultConfigProperties.create(Collections.emptyMap())); - - assertNotNull(actual.getAttribute(AttributeKey.stringKey("sw.apm.version"))); - } } diff --git a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/HostIdResourceProvider.java b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/HostIdResourceProvider.java new file mode 100644 index 00000000..c30a467d --- /dev/null +++ b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/HostIdResourceProvider.java @@ -0,0 +1,153 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * 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. + */ + +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * 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. + */ + +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * 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. + */ + +package com.solarwinds.opentelemetry.extensions; + +import com.google.auto.service.AutoService; +import com.solarwinds.joboe.core.HostId; +import com.solarwinds.joboe.core.util.ServerHostInfoReader; +import io.opentelemetry.api.common.AttributeKey; +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.ResourceProvider; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.semconv.ResourceAttributes; +import java.util.function.BiConsumer; + +@AutoService(ResourceProvider.class) +public class HostIdResourceProvider implements ResourceProvider { + + @Override + public Resource createResource(ConfigProperties configProperties) { + AttributesBuilder builder = Attributes.builder(); + + HostId hostId = ServerHostInfoReader.INSTANCE.getHostId(); + setIfNotNull(builder::put, ResourceAttributes.HOST_NAME, hostId.getHostname()); + setIfNotNull( + builder::put, ResourceAttributes.CLOUD_AVAILABILITY_ZONE, hostId.getEc2AvailabilityZone()); + setIfNotNull(builder::put, ResourceAttributes.HOST_ID, hostId.getEc2InstanceId()); + + setIfNotNull(builder::put, ResourceAttributes.CONTAINER_ID, hostId.getDockerContainerId()); + setIfNotNull(builder::put, ResourceAttributes.PROCESS_PID, (long) hostId.getPid()); + setIfNotNull( + builder::put, AttributeKey.stringArrayKey("mac.addresses"), hostId.getMacAddresses()); + + setIfNotNull( + builder::put, + AttributeKey.stringKey("azure.app.service.instance.id"), + hostId.getAzureAppServiceInstanceId()); + setIfNotNull(builder::put, ResourceAttributes.HOST_ID, hostId.getHerokuDynoId()); + setIfNotNull( + builder::put, AttributeKey.stringKey("sw.uams.client.id"), hostId.getUamsClientId()); + setIfNotNull(builder::put, AttributeKey.stringKey("uuid"), hostId.getUuid()); + + HostId.K8sMetadata k8sMetadata = hostId.getK8sMetadata(); + if (k8sMetadata != null) { + setIfNotNull(builder::put, ResourceAttributes.K8S_POD_UID, k8sMetadata.getPodUid()); + setIfNotNull(builder::put, ResourceAttributes.K8S_NAMESPACE_NAME, k8sMetadata.getNamespace()); + setIfNotNull(builder::put, ResourceAttributes.K8S_POD_NAME, k8sMetadata.getPodName()); + } + + HostId.AwsMetadata awsMetadata = hostId.getAwsMetadata(); + if (awsMetadata != null) { + setIfNotNull(builder::put, ResourceAttributes.HOST_ID, awsMetadata.getHostId()); + setIfNotNull(builder::put, ResourceAttributes.HOST_NAME, awsMetadata.getHostName()); + setIfNotNull(builder::put, ResourceAttributes.CLOUD_PROVIDER, awsMetadata.getCloudProvider()); + + setIfNotNull( + builder::put, ResourceAttributes.CLOUD_ACCOUNT_ID, awsMetadata.getCloudAccountId()); + setIfNotNull(builder::put, ResourceAttributes.CLOUD_PLATFORM, awsMetadata.getCloudPlatform()); + setIfNotNull( + builder::put, + ResourceAttributes.CLOUD_AVAILABILITY_ZONE, + awsMetadata.getCloudAvailabilityZone()); + + setIfNotNull(builder::put, ResourceAttributes.CLOUD_REGION, awsMetadata.getCloudRegion()); + setIfNotNull(builder::put, ResourceAttributes.HOST_IMAGE_ID, awsMetadata.getHostImageId()); + setIfNotNull(builder::put, ResourceAttributes.HOST_TYPE, awsMetadata.getHostType()); + } + + HostId.AzureVmMetadata azureVmMetadata = hostId.getAzureVmMetadata(); + if (azureVmMetadata != null) { + setIfNotNull(builder::put, ResourceAttributes.HOST_ID, azureVmMetadata.getHostId()); + setIfNotNull(builder::put, ResourceAttributes.HOST_NAME, azureVmMetadata.getHostName()); + setIfNotNull( + builder::put, ResourceAttributes.CLOUD_PROVIDER, azureVmMetadata.getCloudProvider()); + + setIfNotNull( + builder::put, ResourceAttributes.CLOUD_ACCOUNT_ID, azureVmMetadata.getCloudAccountId()); + setIfNotNull( + builder::put, ResourceAttributes.CLOUD_PLATFORM, azureVmMetadata.getCloudPlatform()); + setIfNotNull(builder::put, ResourceAttributes.CLOUD_REGION, azureVmMetadata.getCloudRegion()); + + setIfNotNull( + builder::put, AttributeKey.stringKey("azure.vm.name"), azureVmMetadata.getAzureVmName()); + setIfNotNull( + builder::put, AttributeKey.stringKey("azure.vm.size"), azureVmMetadata.getAzureVmSize()); + setIfNotNull( + builder::put, + AttributeKey.stringKey("azure.resource.group.name"), + azureVmMetadata.getAzureResourceGroupName()); + + setIfNotNull( + builder::put, + AttributeKey.stringKey("azure.vm.scale.set.name"), + azureVmMetadata.getAzureVmScaleSetName()); + } + + return Resource.create(builder.build()); + } + + private void setIfNotNull( + BiConsumer, V> setter, AttributeKey key, V value) { + if (value != null) { + setter.accept(key, value); + } + } +} diff --git a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsAgentListener.java b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsAgentListener.java index 8386c45a..0b057b09 100644 --- a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsAgentListener.java +++ b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsAgentListener.java @@ -215,6 +215,9 @@ protected MetricsMonitor buildMetricsMonitor() { */ private void reportInit() { try { + if (ConfigurationLoader.shouldUseOtlpForTraces()) { + return; + } reportLayerInit(); } catch (Exception e) { logger.warn("Failed to post init message: " + (e.getMessage() != null ? e.getMessage() : e)); diff --git a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsPropertiesSupplier.java b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsPropertiesSupplier.java index dac98ec7..a4765474 100644 --- a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsPropertiesSupplier.java +++ b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsPropertiesSupplier.java @@ -29,7 +29,6 @@ public class SolarwindsPropertiesSupplier implements Supplier collection) { - if (!isAgentEnabled()) { + if (!isAgentEnabled() || ConfigurationLoader.shouldUseOtlpForTraces()) { return CompletableResultCode.ofSuccess(); } EventReporter eventReporter = ReporterProvider.getEventReporter(); @@ -84,33 +85,10 @@ public CompletableResultCode export(@Nonnull Collection collection) { entryEvent = new EventImpl(null, w3cContext, false); } - if (!spanData.getParentSpanContext().isValid() - || spanData.getParentSpanContext().isRemote()) { // then a root span of this service - String transactionName = - spanData - .getAttributes() - .get( - AttributeKey.stringKey( - "TransactionName")); // check if there's transaction name set as - // attribute - if (transactionName == null) { - transactionName = TransactionNameManager.getTransactionName(spanData); - if (transactionName != null) { - entryEvent.addInfo( - "TransactionName", - transactionName); // only do this if we are generating a transaction name here. - // If it's already in attributes, it will be inserted by - // addInfo(getTags...) - } - } - } - InstrumentationScopeInfo scopeInfo = spanData.getInstrumentationScopeInfo(); entryEvent.addInfo( "Label", "entry", - "Layer", - spanName, "sw.span_kind", spanData.getKind().toString(), "otel.scope.name", diff --git a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/initialize/ConfigurationLoader.java b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/initialize/ConfigurationLoader.java index aaaf63ac..5997306a 100644 --- a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/initialize/ConfigurationLoader.java +++ b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/initialize/ConfigurationLoader.java @@ -16,6 +16,8 @@ package com.solarwinds.opentelemetry.extensions.initialize; +import static com.solarwinds.opentelemetry.extensions.SharedNames.COMPONENT_NAME; + import com.solarwinds.joboe.config.ConfigContainer; import com.solarwinds.joboe.config.ConfigGroup; import com.solarwinds.joboe.config.ConfigManager; @@ -270,6 +272,42 @@ static void configureOtelMetricExport(ConfigContainer container) { } } + static void configureOtelTraceExport(ConfigContainer container) { + String serviceKey = (String) container.get(ConfigProperty.AGENT_SERVICE_KEY); + String apiKey = ServiceKeyUtils.getApiKey(serviceKey); + + String dataCell = "na-01"; + String env = "cloud"; + String collectorEndpoint = (String) container.get(ConfigProperty.AGENT_COLLECTOR); + + if (collectorEndpoint != null) { + if (collectorEndpoint.contains("appoptics.com")) { + System.setProperty("otel.traces.exporter", COMPONENT_NAME); + return; + } + + collectorEndpoint = collectorEndpoint.split(":")[0]; + String[] fragments = collectorEndpoint.split("\\."); + if (fragments.length > 2) { + // This is based on knowledge of the SWO url format where the third name from the left in + // the domain is the data-cell name and assumes this format will stay stable. + dataCell = fragments[2]; + } + + if (fragments.length > 3) { + env = fragments[3]; + } + } + + System.setProperty("otel.exporter.otlp.traces.protocol", "grpc"); + System.setProperty( + "otel.exporter.otlp.traces.headers", String.format("authorization=Bearer %s", apiKey)); + + System.setProperty( + "otel.exporter.otlp.traces.endpoint", + String.format("https://otel.collector.%s.%s.solarwinds.com", dataCell, env)); + } + static Map mergeEnvWithSysProperties(Map env, Properties props) { Map res = new HashMap<>(env); @@ -323,6 +361,7 @@ private static void loadConfigurations() throws InvalidConfigException { processConfigs(configs); configureOtelLogExport(configs); configureOtelMetricExport(configs); + configureOtelTraceExport(configs); } catch (InvalidConfigException e) { // if there was a config read exception then processConfigs might throw exception due to // incomplete config container. @@ -598,4 +637,9 @@ public static boolean shouldUseOtlpForMetrics() { return (enabled == null || enabled) && (collectorEndpoint == null || !collectorEndpoint.contains("appoptics.com")); } + + public static boolean shouldUseOtlpForTraces() { + String collectorEndpoint = (String) ConfigManager.getConfig(ConfigProperty.AGENT_COLLECTOR); + return (collectorEndpoint == null || !collectorEndpoint.contains("appoptics.com")); + } } diff --git a/custom/src/test/java/com/solarwinds/opentelemetry/extensions/HostIdResourceProviderTest.java b/custom/src/test/java/com/solarwinds/opentelemetry/extensions/HostIdResourceProviderTest.java new file mode 100644 index 00000000..fb77e767 --- /dev/null +++ b/custom/src/test/java/com/solarwinds/opentelemetry/extensions/HostIdResourceProviderTest.java @@ -0,0 +1,45 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * 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. + */ + +package com.solarwinds.opentelemetry.extensions; + +import static org.junit.jupiter.api.Assertions.*; + +import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.semconv.ResourceAttributes; +import java.util.Collections; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class HostIdResourceProviderTest { + @InjectMocks private HostIdResourceProvider hostIdResourceProvider; + + @Test + void createResource() { + Resource resource = + hostIdResourceProvider.createResource( + DefaultConfigProperties.create(Collections.emptyMap())); + Long pid = resource.getAttribute(ResourceAttributes.PROCESS_PID); + String hostname = resource.getAttribute(ResourceAttributes.HOST_NAME); + + assertNotNull(pid); + assertNotNull(hostname); + } +} diff --git a/custom/src/test/java/com/solarwinds/opentelemetry/extensions/initialize/ConfigurationLoaderTest.java b/custom/src/test/java/com/solarwinds/opentelemetry/extensions/initialize/ConfigurationLoaderTest.java index 6d951b04..f4f712ef 100644 --- a/custom/src/test/java/com/solarwinds/opentelemetry/extensions/initialize/ConfigurationLoaderTest.java +++ b/custom/src/test/java/com/solarwinds/opentelemetry/extensions/initialize/ConfigurationLoaderTest.java @@ -390,16 +390,29 @@ void returnTrueWhenOtlpMetricExportIsNotDisabled() { } @Test - void returnFalseWhenCollectorIsAO() throws InvalidConfigException { + void returnFalseWhenCollectorIsAOForMetric() throws InvalidConfigException { ConfigManager.setConfig(ConfigProperty.AGENT_COLLECTOR, "collector.appoptics.com:443"); assertFalse(ConfigurationLoader.shouldUseOtlpForMetrics()); ConfigManager.removeConfig(ConfigProperty.AGENT_COLLECTOR); } @Test - void returnFalseWhenDisabled() throws InvalidConfigException { + void returnFalseWhenDisabledForMetric() throws InvalidConfigException { ConfigManager.setConfig(ConfigProperty.AGENT_EXPORT_METRICS_ENABLED, false); assertFalse(ConfigurationLoader.shouldUseOtlpForMetrics()); ConfigManager.removeConfig(ConfigProperty.AGENT_EXPORT_METRICS_ENABLED); } + + @Test + void returnFalseWhenCollectorIsAOForTrace() throws InvalidConfigException { + ConfigManager.setConfig(ConfigProperty.AGENT_COLLECTOR, "collector.appoptics.com:443"); + assertFalse(ConfigurationLoader.shouldUseOtlpForMetrics()); + ConfigManager.removeConfig(ConfigProperty.AGENT_COLLECTOR); + } + + @Test + void returnTrueWhenNotAOForTrace() { + assertTrue(ConfigurationLoader.shouldUseOtlpForTraces()); + ConfigManager.removeConfig(ConfigProperty.AGENT_EXPORT_METRICS_ENABLED); + } } diff --git a/gradle.properties b/gradle.properties index 1d719851..074477b3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,4 +21,4 @@ systemProp.org.gradle.internal.repository.initial.backoff=500 # Project properties provides a central place for shared property among subprojects otel.agent.version=2.9.0 otel.sdk.version=1.43.0 -swo.agent.version=2.9.0 +swo.agent.version=2.9.1 diff --git a/instrumentation/hibernate/hibernate-4.0/src/main/java/com/solarwinds/opentelemetry/instrumentation/hibernate/v4_0/LoaderInstrumentation.java b/instrumentation/hibernate/hibernate-4.0/src/main/java/com/solarwinds/opentelemetry/instrumentation/hibernate/v4_0/LoaderInstrumentation.java index bb7c40ff..c541178a 100644 --- a/instrumentation/hibernate/hibernate-4.0/src/main/java/com/solarwinds/opentelemetry/instrumentation/hibernate/v4_0/LoaderInstrumentation.java +++ b/instrumentation/hibernate/hibernate-4.0/src/main/java/com/solarwinds/opentelemetry/instrumentation/hibernate/v4_0/LoaderInstrumentation.java @@ -65,7 +65,7 @@ public static void startMethod( return; } - String sql = ""; + String sql = queryParameters.getFilteredSQL(); Context parentContext = currentContext(); if (!InstrumenterSingleton.instrumenter().shouldStart(parentContext, sql)) { return; diff --git a/smoke-tests/k6/basic.js b/smoke-tests/k6/basic.js index 97a89298..4d45becd 100644 --- a/smoke-tests/k6/basic.js +++ b/smoke-tests/k6/basic.js @@ -29,7 +29,7 @@ export const options = { function verify_that_trace_is_persisted() { let retryCount = Number.parseInt(`${__ENV.SWO_RETRY_COUNT}`) || 1000; - for (; retryCount; retryCount--) { + for (; retryCount > 0; retryCount--) { const petTypesResponse = http.get(`${baseUri}/pettypes`); check(petTypesResponse.headers, { 'should have X-Trace header': (h) => h['X-Trace'] !== undefined @@ -50,7 +50,7 @@ function verify_that_trace_is_persisted() { "query": "query getTraceDetails($traceId: ID!, $spanId: ID, $aggregateSpans: Boolean, $incomplete: Boolean) {\n traceDetails(\n traceId: $traceId\n spanId: $spanId\n aggregateSpans: $aggregateSpans\n incomplete: $incomplete\n ) {\n traceId\n action\n spanCount\n time\n controller\n duration\n originSpan {\n id\n service\n status\n transaction\n duration\n method\n errorCount\n host\n startTime\n action\n controller\n serviceEntity\n containerEntity\n hostEntity\n websiteEntity\n hostEntityName\n websiteEntityName\n serviceInstanceEntityName\n __typename\n }\n selectedSpan {\n id\n service\n status\n transaction\n duration\n method\n errorCount\n host\n startTime\n action\n controller\n serviceEntity\n containerEntity\n hostEntity\n websiteEntity\n hostEntityName\n websiteEntityName\n serviceInstanceEntityName\n __typename\n }\n allErrors {\n hostname\n message\n spanLayer\n time\n exceptionClassMessageHash\n spanId\n __typename\n }\n allQueries {\n ...QueryItem\n __typename\n }\n traceBreakdown {\n duration\n errorCount\n layer\n percentOfTraceDuration\n spanCount\n spanIds\n __typename\n }\n waterfall {\n ...WaterfallRow\n __typename\n }\n __typename\n }\n}\n\nfragment QueryItem on QueryItem {\n averageTime\n count\n query\n queryHash\n totalTime\n percentOfTraceDuration\n spanIds\n dboQueryId\n __typename\n}\n\nfragment WaterfallRow on WaterfallRow {\n parentId\n items {\n layer\n spanId\n endTime\n startTime\n service\n error {\n exceptionClassMessageHash\n message\n spanId\n timestamp\n __typename\n }\n async\n __typename\n }\n __typename\n}\n" } - for (; retryCount; retryCount--) { + for (; retryCount > 0; retryCount--) { let traceDetailResponse = http.post(`${__ENV.SWO_HOST_URL}/common/graphql`, JSON.stringify(traceDetailPayload), { headers: { @@ -83,7 +83,7 @@ function verify_that_trace_is_persisted() { function verify_that_span_data_is_persisted() { const newOwner = names.randomOwner(); let retryCount = Number.parseInt(`${__ENV.SWO_RETRY_COUNT}`) || 1000; - for (; retryCount; retryCount--) { + for (; retryCount > 0; retryCount--) { const newOwnerResponse = http.post(`${baseUri}/owners`, JSON.stringify(newOwner), { headers: { @@ -105,7 +105,7 @@ function verify_that_span_data_is_persisted() { "query": "query getSubSpanRawData($traceId: ID!, $spanFilter: TraceArchiveSpanFilter, $incomplete: Boolean) {\n traceArchive(\n traceId: $traceId\n spanFilter: $spanFilter\n incomplete: $incomplete\n ) {\n traceId\n traceSpans {\n edges {\n node {\n events {\n eventId\n properties {\n key\n value\n __typename\n }\n __typename\n }\n spanId\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n" } - for (; retryCount; retryCount--) { + for (; retryCount > 0; retryCount--) { let spanDataResponse = http.post(`${__ENV.SWO_HOST_URL}/common/graphql`, JSON.stringify(spanRawDataPayload), { headers: { @@ -157,7 +157,7 @@ function verify_that_span_data_is_persisted() { function verify_that_span_data_is_persisted_0() { let retryCount = Number.parseInt(`${__ENV.SWO_RETRY_COUNT}`) || 1000; - for (; retryCount; retryCount--) { + for (; retryCount > 0; retryCount--) { const transactionName = "int-test" const response = http.get(`${webMvcUri}/greet/${transactionName}`, { headers: { @@ -179,7 +179,7 @@ function verify_that_span_data_is_persisted_0() { "query": "query getSubSpanRawData($traceId: ID!, $spanFilter: TraceArchiveSpanFilter, $incomplete: Boolean) {\n traceArchive(\n traceId: $traceId\n spanFilter: $spanFilter\n incomplete: $incomplete\n ) {\n traceId\n traceSpans {\n edges {\n node {\n events {\n eventId\n properties {\n key\n value\n __typename\n }\n __typename\n }\n spanId\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n" } - for (; retryCount; retryCount--) { + for (; retryCount > 0; retryCount--) { let spanDataResponse = http.post(`${__ENV.SWO_HOST_URL}/common/graphql`, JSON.stringify(spanRawDataPayload), { headers: { @@ -222,7 +222,7 @@ function verify_that_span_data_is_persisted_0() { function verify_distributed_trace() { let retryCount = Number.parseInt(`${__ENV.SWO_RETRY_COUNT}`) || 1000; - for (; retryCount; retryCount--) { + for (; retryCount > 0; retryCount--) { const response = http.get(`${webMvcUri}/distributed`, { headers: { 'Content-Type': 'application/json' @@ -242,7 +242,7 @@ function verify_distributed_trace() { "query": "query getSubSpanRawData($traceId: ID!, $spanFilter: TraceArchiveSpanFilter, $incomplete: Boolean) {\n traceArchive(\n traceId: $traceId\n spanFilter: $spanFilter\n incomplete: $incomplete\n ) {\n traceId\n traceSpans {\n edges {\n node {\n events {\n eventId\n properties {\n key\n value\n __typename\n }\n __typename\n }\n spanId\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n" } - for (; retryCount; retryCount--) { + for (; retryCount > 0; retryCount--) { let spanDataResponse = http.post(`${__ENV.SWO_HOST_URL}/common/graphql`, JSON.stringify(spanRawDataPayload), { headers: { @@ -383,7 +383,7 @@ function verify_that_metrics_are_reported(metric, checkFn, service="lambda-e2e") function verify_transaction_name() { let retryCount = Number.parseInt(`${__ENV.SWO_RETRY_COUNT}`) || 1000; - for (; retryCount; retryCount--) { + for (; retryCount > 0; retryCount--) { const newOwner = names.randomOwner(); const response = http.post(`${baseUri}/owners`, JSON.stringify(newOwner), { @@ -406,7 +406,7 @@ function verify_transaction_name() { "query": "query getSubSpanRawData($traceId: ID!, $spanFilter: TraceArchiveSpanFilter, $incomplete: Boolean) {\n traceArchive(\n traceId: $traceId\n spanFilter: $spanFilter\n incomplete: $incomplete\n ) {\n traceId\n traceSpans {\n edges {\n node {\n events {\n eventId\n properties {\n key\n value\n __typename\n }\n __typename\n }\n spanId\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n" } - for (; retryCount; retryCount--) { + for (; retryCount > 0; retryCount--) { let spanDataResponse = http.post(`${__ENV.SWO_HOST_URL}/common/graphql`, JSON.stringify(spanRawDataPayload), { headers: { @@ -475,7 +475,7 @@ function getEntityId() { "query": "query getServiceEntitiesQuery($filter: EntityFilterInput, $timeFilter: TimeRangeInput!, $sortBy: EntitySortInput, $pagination: PagingInput, $bucketSizeInS: Int!, $includeKubernetesClusterUid: Boolean = false) {\n entities {\n search(\n filter: $filter\n sortBy: $sortBy\n paging: $pagination\n timeRange: $timeFilter\n ) {\n totalEntitiesCount\n pageInfo {\n endCursor\n hasNextPage\n startCursor\n hasPreviousPage\n __typename\n }\n groups {\n entities {\n ... on Service {\n ...ServiceEntity\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n\nfragment ServiceEntity on Service {\n id\n name: displayName\n lastSeenTime\n language\n kubernetesPodInstances @include(if: $includeKubernetesClusterUid) {\n clusterUid\n __typename\n }\n healthScore {\n scoreV2\n categoryV2\n __typename\n }\n traceServiceErrorRatio {\n ...MetricSeriesMeasurementsForServiceEntity\n __typename\n }\n traceServiceErrorRatioValue\n traceServiceRequestRate {\n ...MetricSeriesMeasurementsForServiceEntity\n __typename\n }\n traceServiceRequestRateValue\n responseTime {\n ...MetricSeriesMeasurementsForServiceEntity\n __typename\n }\n responseTimeValue\n sumRequests\n __typename\n}\n\nfragment MetricSeriesMeasurementsForServiceEntity on Metric {\n measurements(\n metricInput: {aggregation: {method: AVG, bucketSizeInS: $bucketSizeInS, missingDataPointsHandling: NULL_FILL}, timeRange: $timeFilter}\n ) {\n series {\n measurements {\n time\n value\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n}\n" } - for (; retryCount; retryCount--) { + for (; retryCount > 0; retryCount--) { let entityResponse = http.post(`${__ENV.SWO_HOST_URL}/common/graphql`, JSON.stringify(entityQueryPayload), { headers: { @@ -522,7 +522,7 @@ function verify_logs_export() { "query": "query getLogEvents($input: LogEventsInput!) {\n logEvents(input: $input) {\n events {\n id\n facility\n program\n message\n receivedAt\n severity\n sourceName\n isJson\n positions {\n length\n starts\n __typename\n }\n __typename\n }\n cursor {\n maxId\n maxTimestamp\n minId\n minTimestamp\n __typename\n }\n __typename\n }\n}\n" } - for (; retryCount; retryCount--) { + for (; retryCount > 0; retryCount--) { let logResponse = http.post(`${__ENV.SWO_HOST_URL}/common/graphql`, JSON.stringify(logQueryPayload), { headers: { diff --git a/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java b/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java index 1bd3f099..c792ecec 100644 --- a/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java +++ b/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java @@ -138,7 +138,7 @@ void assertJDBC() throws IOException { void assertXTraceOptions() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['xtrace-options is added to root span'].passes"); - assertTrue(passes > 2, "Xtrace options is not captured in root span"); + assertTrue(passes > 1, "Xtrace options is not captured in root span"); } @Test diff --git a/smoke-tests/src/test/java/com/solarwinds/containers/SpringBootWebMvcContainer.java b/smoke-tests/src/test/java/com/solarwinds/containers/SpringBootWebMvcContainer.java index 328ecc86..3b865038 100644 --- a/smoke-tests/src/test/java/com/solarwinds/containers/SpringBootWebMvcContainer.java +++ b/smoke-tests/src/test/java/com/solarwinds/containers/SpringBootWebMvcContainer.java @@ -70,7 +70,7 @@ public GenericContainer build() { .withCopyFileToContainer( MountableFile.forHostPath(agentPath), "/app/" + agentPath.getFileName()) - .withCommand(buildCommandline(agentPath, true)); + .withCommand(buildCommandline(agentPath)); } return new GenericContainer<>(DockerImageName.parse("smt:webmvc")) @@ -88,16 +88,13 @@ public GenericContainer build() { .withCopyFileToContainer( MountableFile.forHostPath(agentPath), "/app/" + agentPath.getFileName()) - .withCommand(buildCommandline(agentPath, false)); + .withCommand(buildCommandline(agentPath)); } @NotNull - private String[] buildCommandline(Path agentJarPath, boolean isLambda) { + private String[] buildCommandline(Path agentJarPath) { List result = new ArrayList<>(); result.add("java"); - if (!isLambda) { - result.add("-Dotel.javaagent.extensions=/app/custom-extensions.jar"); - } result.addAll(this.agent.getAdditionalJvmArgs()); result.add("-javaagent:/app/" + agentJarPath.getFileName());