-
Notifications
You must be signed in to change notification settings - Fork 303
Support targeting services with configurations in stable configuration file #8526
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 107 commits
Commits
Show all changes
109 commits
Select commit
Hold shift + click to select a range
a9d4400
Abstract away getVMArgumentsThroughReflection into a VMArgsCache class
mtoffl01 d688313
Change underlying data structure of VMArgsCache to HashSet
mtoffl01 d6344a8
Update internal-api/src/main/java/datadog/trace/bootstrap/config/prov…
mtoffl01 6aba3f8
Update internal-api/src/main/java/datadog/trace/bootstrap/config/prov…
mtoffl01 8afbec1
Update internal-api/src/main/java/datadog/trace/bootstrap/config/prov…
mtoffl01 d807b02
Clean up for initial review
mtoffl01 0603490
fix merge conflicts
mtoffl01 7ce4953
move VMArgsCache to components/cli
mtoffl01 7a9f694
fix datadog.cli import
mtoffl01 dd17ca2
nits: remove outdated comments
mtoffl01 2798bed
annotate initJvmArgs with @SuppressForbidden to allow Class.forName()…
mtoffl01 f5d89a3
initial implementation using snakeyaml + StableConfigYaml for parsing…
mtoffl01 0f54ff1
Clean up tests + expand selectorMatch to cover environment_variables …
mtoffl01 9826f0f
address [some] github codequality breaches
mtoffl01 63280ae
use config_id even if configs are empty/missing
mtoffl01 5859ec9
nits: refactor StableConfigParser for clarity
mtoffl01 4e8c0fa
Clean up for first review
mtoffl01 1bf6ccc
Amend StableConfigParserTest valid test to include multiple selector-…
mtoffl01 57762b1
nits/ cleanup
mtoffl01 fe843e1
nits/ cleanup
mtoffl01 55a798b
Fix Test Optimization init when repo root cannot be determined (#8533)
nikita-tkachenko-datadog cdd2010
Improve Baggage API (#8523)
PerfectSlayer 9a4458a
Update system-tests to 5aee0ed598fd984344cf0da0048b27bdb2eb4da1 (#8537)
mhlidd 89286d7
Introducing `DD_TRACE_EXPERIMENTAL_FEATURES_ENABLED` Config (#8536)
mhlidd 4c2a2f5
Remove AgentScope.source() from instrumentation API (#8539)
mcculls fd8a076
Add smoke tests for java's concurrent API (#8438)
sarahchen6 f1da84c
Update capabilities tagging to use versioning (#8540)
daniel-mohedano 7d5b034
Remove ScopeSource from instrumentation API (#8542)
mcculls c1d1693
Simplify activateSpan calls which use the default value for isAsyncPr…
mcculls 5ae5655
Make the default config sources more robust when a security manager i…
mcculls dc70612
Support common config sources for user-provided git info (#8547)
nikita-tkachenko-datadog 3765fd1
Allow login events SDK to be used with appsec disabled (#8464)
manuel-alvarez-alvarez b7656bd
Update system-tests to c208feb5b40cca543670870b9601509d6a69c65e (#8550)
manuel-alvarez-alvarez 6eb11aa
Add missing address for signup event (#8469)
manuel-alvarez-alvarez 0a8bc73
Remove unnecessary calls to setAsyncPropagationEnabled (#8551)
mcculls 26c11f4
Be consistent when deciding when to do async propagation (#8555)
mcculls 3c4876c
Add new parser for `DD_TAGS` and prioritizing `DD_SERVICE` (#8296)
mhlidd 518cd4a
Async propagation is on by default, so HystrixThreadPoolInstrumentati…
mcculls 8f2d28b
Ensure shaded helpers have unique names (#8559)
amarziali 90c7cbe
ssi tests one-pipeline (#8558)
robertomonteromiguel d06699d
Fix ForkJoinPool.execute() instrumentation on Java 21+ (#8560)
PerfectSlayer 12fe632
Simplify activateSpan API to not include async propagation flag (#8557)
mcculls 7475368
Use internal artifact proxy for Gitlab jobs (#8554)
randomanderson f646940
Remove ScopeSource enum (#8565)
mcculls e8eb022
fix(ci): Mark tests as flaky (#8568)
PerfectSlayer 7ff940b
Prevent before callsites targeting constructors in super calls (#8549)
manuel-alvarez-alvarez 3d8d129
Add JDK built-in support for UDS on Java 16+ (#8314)
sarahchen6 8327a8f
Allow to manually set PR info (#8566)
nikita-tkachenko-datadog 9a78dd7
Nits: Update comments and include exception in log messages
mtoffl01 630c61f
Vendor snakeyaml
mcculls 11b01da
Fix PlayNettySmokeTest logging config (#8576)
smola 888cbd4
Expose Context.empty() as building block for creating custom root con…
mcculls b5b31c3
RASP capabilities for LFI is not sent when RASP is not fully enabled…
jandro996 6473621
Minor test changes to avoid deprecated API (#8574)
mcculls 84ba99a
internal tests for stable config use snakeyaml to build test files
mcculls a920812
Fix test
mcculls f07ed11
Fix instrumentation test+muzzle
mcculls e624538
Inherited decision maker is a meta (#8578)
amarziali f7a339e
Simplification: Context.root() is always empty (#8580)
mcculls 1e1ef67
Support and test kafka-clients 4 (#8581)
amarziali 3f336db
List components:yaml in the dependencies to exclude outside of shared…
mcculls 0c2b8e2
fix muzzle on CI
mcculls c9d4c10
Improve StableConfig exception logging
mtoffl01 7a8fabe
Include StableConfigYaml in java-agent shadowJar
mtoffl01 d1fc580
Change in selectorMatch switch to return false
mtoffl01 f1fdaaf
Make selectorMatch case insensitive
mtoffl01 e94a06a
fix null ptr exceptions in selectorMatch
mtoffl01 a52a393
convert underlying datastructure to hashmap; split jvm args into key …
mtoffl01 dab2bbb
write CLIHelper Test
mtoffl01 e9fec18
Update javaagent logic inside of AgentBootstrap
mtoffl01 f04424e
merge with base branch mtoff/jvm-args
mtoffl01 1ac75d9
Rebase with mtoff/jvm-args
mtoffl01 1d30309
Merge branch 'master' into mtoff/jvm-args
mtoffl01 ca2ae42
merge in mtoff/jvm-args
mtoffl01 94c6d53
remove unused components/cli test dir
mtoffl01 73af087
Cleanup
mtoffl01 4ab687f
nits/cleanup
mtoffl01 2ca8d98
Merge remote-tracking branch 'origin/master' into mtoff/jvm-args
mcculls 253e5e4
Fix package directory
mcculls e67ae7a
Cleanup code:
mcculls b844607
Remove warning when reflection fails
mcculls 8837a21
Expose components:cli from internal-api
mcculls 46f0902
Merge branch 'mtoff/jvm-args' into mtoff/stable_cfg_2
mcculls 2a2012c
Fix package directory
mcculls f00b0f4
Expose components:yaml from internal-api
mcculls e3ad995
Domain classes should not exist in component module
mcculls 8324c3a
Cleanup relocation
mcculls 83b2f7e
Fix
mcculls b0f4c55
Cleanup
mcculls e2ef0ef
Merge branch 'master' into mtoff/stable_cfg_2
mtoffl01 f085baf
Remove unused ConfigurationValue.toString; hopefully pass Jacoco test…
mtoffl01 3b86143
reset to f085bafeed
mtoffl01 1a48f84
manually remove testImplementation snakeyaml 1.33 changes in dd-smoke…
mtoffl01 a99d016
exclude org.yaml.snakeyaml dependency from dd-smoke-tests
mtoffl01 a62edd3
Merge branch 'master' into mtoff/stable_cfg_2
mtoffl01 8389804
Merge branch 'master' into mtoff/stable_cfg_2
mtoffl01 1a8cee4
Remove unused ConfigurationValue.toString (again..)
mtoffl01 679c4ca
Attempt to fix muzzle
mcculls 9e905b5
Attempt to fix muzzle
mcculls 29c1925
comment
mcculls 6f28159
Merge remote-tracking branch 'origin/master' into mtoff/stable_cfg_2
mcculls 10a1028
cleanup
mcculls d9b6836
log when we find stable config. rather than when we don't (also reduc…
mcculls 65b4cb7
Merge branch 'master' into mtoff/stable_cfg_2
mtoffl01 b8283a9
Update internal-api/src/main/java/datadog/trace/bootstrap/config/prov…
mtoffl01 dd40811
Update internal-api/src/main/java/datadog/trace/bootstrap/config/prov…
mtoffl01 ccc18c6
Make selector match package-private
mtoffl01 cffcc17
remove comment reminder about process_arguments test
mtoffl01 23f1013
Merge branch 'master' into mtoff/stable_cfg_2
mtoffl01 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
plugins { | ||
id("me.champeau.jmh") | ||
} | ||
|
||
apply(from = "$rootDir/gradle/java.gradle") | ||
|
||
jmh { | ||
version = "1.28" | ||
} | ||
|
||
// https://repo1.maven.org/maven2/org/yaml/snakeyaml/2.4/snakeyaml-2.4.pom | ||
dependencies { | ||
implementation("org.yaml", "snakeyaml", "2.4") | ||
} |
19 changes: 19 additions & 0 deletions
19
components/yaml/src/main/java/datadog/yaml/YamlParser.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package datadog.yaml; | ||
|
||
import java.io.FileInputStream; | ||
import java.io.IOException; | ||
import org.yaml.snakeyaml.Yaml; | ||
|
||
public class YamlParser { | ||
// Supports clazz == null for default yaml parsing | ||
public static <T> T parse(String filePath, Class<T> clazz) throws IOException { | ||
Yaml yaml = new Yaml(); | ||
try (FileInputStream fis = new FileInputStream(filePath)) { | ||
if (clazz == null) { | ||
return yaml.load(fis); | ||
} else { | ||
return yaml.loadAs(fis, clazz); | ||
} | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
220 changes: 161 additions & 59 deletions
220
internal-api/src/main/java/datadog/trace/bootstrap/config/provider/StableConfigParser.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,77 +1,179 @@ | ||
package datadog.trace.bootstrap.config.provider; | ||
|
||
import java.io.File; | ||
import datadog.cli.CLIHelper; | ||
import datadog.trace.bootstrap.config.provider.stableconfigyaml.ConfigurationMap; | ||
import datadog.trace.bootstrap.config.provider.stableconfigyaml.Rule; | ||
import datadog.trace.bootstrap.config.provider.stableconfigyaml.Selector; | ||
import datadog.trace.bootstrap.config.provider.stableconfigyaml.StableConfigYaml; | ||
import datadog.yaml.YamlParser; | ||
import java.io.IOException; | ||
import java.nio.file.Files; | ||
import java.nio.file.Paths; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
import java.util.stream.Stream; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.util.function.BiPredicate; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
public class StableConfigParser { | ||
private static final Logger log = LoggerFactory.getLogger(StableConfigParser.class); | ||
// Match config_id:<value> | ||
private static final Pattern idPattern = Pattern.compile("^config_id\\s*:(.*)$"); | ||
// Match 'apm_configuration_default:' | ||
private static final Pattern apmConfigPattern = Pattern.compile("^apm_configuration_default:$"); | ||
// Match indented (2 spaces) key-value pairs, either with double quotes or without | ||
private static final Pattern keyValPattern = | ||
Pattern.compile("^\\s{2}([^:]+):\\s*(\"[^\"]*\"|[^\"\\n]*)$");; | ||
|
||
private static final Set<String> VM_ARGS = new HashSet<>(CLIHelper.getVmArgs()); | ||
|
||
/** | ||
* Parses a configuration file and returns a stable configuration object. | ||
* | ||
* <p>This method reads a configuration file from the given file path, parses the YAML content, | ||
* and identifies configurations for the process using a combination of apm_configuration_default | ||
* and apm_configuration_rules. If a matching rule is found in apm_configuration_rules, it returns | ||
* a {@link StableConfigSource.StableConfig} object with the merged configuration. If no matching | ||
* rule is found, it returns the default configuration. If neither a matching rule nor a default | ||
* configuration is found, an empty configuration is returned. | ||
* | ||
* @param filePath The path to the YAML configuration file to be parsed. | ||
* @return A {@link StableConfigSource.StableConfig} object containing the stable configuration. | ||
* @throws IOException If there is an error reading the file or parsing the YAML content. | ||
*/ | ||
public static StableConfigSource.StableConfig parse(String filePath) throws IOException { | ||
File file = new File(filePath); | ||
if (!file.exists()) { | ||
log.debug("Stable configuration file not available at specified path: {}", file); | ||
return StableConfigSource.StableConfig.EMPTY; | ||
try { | ||
StableConfigYaml data = YamlParser.parse(filePath, StableConfigYaml.class); | ||
|
||
String configId = data.getConfig_id(); | ||
ConfigurationMap configMap = data.getApm_configuration_default(); | ||
List<Rule> rules = data.getApm_configuration_rules(); | ||
|
||
if (!rules.isEmpty()) { | ||
for (Rule rule : rules) { | ||
// Use the first matching rule | ||
if (doesRuleMatch(rule)) { | ||
// Merge configs found in apm_configuration_rules with those found in | ||
// apm_configuration_default | ||
configMap.putAll(rule.getConfiguration()); | ||
return createStableConfig(configId, configMap); | ||
} | ||
} | ||
} | ||
// If configs were found in apm_configuration_default, use them | ||
if (!configMap.isEmpty()) { | ||
return createStableConfig(configId, configMap); | ||
} | ||
|
||
// If there's a configId but no configMap, use configId but return an empty map | ||
if (configId != null) { | ||
return new StableConfigSource.StableConfig(configId, Collections.emptyMap()); | ||
} | ||
|
||
} catch (IOException e) { | ||
log.debug( | ||
"Stable configuration file either not found or not readable at filepath {}", filePath); | ||
} | ||
return StableConfigSource.StableConfig.EMPTY; | ||
} | ||
|
||
/** | ||
* Checks if the rule's selectors match the current process. All must match for a "true" return | ||
* value. | ||
*/ | ||
private static boolean doesRuleMatch(Rule rule) { | ||
for (Selector selector : rule.getSelectors()) { | ||
if (!selectorMatch( | ||
selector.getOrigin(), selector.getMatches(), selector.getOperator(), selector.getKey())) { | ||
return false; // Return false immediately if any selector doesn't match | ||
} | ||
} | ||
return true; // Return true if all selectors match | ||
} | ||
|
||
/** Creates a StableConfig object from the provided configId and configMap. */ | ||
private static StableConfigSource.StableConfig createStableConfig( | ||
String configId, ConfigurationMap configMap) { | ||
return new StableConfigSource.StableConfig(configId, new HashMap<>(configMap)); | ||
} | ||
|
||
private static boolean validOperatorForLanguageOrigin(String operator) { | ||
operator = operator.toLowerCase(); | ||
// "exists" is not valid | ||
switch (operator) { | ||
case "equals": | ||
case "starts_with": | ||
case "ends_with": | ||
case "contains": | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
|
||
private static boolean checkEnvMatches( | ||
List<String> values, List<String> matches, BiPredicate<String, String> compareFunc) { | ||
// envValue shouldn't be null, but doing an extra check to avoid NullPointerException on | ||
// compareFunc.test | ||
if (values == null) { | ||
return false; | ||
} | ||
Map<String, String> configMap = new HashMap<>(); | ||
String[] configId = new String[1]; | ||
try (Stream<String> lines = Files.lines(Paths.get(filePath))) { | ||
int apmConfigNotFound = -1, apmConfigStarted = 0, apmConfigComplete = 1; | ||
int[] apmConfigFound = {apmConfigNotFound}; | ||
lines.forEach( | ||
line -> { | ||
Matcher matcher = idPattern.matcher(line); | ||
if (matcher.find()) { | ||
// Do not allow duplicate config_id keys | ||
if (configId[0] != null) { | ||
throw new RuntimeException("Duplicate config_id keys found; file may be malformed"); | ||
} | ||
configId[0] = trimQuotes(matcher.group(1).trim()); | ||
return; // go to next line | ||
} | ||
// TODO: Do not allow duplicate apm_configuration_default keys; and/or return early once | ||
// apmConfigFound[0] == apmConfigComplete | ||
if (apmConfigFound[0] == apmConfigNotFound | ||
&& apmConfigPattern.matcher(line).matches()) { | ||
apmConfigFound[0] = apmConfigStarted; | ||
return; // go to next line | ||
} | ||
if (apmConfigFound[0] == apmConfigStarted) { | ||
Matcher keyValueMatcher = keyValPattern.matcher(line); | ||
if (keyValueMatcher.matches()) { | ||
configMap.put( | ||
keyValueMatcher.group(1).trim(), | ||
trimQuotes(keyValueMatcher.group(2).trim())); // Store key-value pair in map | ||
} else { | ||
// If we encounter a non-indented or non-key-value line, stop processing | ||
apmConfigFound[0] = apmConfigComplete; | ||
} | ||
} | ||
}); | ||
return new StableConfigSource.StableConfig(configId[0], configMap); | ||
for (String match : matches) { | ||
if (match == null) { | ||
continue; | ||
} | ||
for (String value : values) { | ||
if (compareFunc.test(value, match.toLowerCase())) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
private static String trimQuotes(String value) { | ||
if (value.length() > 1 && (value.startsWith("'") && value.endsWith("'")) | ||
|| (value.startsWith("\"") && value.endsWith("\""))) { | ||
return value.substring(1, value.length() - 1); | ||
// We do all of the case insensitivity modifications in this function, because each selector will | ||
// be viewed just once | ||
static boolean selectorMatch(String origin, List<String> matches, String operator, String key) { | ||
switch (origin.toLowerCase()) { | ||
case "language": | ||
if (!validOperatorForLanguageOrigin(operator)) { | ||
return false; | ||
} | ||
for (String entry : matches) { | ||
// loose match on any reference to "*java*" | ||
if (entry.toLowerCase().contains("java")) { | ||
return true; | ||
} | ||
} | ||
case "environment_variables": | ||
if (key == null) { | ||
return false; | ||
} | ||
String envValue = System.getenv(key.toUpperCase()); | ||
if (envValue == null) { | ||
return false; | ||
} | ||
envValue = envValue.toLowerCase(); | ||
switch (operator.toLowerCase()) { | ||
case "exists": | ||
// We don't care about the value | ||
return true; | ||
case "equals": | ||
return checkEnvMatches( | ||
Collections.singletonList(envValue), matches, String::equalsIgnoreCase); | ||
case "starts_with": | ||
return checkEnvMatches( | ||
Collections.singletonList(envValue), matches, String::startsWith); | ||
case "ends_with": | ||
return checkEnvMatches(Collections.singletonList(envValue), matches, String::endsWith); | ||
case "contains": | ||
return checkEnvMatches(Collections.singletonList(envValue), matches, String::contains); | ||
default: | ||
return false; | ||
} | ||
case "process_arguments": | ||
// For now, always return true if `key` exists in the JVM Args | ||
// TODO: flesh out the meaning of each operator for process_arguments | ||
return VM_ARGS.contains(key); | ||
case "tags": | ||
// TODO: Support this down the line (Must define the source of "tags" first) | ||
return false; | ||
default: | ||
return false; | ||
} | ||
return value; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.