Skip to content

Commit 3684c74

Browse files
authored
Merge branch 'master' into augusto.deoliveira/apmsp-2369.ensure-correct-interrupt-policy
2 parents a1649f3 + c05874d commit 3684c74

File tree

109 files changed

+5214
-103
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

109 files changed

+5214
-103
lines changed

.github/CODEOWNERS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@
115115
**/datastreams/ @DataDog/data-streams-monitoring
116116
**/DataStreams* @DataDog/data-streams-monitoring
117117

118+
# @DataDog/feature-flagging-and-experimentation-sdk
119+
/products/feature-flagging/ @DataDog/feature-flagging-and-experimentation-sdk
120+
118121
# @DataDog/profiling-java
119122
/dd-java-agent/agent-profiling/ @DataDog/profiling-java
120123
/dd-java-agent/agent-crashtracking/ @DataDog/profiling-java

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ out/
4646
######################
4747
.vscode
4848

49+
# Cursor #
50+
##########
51+
.cursor
52+
4953
# Others #
5054
##########
5155
/logs/*

buildSrc/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ dependencies {
5757
implementation(gradleApi())
5858
implementation(localGroovy())
5959

60-
implementation("net.bytebuddy", "byte-buddy-gradle-plugin", "1.17.7")
60+
implementation("net.bytebuddy", "byte-buddy-gradle-plugin", "1.18.1")
6161

6262
implementation("org.eclipse.aether", "aether-connector-basic", "1.1.0")
6363
implementation("org.eclipse.aether", "aether-transport-http", "1.1.0")

buildSrc/src/main/kotlin/datadog.configure-tests.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ tasks.withType<Test>().configureEach {
101101
develocity.testRetry {
102102
if (providers.environmentVariable("CI").isPresent()) {
103103
maxRetries = 3
104+
filter {
105+
excludeAnnotationClasses.add("*NonRetryable") // allow to mark classes non retryable
106+
}
104107
}
105108
}
106109
}

buildSrc/src/test/groovy/CallSiteInstrumentationPluginTest.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class CallSiteInstrumentationPluginTest extends Specification {
2727
}
2828
2929
dependencies {
30-
implementation group: 'net.bytebuddy', name: 'byte-buddy', version: '1.17.7'
30+
implementation group: 'net.bytebuddy', name: 'byte-buddy', version: '1.18.1'
3131
implementation group: 'com.google.auto.service', name: 'auto-service-annotations', version: '1.1.1'
3232
}
3333
'''

buildSrc/src/test/groovy/InstrumentPluginTest.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class InstrumentPluginTest extends Specification {
2323
}
2424
2525
dependencies {
26-
compileOnly group: 'net.bytebuddy', name: 'byte-buddy', version: '1.17.7' // just to build TestPlugin
26+
compileOnly group: 'net.bytebuddy', name: 'byte-buddy', version: '1.18.1' // just to build TestPlugin
2727
}
2828
2929
apply plugin: 'instrument'

dd-java-agent/agent-aiguard/src/main/java/com/datadog/aiguard/AIGuardInternal.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import static datadog.trace.api.telemetry.WafMetricCollector.AIGuardTruncationType.CONTENT;
55
import static datadog.trace.api.telemetry.WafMetricCollector.AIGuardTruncationType.MESSAGES;
66
import static datadog.trace.util.Strings.isBlank;
7-
import static java.util.Collections.singletonMap;
87

98
import com.squareup.moshi.JsonAdapter;
109
import com.squareup.moshi.JsonReader;
@@ -69,7 +68,8 @@ public BadConfigurationException(final String message) {
6968
static final String REASON_TAG = "ai_guard.reason";
7069
static final String BLOCKED_TAG = "ai_guard.blocked";
7170
static final String META_STRUCT_TAG = "ai_guard";
72-
static final String META_STRUCT_KEY = "messages";
71+
static final String META_STRUCT_MESSAGES = "messages";
72+
static final String META_STRUCT_CATEGORIES = "attack_categories";
7373

7474
public static void install() {
7575
final Config config = Config.get();
@@ -208,8 +208,8 @@ public Evaluation evaluate(final List<Message> messages, final Options options)
208208
} else {
209209
span.setTag(TARGET_TAG, "prompt");
210210
}
211-
final Map<String, Object> metaStruct =
212-
singletonMap(META_STRUCT_KEY, messagesForMetaStruct(messages));
211+
final Map<String, Object> metaStruct = new HashMap<>(2);
212+
metaStruct.put(META_STRUCT_MESSAGES, messagesForMetaStruct(messages));
213213
span.setMetaStruct(META_STRUCT_TAG, metaStruct);
214214
final Request.Builder request =
215215
new Request.Builder()
@@ -224,14 +224,21 @@ public Evaluation evaluate(final List<Message> messages, final Options options)
224224
}
225225
final Action action = Action.valueOf(actionStr);
226226
final String reason = (String) result.get("reason");
227+
@SuppressWarnings("unchecked")
228+
final List<String> tags = (List<String>) result.get("tags");
227229
span.setTag(ACTION_TAG, action);
228-
span.setTag(REASON_TAG, reason);
230+
if (reason != null) {
231+
span.setTag(REASON_TAG, reason);
232+
}
233+
if (tags != null && !tags.isEmpty()) {
234+
metaStruct.put(META_STRUCT_CATEGORIES, tags);
235+
}
229236
final boolean shouldBlock =
230237
isBlockingEnabled(options, result.get("is_blocking_enabled")) && action != Action.ALLOW;
231238
WafMetricCollector.get().aiGuardRequest(action, shouldBlock);
232239
if (shouldBlock) {
233240
span.setTag(BLOCKED_TAG, true);
234-
throw new AIGuardAbortError(action, reason);
241+
throw new AIGuardAbortError(action, reason, tags);
235242
}
236243
return new Evaluation(action, reason);
237244
}

dd-java-agent/agent-aiguard/src/test/groovy/com/datadog/aiguard/AIGuardInternalTests.groovy

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,14 @@ class AIGuardInternalTests extends DDSpecification {
157157
Request request = null
158158
Throwable error = null
159159
AIGuard.Evaluation eval = null
160+
Map<String, Object> receivedMeta = null
160161
final throwAbortError = suite.blocking && suite.action != ALLOW
161162
final call = Mock(Call) {
162163
execute() >> {
163164
return mockResponse(
164165
request,
165166
200,
166-
[data: [attributes: [action: suite.action, reason: suite.reason, is_blocking_enabled: suite.blocking]]]
167+
[data: [attributes: [action: suite.action, reason: suite.reason, tags: suite.tags ?: [], is_blocking_enabled: suite.blocking]]]
167168
)
168169
}
169170
}
@@ -189,11 +190,18 @@ class AIGuardInternalTests extends DDSpecification {
189190
}
190191
1 * span.setTag(AIGuardInternal.ACTION_TAG, suite.action)
191192
1 * span.setTag(AIGuardInternal.REASON_TAG, suite.reason)
192-
1 * span.setMetaStruct(AIGuardInternal.META_STRUCT_TAG, [messages: suite.messages])
193+
1 * span.setMetaStruct(AIGuardInternal.META_STRUCT_TAG, _ as Map) >> {
194+
receivedMeta = it[1] as Map<String, Object>
195+
return span
196+
}
193197
if (throwAbortError) {
194198
1 * span.addThrowable(_ as AIGuard.AIGuardAbortError)
195199
}
196200

201+
receivedMeta.messages == suite.messages
202+
if (suite.tags) {
203+
receivedMeta.attack_categories == suite.tags
204+
}
197205
assertRequest(request, suite.messages)
198206
if (throwAbortError) {
199207
error instanceof AIGuard.AIGuardAbortError
@@ -444,6 +452,14 @@ class AIGuardInternalTests extends DDSpecification {
444452
0 * span.setTag(AIGuardInternal.TOOL_TAG, _)
445453
}
446454

455+
void 'map requires even number of params'() {
456+
when:
457+
AIGuardInternal.mapOf('1', '2', '3')
458+
459+
then:
460+
thrown(IllegalArgumentException)
461+
}
462+
447463
private static assertTelemetry(final String metric, final String...tags) {
448464
final metrics = WafMetricCollector.get().with {
449465
prepareMetrics()
@@ -497,22 +513,28 @@ class AIGuardInternalTests extends DDSpecification {
497513
private static class TestSuite {
498514
private final AIGuard.Action action
499515
private final String reason
516+
private final List<String> tags
500517
private final boolean blocking
501518
private final String description
502519
private final String target
503520
private final List<AIGuard.Message> messages
504521

505-
TestSuite(AIGuard.Action action, String reason, boolean blocking, String description, String target, List<AIGuard.Message> messages) {
522+
TestSuite(AIGuard.Action action, String reason, List<String> tags, boolean blocking, String description, String target, List<AIGuard.Message> messages) {
506523
this.action = action
507524
this.reason = reason
525+
this.tags = tags
508526
this.blocking = blocking
509527
this.description = description
510528
this.target = target
511529
this.messages = messages
512530
}
513531

514532
static List<TestSuite> build() {
515-
def actionValues = [[ALLOW, 'Go ahead'], [DENY, 'Nope'], [ABORT, 'Kill it with fire']]
533+
def actionValues = [
534+
[ALLOW, 'Go ahead', []],
535+
[DENY, 'Nope', ['deny_everything', 'test_deny']],
536+
[ABORT, 'Kill it with fire', ['alarm_tag', 'abort_everything']]
537+
]
516538
def blockingValues = [true, false]
517539
def suiteValues = [
518540
['tool call', 'tool', TOOL_CALL],
@@ -521,7 +543,7 @@ class AIGuardInternalTests extends DDSpecification {
521543
]
522544
return combinations([actionValues, blockingValues, suiteValues] as Iterable)
523545
.collect { action, blocking, suite ->
524-
new TestSuite(action[0], action[1], blocking, suite[0], suite[1], suite[2])
546+
new TestSuite(action[0], action[1], action[2], blocking, suite[0], suite[1], suite[2])
525547
}
526548
}
527549

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import datadog.trace.api.config.CrashTrackingConfig;
3333
import datadog.trace.api.config.CwsConfig;
3434
import datadog.trace.api.config.DebuggerConfig;
35+
import datadog.trace.api.config.FeatureFlaggingConfig;
3536
import datadog.trace.api.config.GeneralConfig;
3637
import datadog.trace.api.config.IastConfig;
3738
import datadog.trace.api.config.JmxFetchConfig;
@@ -125,7 +126,8 @@ private enum AgentFeature {
125126
DATA_JOBS(GeneralConfig.DATA_JOBS_ENABLED, false),
126127
AGENTLESS_LOG_SUBMISSION(GeneralConfig.AGENTLESS_LOG_SUBMISSION_ENABLED, false),
127128
LLMOBS(LlmObsConfig.LLMOBS_ENABLED, false),
128-
LLMOBS_AGENTLESS(LlmObsConfig.LLMOBS_AGENTLESS_ENABLED, false);
129+
LLMOBS_AGENTLESS(LlmObsConfig.LLMOBS_AGENTLESS_ENABLED, false),
130+
FEATURE_FLAGGING(FeatureFlaggingConfig.FLAGGING_PROVIDER_ENABLED, false);
129131

130132
private final String configKey;
131133
private final String systemProp;
@@ -184,6 +186,7 @@ public boolean isEnabledByDefault() {
184186
private static boolean codeOriginEnabled = false;
185187
private static boolean distributedDebuggerEnabled = false;
186188
private static boolean agentlessLogSubmissionEnabled = false;
189+
private static boolean featureFlaggingEnabled = false;
187190

188191
private static void safelySetContextClassLoader(ClassLoader classLoader) {
189192
try {
@@ -268,6 +271,7 @@ public static void start(
268271
codeOriginEnabled = isFeatureEnabled(AgentFeature.CODE_ORIGIN);
269272
agentlessLogSubmissionEnabled = isFeatureEnabled(AgentFeature.AGENTLESS_LOG_SUBMISSION);
270273
llmObsEnabled = isFeatureEnabled(AgentFeature.LLMOBS);
274+
featureFlaggingEnabled = isFeatureEnabled(AgentFeature.FEATURE_FLAGGING);
271275

272276
// setup writers when llmobs is enabled to accomodate apm and llmobs
273277
if (llmObsEnabled) {
@@ -662,6 +666,7 @@ public void execute() {
662666
maybeStartDebugger(instrumentation, scoClass, sco);
663667
maybeStartRemoteConfig(scoClass, sco);
664668
maybeStartAiGuard();
669+
maybeStartFeatureFlagging(scoClass, sco);
665670

666671
if (telemetryEnabled) {
667672
startTelemetry(instrumentation, scoClass, sco);
@@ -1083,6 +1088,23 @@ private static void maybeStartLLMObs(Instrumentation inst, Class<?> scoClass, Ob
10831088
}
10841089
}
10851090

1091+
private static void maybeStartFeatureFlagging(final Class<?> scoClass, final Object sco) {
1092+
if (featureFlaggingEnabled) {
1093+
StaticEventLogger.begin("Feature Flagging");
1094+
1095+
try {
1096+
final Class<?> ffSysClass =
1097+
AGENT_CLASSLOADER.loadClass("com.datadog.featureflag.FeatureFlaggingSystem");
1098+
final Method ffSysMethod = ffSysClass.getMethod("start", scoClass);
1099+
ffSysMethod.invoke(null, sco);
1100+
} catch (final Throwable e) {
1101+
log.warn("Not starting Feature Flagging subsystem", e);
1102+
}
1103+
1104+
StaticEventLogger.end("Feature Flagging");
1105+
}
1106+
}
1107+
10861108
private static void maybeInstallLogsIntake(Class<?> scoClass, Object sco) {
10871109
if (agentlessLogSubmissionEnabled) {
10881110
StaticEventLogger.begin("Logs Intake");

dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ public CrashLog parse(String uuid, String crashLog) {
120120
String pid = null;
121121
List<StackFrame> frames = new ArrayList<>();
122122
String datetime = null;
123-
StringBuilder message = new StringBuilder();
124123
boolean incomplete = false;
125124

126125
String[] lines = NEWLINE_SPLITTER.split(crashLog);
@@ -130,7 +129,6 @@ public CrashLog parse(String uuid, String crashLog) {
130129
case NEW:
131130
if (line.startsWith(
132131
"# A fatal error has been detected by the Java Runtime Environment:")) {
133-
message.append("\n\n");
134132
state = State.MESSAGE; // jump directly to MESSAGE state
135133
}
136134
break;
@@ -151,8 +149,6 @@ public CrashLog parse(String uuid, String crashLog) {
151149
int endIdx = line.indexOf(',', pidIdx);
152150
pid = line.substring(pidIdx + 4, endIdx);
153151
}
154-
} else {
155-
message.append(line.substring(2)).append('\n');
156152
}
157153
}
158154
break;
@@ -174,7 +170,6 @@ public CrashLog parse(String uuid, String crashLog) {
174170
case THREAD:
175171
// Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
176172
if (line.startsWith("Native frames: ")) {
177-
message.append('\n').append(line).append('\n');
178173
state = State.STACKTRACE;
179174
}
180175
break;
@@ -183,7 +178,6 @@ public CrashLog parse(String uuid, String crashLog) {
183178
state = State.DONE;
184179
} else {
185180
// Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
186-
message.append(line).append('\n');
187181
frames.add(parseLine(line));
188182
}
189183
break;
@@ -200,10 +194,10 @@ public CrashLog parse(String uuid, String crashLog) {
200194
// incomplete crash log
201195
incomplete = true;
202196
}
197+
String message = "Process terminated by signal " + (signal != null ? signal : "UNKNOWN");
203198

204199
ErrorData error =
205-
new ErrorData(
206-
signal, message.toString(), new StackTrace(frames.toArray(new StackFrame[0])));
200+
new ErrorData(signal, message, new StackTrace(frames.toArray(new StackFrame[0])));
207201
// We can not really extract the full metadata and os info from the crash log
208202
// This code assumes the parser is run on the same machine as the crash happened
209203
Metadata metadata = new Metadata("dd-trace-java", VersionInfo.VERSION, "java", null);

0 commit comments

Comments
 (0)