diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PayloadTagsProcessor.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PayloadTagsProcessor.java index a52fa938c3e..87544b62aeb 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PayloadTagsProcessor.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PayloadTagsProcessor.java @@ -1,19 +1,19 @@ package datadog.trace.core.tagprocessor; +import static datadog.trace.util.json.JsonPathParser.parseJsonPaths; + import datadog.trace.api.Config; import datadog.trace.api.ConfigDefaults; import datadog.trace.api.TagMap; import datadog.trace.api.telemetry.LogCollector; import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; import datadog.trace.core.DDSpanContext; +import datadog.trace.core.util.JsonStreamParser; import datadog.trace.payloadtags.PayloadTagsData; -import datadog.trace.payloadtags.json.JsonPath; -import datadog.trace.payloadtags.json.JsonPathParser; -import datadog.trace.payloadtags.json.JsonStreamParser; -import datadog.trace.payloadtags.json.PathCursor; +import datadog.trace.util.json.JsonPath; +import datadog.trace.util.json.PathCursor; import java.io.InputStream; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -38,7 +38,7 @@ public static PayloadTagsProcessor create(Config config) { new RedactionRules.Builder() .addRedactionJsonPaths(ConfigDefaults.DEFAULT_CLOUD_COMMON_PAYLOAD_TAGGING) .addRedactionJsonPaths(ConfigDefaults.DEFAULT_CLOUD_REQUEST_PAYLOAD_TAGGING) - .addRedactionJsonPaths(config.getCloudRequestPayloadTagging()) + .addParsedRedactionJsonPaths(config.getCloudRequestPayloadTagging()) .build()); } if (config.isCloudResponsePayloadTaggingEnabled()) { @@ -47,7 +47,7 @@ public static PayloadTagsProcessor create(Config config) { new RedactionRules.Builder() .addRedactionJsonPaths(ConfigDefaults.DEFAULT_CLOUD_COMMON_PAYLOAD_TAGGING) .addRedactionJsonPaths(ConfigDefaults.DEFAULT_CLOUD_RESPONSE_PAYLOAD_TAGGING) - .addRedactionJsonPaths(config.getCloudResponsePayloadTagging()) + .addParsedRedactionJsonPaths(config.getCloudResponsePayloadTagging()) .build()); } if (redactionRulesByTagPrefix.isEmpty()) { @@ -145,20 +145,13 @@ public RedactionRules.Builder addRedactionJsonPaths(List jsonPaths) { return this; } - private static List parseJsonPaths(List rules) { - if (rules.isEmpty() || rules.size() == 1 && rules.get(0).equalsIgnoreCase("all")) { - return Collections.emptyList(); - } - List result = new ArrayList<>(rules.size()); - for (String rule : rules) { - try { - JsonPath jp = JsonPathParser.parse(rule); - result.add(jp); - } catch (Exception ex) { - log.warn("Skipping failed to parse redaction rule '{}'. {}", rule, ex.getMessage()); - } + public RedactionRules.Builder addParsedRedactionJsonPaths(List jsonPaths) { + if (null == jsonPaths) { + log.warn("Provided JsonPaths list is null, skipping."); + return this; } - return result; + this.redactionRules.addAll(jsonPaths); + return this; } RedactionRules build() { diff --git a/dd-trace-core/src/main/java/datadog/trace/payloadtags/json/JsonStreamParser.java b/dd-trace-core/src/main/java/datadog/trace/core/util/JsonStreamParser.java similarity index 98% rename from dd-trace-core/src/main/java/datadog/trace/payloadtags/json/JsonStreamParser.java rename to dd-trace-core/src/main/java/datadog/trace/core/util/JsonStreamParser.java index 916e65afb72..b8d1050cfb3 100644 --- a/dd-trace-core/src/main/java/datadog/trace/payloadtags/json/JsonStreamParser.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/util/JsonStreamParser.java @@ -1,6 +1,7 @@ -package datadog.trace.payloadtags.json; +package datadog.trace.core.util; import com.squareup.moshi.JsonReader; +import datadog.trace.util.json.PathCursor; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PayloadTagsProcessorTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PayloadTagsProcessorTest.groovy index 40ef22a3f4e..b5f97c053ca 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PayloadTagsProcessorTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PayloadTagsProcessorTest.groovy @@ -3,7 +3,7 @@ package datadog.trace.core.tagprocessor import com.squareup.moshi.JsonWriter import datadog.trace.payloadtags.PayloadTagsData import datadog.trace.payloadtags.PayloadTagsData.PathAndValue -import datadog.trace.payloadtags.json.PathCursor +import datadog.trace.util.json.PathCursor import datadog.trace.test.util.DDSpecification import datadog.trace.api.Config import okio.Buffer diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index b22778171d5..60d6f29978f 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -673,6 +673,7 @@ import static datadog.trace.util.CollectionUtils.tryMakeImmutableList; import static datadog.trace.util.CollectionUtils.tryMakeImmutableSet; import static datadog.trace.util.ConfigStrings.propertyNameToEnvironmentVariableName; +import static datadog.trace.util.json.JsonPathParser.parseJsonPaths; import datadog.environment.JavaVirtualMachine; import datadog.environment.OperatingSystem; @@ -704,6 +705,7 @@ import datadog.trace.util.PidHelper; import datadog.trace.util.RandomUtils; import datadog.trace.util.Strings; +import datadog.trace.util.json.JsonPath; import datadog.trace.util.throwable.FatalAgentMisconfigurationError; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.BufferedReader; @@ -1283,8 +1285,8 @@ public static String getHostName() { private final String agentlessLogSubmissionProduct; private final Set cloudPayloadTaggingServices; - @Nullable private final List cloudRequestPayloadTagging; - @Nullable private final List cloudResponsePayloadTagging; + @Nullable private final List cloudRequestPayloadTagging; + @Nullable private final List cloudResponsePayloadTagging; private final int cloudPayloadTaggingMaxDepth; private final int cloudPayloadTaggingMaxTags; @@ -2861,10 +2863,39 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment()) this.cloudPayloadTaggingServices = configProvider.getSet( TRACE_CLOUD_PAYLOAD_TAGGING_SERVICES, DEFAULT_TRACE_CLOUD_PAYLOAD_TAGGING_SERVICES); - this.cloudRequestPayloadTagging = + + List cloudReqPayloadTaggingConf = configProvider.getList(TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING, null); - this.cloudResponsePayloadTagging = + if (null == cloudReqPayloadTaggingConf) { + // if no configuration is provided, disable payload tagging + this.cloudRequestPayloadTagging = null; + } else if (cloudReqPayloadTaggingConf.size() == 1 + && cloudReqPayloadTaggingConf.get(0).equalsIgnoreCase("all")) { + // if "all" is specified enable all JSON paths + this.cloudRequestPayloadTagging = Collections.emptyList(); + } else { + // parse and validate JSON paths. if none are valid, disable payload tagging + List validRequestJsonPaths = parseJsonPaths(cloudReqPayloadTaggingConf); + this.cloudRequestPayloadTagging = + validRequestJsonPaths.isEmpty() ? null : validRequestJsonPaths; + } + + List cloudRespPayloadTaggingConf = configProvider.getList(TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING, null); + if (null == cloudRespPayloadTaggingConf) { + // if no configuration is provided, disable payload tagging + this.cloudResponsePayloadTagging = null; + } else if (cloudRespPayloadTaggingConf.size() == 1 + && cloudRespPayloadTaggingConf.get(0).equalsIgnoreCase("all")) { + // if "all" is specified enable all JSON paths + this.cloudResponsePayloadTagging = Collections.emptyList(); + } else { + // parse and validate JSON paths. if none are valid, disable payload tagging + List validResponseJsonPaths = parseJsonPaths(cloudRespPayloadTaggingConf); + this.cloudResponsePayloadTagging = + validResponseJsonPaths.isEmpty() ? null : validResponseJsonPaths; + } + this.cloudPayloadTaggingMaxDepth = configProvider.getInteger(TRACE_CLOUD_PAYLOAD_TAGGING_MAX_DEPTH, 10); this.cloudPayloadTaggingMaxTags = @@ -5315,7 +5346,7 @@ public boolean isCloudPayloadTaggingEnabled() { return isCloudRequestPayloadTaggingEnabled() || isCloudResponsePayloadTaggingEnabled(); } - public List getCloudRequestPayloadTagging() { + public List getCloudRequestPayloadTagging() { return cloudRequestPayloadTagging == null ? Collections.emptyList() : cloudRequestPayloadTagging; @@ -5325,7 +5356,7 @@ public boolean isCloudRequestPayloadTaggingEnabled() { return cloudRequestPayloadTagging != null; } - public List getCloudResponsePayloadTagging() { + public List getCloudResponsePayloadTagging() { return cloudResponsePayloadTagging == null ? Collections.emptyList() : cloudResponsePayloadTagging; diff --git a/dd-trace-core/src/main/java/datadog/trace/payloadtags/json/JsonPath.java b/internal-api/src/main/java/datadog/trace/util/json/JsonPath.java similarity index 99% rename from dd-trace-core/src/main/java/datadog/trace/payloadtags/json/JsonPath.java rename to internal-api/src/main/java/datadog/trace/util/json/JsonPath.java index a65a1726db7..15774b80fb9 100644 --- a/dd-trace-core/src/main/java/datadog/trace/payloadtags/json/JsonPath.java +++ b/internal-api/src/main/java/datadog/trace/util/json/JsonPath.java @@ -1,4 +1,4 @@ -package datadog.trace.payloadtags.json; +package datadog.trace.util.json; import java.util.ArrayList; import java.util.Collection; diff --git a/dd-trace-core/src/main/java/datadog/trace/payloadtags/json/JsonPathParser.java b/internal-api/src/main/java/datadog/trace/util/json/JsonPathParser.java similarity index 91% rename from dd-trace-core/src/main/java/datadog/trace/payloadtags/json/JsonPathParser.java rename to internal-api/src/main/java/datadog/trace/util/json/JsonPathParser.java index 2d75d00fffc..4bb2218da49 100644 --- a/dd-trace-core/src/main/java/datadog/trace/payloadtags/json/JsonPathParser.java +++ b/internal-api/src/main/java/datadog/trace/util/json/JsonPathParser.java @@ -1,7 +1,13 @@ -package datadog.trace.payloadtags.json; +package datadog.trace.util.json; import static java.lang.Character.isDigit; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class JsonPathParser { public static final class ParseError extends Exception { @@ -26,6 +32,24 @@ public ParseError(CharSequence path, int position, String error) { private static final char DOUBLE_QUOTE = '"'; private static final char ESC = '\\'; + private static final Logger log = LoggerFactory.getLogger(JsonPathParser.class); + + public static List parseJsonPaths(List rules) { + if (null == rules || rules.isEmpty()) { + return Collections.emptyList(); + } + List result = new ArrayList<>(rules.size()); + for (String rule : rules) { + try { + JsonPath jp = parse(rule); + result.add(jp); + } catch (Exception ex) { + log.warn("Failed to parse redaction rule '{}'. {}. Skipping rule.", rule, ex.getMessage()); + } + } + return result; + } + public static JsonPath parse(String path) throws ParseError { Cursor cur = new Cursor(path); diff --git a/dd-trace-core/src/main/java/datadog/trace/payloadtags/json/PathCursor.java b/internal-api/src/main/java/datadog/trace/util/json/PathCursor.java similarity index 97% rename from dd-trace-core/src/main/java/datadog/trace/payloadtags/json/PathCursor.java rename to internal-api/src/main/java/datadog/trace/util/json/PathCursor.java index 1b23b315ccb..5048c724e01 100644 --- a/dd-trace-core/src/main/java/datadog/trace/payloadtags/json/PathCursor.java +++ b/internal-api/src/main/java/datadog/trace/util/json/PathCursor.java @@ -1,4 +1,4 @@ -package datadog.trace.payloadtags.json; +package datadog.trace.util.json; import java.util.Arrays; diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index 164278d81d7..028e5f0e29b 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -136,6 +136,8 @@ import static datadog.trace.api.config.TracerConfig.TRACE_SAMPLING_OPERATION_RUL import static datadog.trace.api.config.TracerConfig.TRACE_SAMPLING_SERVICE_RULES import static datadog.trace.api.config.TracerConfig.TRACE_X_DATADOG_TAGS_MAX_LENGTH import static datadog.trace.api.config.TracerConfig.WRITER_TYPE +import static datadog.trace.api.config.TracerConfig.TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING +import static datadog.trace.api.config.TracerConfig.TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING import static datadog.trace.api.config.OtlpConfig.Protocol.HTTP_PROTOBUF import static datadog.trace.api.config.OtlpConfig.Protocol.HTTP_JSON import static datadog.trace.api.config.OtlpConfig.Temporality.CUMULATIVE @@ -184,6 +186,8 @@ class ConfigTest extends DDSpecification { private static final DD_LLMOBS_ENABLED_ENV = "DD_LLMOBS_ENABLED" private static final DD_LLMOBS_ML_APP_ENV = "DD_LLMOBS_ML_APP" private static final DD_LLMOBS_AGENTLESS_ENABLED_ENV = "DD_LLMOBS_AGENTLESS_ENABLED" + private static final DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING_ENV = "DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING" + private static final DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING_ENV = "DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING" private static final DD_TRACE_OTEL_ENABLED_ENV = "DD_TRACE_OTEL_ENABLED" private static final DD_TRACE_OTEL_ENABLED_PROP = "dd.trace.otel.enabled" @@ -313,6 +317,9 @@ class ConfigTest extends DDSpecification { prop.setProperty(TRACE_X_DATADOG_TAGS_MAX_LENGTH, "128") prop.setProperty(JDK_SOCKET_ENABLED, "false") + prop.setProperty(TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING, "all") + prop.setProperty(TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING, "all") + prop.setProperty(METRICS_OTEL_ENABLED, "True") prop.setProperty(METRICS_OTEL_INTERVAL, "11000") prop.setProperty(METRICS_OTEL_TIMEOUT, "9000") @@ -418,6 +425,10 @@ class ConfigTest extends DDSpecification { config.xDatadogTagsMaxLength == 128 config.jdkSocketEnabled == false + config.cloudRequestPayloadTagging == [] + config.cloudResponsePayloadTagging == [] + + config.xDatadogTagsMaxLength == 128 config.metricsOtelEnabled config.metricsOtelInterval == 11000 config.metricsOtelTimeout == 9000 @@ -708,6 +719,9 @@ class ConfigTest extends DDSpecification { System.setProperty(PREFIX + DYNAMIC_INSTRUMENTATION_EXCLUDE_FILES, "exclude file") System.setProperty(PREFIX + TRACE_X_DATADOG_TAGS_MAX_LENGTH, "128") + System.setProperty(PREFIX + TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING, "all") + System.setProperty(PREFIX + TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING, "all") + System.setProperty(DD_METRICS_OTEL_ENABLED_PROP, "True") System.setProperty(OTEL_METRIC_EXPORT_INTERVAL_PROP, "11000") System.setProperty(OTEL_METRIC_EXPORT_TIMEOUT_PROP, "9000") @@ -809,6 +823,9 @@ class ConfigTest extends DDSpecification { config.dynamicInstrumentationInstrumentTheWorld == "method" config.dynamicInstrumentationExcludeFiles == "exclude file" + config.cloudRequestPayloadTagging == [] + config.cloudResponsePayloadTagging == [] + config.xDatadogTagsMaxLength == 128 config.metricsOtelEnabled @@ -840,6 +857,9 @@ class ConfigTest extends DDSpecification { environmentVariables.set(DD_TRACE_LONG_RUNNING_ENABLED, "true") environmentVariables.set(DD_TRACE_LONG_RUNNING_FLUSH_INTERVAL, "81") environmentVariables.set(DD_TRACE_HEADER_TAGS, "*") + environmentVariables.set(DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING_ENV, "all") + environmentVariables.set(DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING_ENV, "all") + environmentVariables.set(DD_METRICS_OTEL_ENABLED_ENV, "True") environmentVariables.set(OTEL_RESOURCE_ATTRIBUTES_ENV, "service.name=my=app,service.version=1.0.0,deployment.environment=production") environmentVariables.set(OTEL_METRIC_EXPORT_INTERVAL_ENV, "11000") @@ -868,8 +888,11 @@ class ConfigTest extends DDSpecification { config.xDatadogTagsMaxLength == 42 config.isLongRunningTraceEnabled() config.getLongRunningTraceFlushInterval() == 81 - config.requestHeaderTags == ["*":"http.request.headers."] - config.responseHeaderTags == ["*":"http.response.headers."] + config.cloudRequestPayloadTagging == [] + config.cloudResponsePayloadTagging == [] + + config.requestHeaderTags == ["*": "http.request.headers."] + config.responseHeaderTags == ["*": "http.response.headers."] config.metricsOtelEnabled config.metricsOtelInterval == 11000 config.metricsOtelTimeout == 9000 @@ -888,6 +911,8 @@ class ConfigTest extends DDSpecification { environmentVariables.set(DD_PRIORITIZATION_TYPE_ENV, "EnsureTrace") environmentVariables.set(DD_TRACE_AGENT_PORT_ENV, "777") environmentVariables.set(DD_TRACE_LONG_RUNNING_ENABLED, "false") + environmentVariables.set(DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING_ENV, "all") + environmentVariables.set(DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING_ENV, "") System.setProperty(PREFIX + SERVICE_NAME, "what we actually want") System.setProperty(PREFIX + WRITER_TYPE, "DDAgentWriter") @@ -895,6 +920,8 @@ class ConfigTest extends DDSpecification { System.setProperty(PREFIX + AGENT_HOST, "somewhere") System.setProperty(PREFIX + TRACE_AGENT_PORT, "123") System.setProperty(PREFIX + TRACE_LONG_RUNNING_ENABLED, "true") + System.setProperty(PREFIX + TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING, "") + System.setProperty(PREFIX + TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING, "all") when: def config = new Config() @@ -907,6 +934,10 @@ class ConfigTest extends DDSpecification { config.agentUrl == "http://somewhere:123" config.longRunningTraceEnabled config.longRunningTraceFlushInterval == 120 + config.cloudRequestPayloadTagging == [] + config.cloudResponsePayloadTagging == [] + !config.isCloudRequestPayloadTaggingEnabled() + config.isCloudResponsePayloadTaggingEnabled() } def "default when configured incorrectly"() { @@ -1061,7 +1092,7 @@ class ConfigTest extends DDSpecification { config.mergedSpanTags == [b: "2", c: "3"] config.mergedJmxTags == [b: "2", d: "4", (RUNTIME_ID_TAG): config.getRuntimeId(), (SERVICE_TAG): config.serviceName] config.requestHeaderTags == [e: "five"] - config.baggageMapping == [f: "six",g: "g"] + config.baggageMapping == [f: "six", g: "g"] config.httpServerErrorStatuses == toBitSet((122..457)) config.httpClientErrorStatuses == toBitSet((111..111)) config.httpClientSplitByDomain == true @@ -1333,8 +1364,8 @@ class ConfigTest extends DDSpecification { value | expected // null means default value // spotless:off "1" | [1] - "3,13,400-403" | [3,13,400,401,402,403] - "2,10,13-15" | [2,10,13,14,15] + "3,13,400-403" | [3, 13, 400, 401, 402, 403] + "2,10,13-15" | [2, 10, 13, 14, 15] "a" | null "" | null "1000" | null @@ -2030,7 +2061,7 @@ class ConfigTest extends DDSpecification { //verify expected behavior when not enabled under feature flag config.logsInjectionEnabled == true - config.globalTags == [env:"test", aKey:"aVal", bKey:"bVal"] + config.globalTags == [env: "test", aKey: "aVal", bKey: "bVal"] } def "verify behavior of DD_TRACE_EXPERIMENTAL_FEATURE_ENABLED when value is 'all'"() { @@ -2105,18 +2136,18 @@ class ConfigTest extends DDSpecification { where: // spotless:off - value | tClass | expected - "true" | Boolean | true - "trUe" | Boolean | true - "false" | Boolean | false - "False" | Boolean | false - "1" | Boolean | true - "0" | Boolean | false - "42.42" | Float | 42.42f - "42.42" | Double | 42.42 - "44" | Integer | 44 - "45" | Long | 45 - "46" | Short | 46 + value | tClass | expected + "true" | Boolean | true + "trUe" | Boolean | true + "false" | Boolean | false + "False" | Boolean | false + "1" | Boolean | true + "0" | Boolean | false + "42.42" | Float | 42.42f + "42.42" | Double | 42.42 + "44" | Integer | 44 + "45" | Long | 45 + "46" | Short | 46 // spotless:on } @@ -2719,12 +2750,12 @@ class ConfigTest extends DDSpecification { where: configuredFlushInterval | flushInterval - "invalid" | DEFAULT_TRACE_LONG_RUNNING_INITIAL_FLUSH_INTERVAL - "-1" | DEFAULT_TRACE_LONG_RUNNING_INITIAL_FLUSH_INTERVAL - "9" | DEFAULT_TRACE_LONG_RUNNING_INITIAL_FLUSH_INTERVAL - "451" | DEFAULT_TRACE_LONG_RUNNING_INITIAL_FLUSH_INTERVAL - "10" | 10 - "450" | 450 + "invalid" | DEFAULT_TRACE_LONG_RUNNING_INITIAL_FLUSH_INTERVAL + "-1" | DEFAULT_TRACE_LONG_RUNNING_INITIAL_FLUSH_INTERVAL + "9" | DEFAULT_TRACE_LONG_RUNNING_INITIAL_FLUSH_INTERVAL + "451" | DEFAULT_TRACE_LONG_RUNNING_INITIAL_FLUSH_INTERVAL + "10" | 10 + "450" | 450 } def "ssi injection enabled"() { @@ -2770,12 +2801,12 @@ class ConfigTest extends DDSpecification { where: configuredFlushInterval | flushInterval - "invalid" | DEFAULT_TRACE_LONG_RUNNING_FLUSH_INTERVAL - "-1" | DEFAULT_TRACE_LONG_RUNNING_FLUSH_INTERVAL - "19" | DEFAULT_TRACE_LONG_RUNNING_FLUSH_INTERVAL - "451" | DEFAULT_TRACE_LONG_RUNNING_FLUSH_INTERVAL - "20" | 20 - "450" | 450 + "invalid" | DEFAULT_TRACE_LONG_RUNNING_FLUSH_INTERVAL + "-1" | DEFAULT_TRACE_LONG_RUNNING_FLUSH_INTERVAL + "19" | DEFAULT_TRACE_LONG_RUNNING_FLUSH_INTERVAL + "451" | DEFAULT_TRACE_LONG_RUNNING_FLUSH_INTERVAL + "20" | 20 + "450" | 450 } def "partial flush and min spans interaction"() { @@ -2818,10 +2849,10 @@ class ConfigTest extends DDSpecification { where: // spotless:off - enablementMode | expectedEnabled | expectedStartDelay | expectedStartForceFirst - "true" | true | 1 | true - "false" | false | 1 | true - "auto" | true | PROFILING_START_DELAY_DEFAULT | PROFILING_START_FORCE_FIRST_DEFAULT + enablementMode | expectedEnabled | expectedStartDelay | expectedStartForceFirst + "true" | true | 1 | true + "false" | false | 1 | true + "auto" | true | PROFILING_START_DELAY_DEFAULT | PROFILING_START_FORCE_FIRST_DEFAULT // spotless:on } @@ -2870,20 +2901,53 @@ class ConfigTest extends DDSpecification { "datad0g.com" | "https://all-http-intake.logs.datad0g.com/api/v2/apmtelemetry" } + def "set cloud payload tagging config"() { + setup: + environmentVariables.set(DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING_ENV, reqEnv) + environmentVariables.set(DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING_ENV, respEnv) + + when: + def config = new Config() + + then: + if (expectedReqConfig == null) { + // if expected config is null, then the feature should be disabled + assert !config.isCloudRequestPayloadTaggingEnabled() + } else { + assert config.cloudRequestPayloadTagging.toString() == expectedReqConfig + } + + if (expectedRespConfig == null) { + assert !config.isCloudResponsePayloadTaggingEnabled() + } else { + assert config.cloudResponsePayloadTagging.toString() == expectedRespConfig + } + + where: + reqEnv | respEnv | expectedReqConfig | expectedRespConfig + "all" | "all" | '[]' | '[]' + "all,invalid" | "all,invalid" | null | null + "" | "" | null | null + "invalid" | "invalid" | null | null + "\$.a" | "\$.b" | '[$[\'a\']]' | '[$[\'b\']]' + "\$.a,invalid" | "\$.b,invalid" | '[$[\'a\']]' | '[$[\'b\']]' + } + // Subclass for setting Strictness of ConfigHelper when using fake configs static class ConfigTestWithFakes extends ConfigTest { def strictness - def setup(){ + def setup() { strictness = ConfigHelper.get().configInversionStrictFlag() ConfigHelper.get().setConfigInversionStrict(ConfigHelper.StrictnessPolicy.TEST) } - def cleanup(){ + def cleanup() { ConfigHelper.get().setConfigInversionStrict(strictness) } + def "verify rule config #name"() { setup: environmentVariables.set("DD_TRACE_TEST_ENABLED", "true") diff --git a/dd-trace-core/src/test/groovy/datadog/trace/payloadtags/json/JsonPathParserSpec.groovy b/internal-api/src/test/groovy/datadog/trace/util/json/JsonPathParserSpec.groovy similarity index 92% rename from dd-trace-core/src/test/groovy/datadog/trace/payloadtags/json/JsonPathParserSpec.groovy rename to internal-api/src/test/groovy/datadog/trace/util/json/JsonPathParserSpec.groovy index d2c161426f9..5c3be6fc1c2 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/payloadtags/json/JsonPathParserSpec.groovy +++ b/internal-api/src/test/groovy/datadog/trace/util/json/JsonPathParserSpec.groovy @@ -1,4 +1,4 @@ -package datadog.trace.payloadtags.json +package datadog.trace.util.json import spock.lang.Specification @@ -8,6 +8,20 @@ class JsonPathParserSpec extends Specification { return JsonPath.Builder.start() } + def "parse lists of json-path patterns for payload tagging"() { + expect: + JsonPathParser.parseJsonPaths(paths).toString() == expected + + where: + paths | expected + ['$.a'] | '[$[\'a\']]' + ['$.a.b.c', '$.x.y.z'] | '[$[\'a\'][\'b\'][\'c\'], $[\'x\'][\'y\'][\'z\']]' + ['$.BarFoo', "invalid"] | '[$[\'BarFoo\']]' + ['all'] | '[]' + ['all', 'all'] | '[]' + ['invalid1', "invalid2"] | '[]' + } + def "parse correct json-path patterns"() { expect: JsonPathParser.parse(path).toString() == expected.toString() diff --git a/dd-trace-core/src/test/groovy/datadog/trace/payloadtags/json/JsonPathSpec.groovy b/internal-api/src/test/groovy/datadog/trace/util/json/JsonPathSpec.groovy similarity index 99% rename from dd-trace-core/src/test/groovy/datadog/trace/payloadtags/json/JsonPathSpec.groovy rename to internal-api/src/test/groovy/datadog/trace/util/json/JsonPathSpec.groovy index 42293126bdf..38412ca4dbf 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/payloadtags/json/JsonPathSpec.groovy +++ b/internal-api/src/test/groovy/datadog/trace/util/json/JsonPathSpec.groovy @@ -1,4 +1,4 @@ -package datadog.trace.payloadtags.json +package datadog.trace.util.json import spock.lang.Specification diff --git a/dd-trace-core/src/test/groovy/datadog/trace/payloadtags/json/PathCursorSpec.groovy b/internal-api/src/test/groovy/datadog/trace/util/json/PathCursorSpec.groovy similarity index 79% rename from dd-trace-core/src/test/groovy/datadog/trace/payloadtags/json/PathCursorSpec.groovy rename to internal-api/src/test/groovy/datadog/trace/util/json/PathCursorSpec.groovy index eba5530beb3..e2c70858755 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/payloadtags/json/PathCursorSpec.groovy +++ b/internal-api/src/test/groovy/datadog/trace/util/json/PathCursorSpec.groovy @@ -1,4 +1,4 @@ -package datadog.trace.payloadtags.json +package datadog.trace.util.json import spock.lang.Specification @@ -133,4 +133,38 @@ class PathCursorSpec extends Specification { then: p2.push("c").toString("") == ".a.3.b.c" } + + def "get item at index of path cursor"() { + expect: + p().push("a").push(3).get(0) == "a" + p().push("a").push(3).get(1) == 3 + } + + def "pop on empty cursor does nothing"() { + def p = p() + when: + p.pop() + + then: + p.length() == 0 + p.toString("") == "" + + when: + p.push("a").pop() + p.pop() + + then: + p.length() == 0 + p.toString("") == "" + } + + def "advance on empty cursor does nothing"() { + when: + def p = p() + p.advance() + + then: + p.length() == 0 + p.toString("") == "" + } }