Skip to content

Commit 955fa92

Browse files
authored
Merge branch 'master' into dougqh/v05-serializer-no-boxing
2 parents 4d931cc + 02cc483 commit 955fa92

23 files changed

Lines changed: 948 additions & 46 deletions

File tree

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturedSnapshotTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2845,6 +2845,7 @@ private TestSnapshotListener setupInstrumentTheWorldTransformer(
28452845
return listener;
28462846
}
28472847

2848+
// TODO: JEP 500 - avoid mutating final fields
28482849
private void setCorrelationSingleton(Object instance) {
28492850
Class<?> singletonClass = CorrelationAccess.class.getDeclaredClasses()[0];
28502851
try {

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/origin/CodeOriginConfigTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ public void defaultConfigJDK25() {
2222
@EnabledOnJre(JRE.JAVA_21)
2323
@Test
2424
public void defaultConfigJDK21() {
25-
assertFalse(Config.get().isDebuggerCodeOriginEnabled());
26-
assertFalse(InstrumenterConfig.get().isCodeOriginEnabled());
25+
assertTrue(Config.get().isDebuggerCodeOriginEnabled());
26+
assertTrue(InstrumenterConfig.get().isCodeOriginEnabled());
2727
}
2828

2929
@EnabledOnJre(JRE.JAVA_17)

dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/Bug4304Instrumentation.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@
1616
import datadog.trace.api.gateway.RequestContext;
1717
import datadog.trace.api.gateway.RequestContextSlot;
1818
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
19+
import de.thetaphi.forbiddenapis.SuppressForbidden;
1920
import java.lang.reflect.Field;
2021
import java.util.regex.Pattern;
2122
import net.bytebuddy.asm.Advice;
2223
import net.bytebuddy.description.type.TypeDescription;
2324
import net.bytebuddy.matcher.ElementMatcher;
2425

25-
/** See https://github.com/akka/akka-http/issues/4304 */
26+
/**
27+
* See <a href="https://github.com/akka/akka-http/issues/4304">Duplicated 100 responses if there is
28+
* an exception thrown by the unmarshaller</a>
29+
*/
2630
@AutoService(InstrumenterModule.class)
2731
public class Bug4304Instrumentation extends InstrumenterModule.AppSec
2832
implements Instrumenter.ForTypeHierarchy,
@@ -91,6 +95,11 @@ public void methodAdvice(MethodTransformer transformer) {
9195
}
9296

9397
static class GraphStageLogicAdvice {
98+
// Field::set() is forbidden because it may be used to mutate final fields, disallowed by
99+
// https://openjdk.org/jeps/500.
100+
// However, in this case the method is called on a non-final field, so it is safe. See
101+
// https://github.com/akka/akka-http/blob/8fb19fce3548c3bfa1e8ebcb1115be29f342df69/akka-http-core/src/main/scala/akka/http/impl/engine/server/HttpServerBluePrint.scala#L588
102+
@SuppressForbidden
94103
@Advice.OnMethodExit(suppress = Throwable.class)
95104
static void after(@Advice.This GraphStageLogic thiz)
96105
throws NoSuchFieldException, IllegalAccessException {
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
apply from: "$rootDir/gradle/java.gradle"
2+
3+
// Configuration for downloading CICS SDK from IBM
4+
ext {
5+
cicsVersion = '9.1'
6+
cicsSdkName = 'CICS_TG_SDK_91_Unix'
7+
}
8+
9+
repositories {
10+
ivy {
11+
url = 'https://public.dhe.ibm.com/software/htp/cics/support/supportpacs/individual/'
12+
patternLayout {
13+
artifact '[module].[ext]'
14+
}
15+
metadataSources {
16+
it.artifact()
17+
}
18+
}
19+
}
20+
21+
configurations {
22+
register('cicsSdk') {
23+
canBeResolved = true
24+
canBeConsumed = false
25+
}
26+
register('cicsJars') {
27+
canBeResolved = true
28+
canBeConsumed = false
29+
}
30+
}
31+
32+
// Task to extract the CICS SDK and get the required JARs
33+
abstract class ExtractCicsJars extends DefaultTask {
34+
@InputFiles
35+
final ConfigurableFileCollection sdkArchive = project.objects.fileCollection()
36+
37+
@OutputDirectory
38+
final DirectoryProperty outputDir = project.objects.directoryProperty()
39+
40+
ExtractCicsJars() {
41+
outputDir.convention(project.layout.buildDirectory.dir('cics-jars'))
42+
}
43+
44+
@TaskAction
45+
def extract() {
46+
def sdkFile = sdkArchive.singleFile
47+
def buildDir = outputDir.get().asFile
48+
buildDir.mkdirs()
49+
50+
// Extract outer tar.gz to get the inner tar.gz
51+
def tempDir = new File(buildDir, 'temp')
52+
tempDir.mkdirs()
53+
54+
project.copy {
55+
from project.tarTree(sdkFile)
56+
into tempDir
57+
}
58+
59+
// Find and extract the multiplatforms SDK
60+
def multiplatformsSdk = new File(tempDir, 'CICS_TG_SDK_91_Multiplatforms.tar.gz')
61+
if (!multiplatformsSdk.exists()) {
62+
throw new GradleException("Could not find CICS_TG_SDK_91_Multiplatforms.tar.gz in extracted archive")
63+
}
64+
65+
def sdkDir = new File(tempDir, 'sdk')
66+
sdkDir.mkdirs()
67+
68+
project.copy {
69+
from project.tarTree(multiplatformsSdk)
70+
into sdkDir
71+
}
72+
73+
// Extract cicseci.rar to get cicseci.jar, ctgclient.jar, and ctgserver.jar
74+
def cicsEciRar = new File(sdkDir, 'cicstgsdk/api/jee/runtime/managed/cicseci.rar')
75+
if (!cicsEciRar.exists()) {
76+
throw new GradleException("Could not find cicseci.rar at expected location")
77+
}
78+
79+
project.copy {
80+
from project.zipTree(cicsEciRar)
81+
into buildDir
82+
include 'cicseci.jar'
83+
include 'ctgclient.jar'
84+
include 'ctgserver.jar'
85+
}
86+
87+
// Copy cicsjee.jar
88+
def cicsJeeJar = new File(sdkDir, 'cicstgsdk/api/jee/runtime/nonmanaged/cicsjee.jar')
89+
if (!cicsJeeJar.exists()) {
90+
throw new GradleException("Could not find cicsjee.jar at expected location")
91+
}
92+
93+
project.copy {
94+
from cicsJeeJar
95+
into buildDir
96+
}
97+
98+
// Clean up temp directory
99+
tempDir.deleteDir()
100+
101+
logger.lifecycle("Extracted CICS JARs to: ${buildDir.absolutePath}")
102+
}
103+
}
104+
105+
tasks.register('extractCicsJars', ExtractCicsJars) {
106+
sdkArchive.from(configurations.named('cicsSdk'))
107+
108+
// Only extract if the output directory doesn't exist or SDK configuration changed
109+
outputs.upToDateWhen {
110+
def outputDir = it.outputDir.get().asFile
111+
outputDir.exists() &&
112+
new File(outputDir, 'cicseci.jar').exists() &&
113+
new File(outputDir, 'ctgclient.jar').exists() &&
114+
new File(outputDir, 'ctgserver.jar').exists() &&
115+
new File(outputDir, 'cicsjee.jar').exists()
116+
}
117+
}
118+
119+
dependencies {
120+
// Download the CICS SDK from IBM
121+
cicsSdk "${cicsSdkName}:${cicsSdkName}:@tar.gz"
122+
123+
// Compile-time dependencies (eliminates reflection)
124+
compileOnly group: 'javax.resource', name: 'javax.resource-api', version: '1.7.1'
125+
compileOnly files(tasks.named('extractCicsJars').map { task ->
126+
project.fileTree(task.outputDir) {
127+
include 'cicseci.jar'
128+
}
129+
})
130+
131+
// Test dependencies
132+
testImplementation group: 'javax.resource', name: 'javax.resource-api', version: '1.7.1'
133+
testImplementation libs.bundles.mockito
134+
testImplementation files(tasks.named('extractCicsJars').map { task ->
135+
project.fileTree(task.outputDir) {
136+
include '*.jar'
137+
}
138+
})
139+
}
140+
141+
// Ensure extraction happens before compilation
142+
tasks.named('compileJava') {
143+
dependsOn 'extractCicsJars'
144+
}
145+
146+
tasks.named('compileTestGroovy') {
147+
dependsOn 'extractCicsJars'
148+
}
149+
150+
tasks.named('forbiddenApisMain').configure {
151+
failOnMissingClasses = false
152+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package datadog.trace.instrumentation.cics;
2+
3+
import com.ibm.connector2.cics.ECIInteractionSpec;
4+
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
5+
import datadog.trace.bootstrap.instrumentation.api.InternalSpanTypes;
6+
import datadog.trace.bootstrap.instrumentation.api.Tags;
7+
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
8+
import datadog.trace.bootstrap.instrumentation.decorator.ClientDecorator;
9+
import java.net.InetAddress;
10+
11+
public class CicsDecorator extends ClientDecorator {
12+
public static final CharSequence CICS_CLIENT = UTF8BytesString.create("cics-client");
13+
public static final CharSequence ECI_EXECUTE_OPERATION = UTF8BytesString.create("cics.execute");
14+
public static final CharSequence GATEWAY_FLOW_OPERATION = UTF8BytesString.create("gateway.flow");
15+
16+
public static final CicsDecorator DECORATE = new CicsDecorator();
17+
18+
@Override
19+
protected String[] instrumentationNames() {
20+
return new String[] {"cics"};
21+
}
22+
23+
@Override
24+
protected String service() {
25+
return null; // Use default service name
26+
}
27+
28+
@Override
29+
protected CharSequence component() {
30+
return CICS_CLIENT;
31+
}
32+
33+
@Override
34+
protected CharSequence spanType() {
35+
return InternalSpanTypes.RPC;
36+
}
37+
38+
@Override
39+
public AgentSpan afterStart(AgentSpan span) {
40+
assert span != null;
41+
span.setTag("rpc.system", "cics");
42+
return super.afterStart(span);
43+
}
44+
45+
/**
46+
* Adds connection details to a span from JavaGatewayInterface fields.
47+
*
48+
* @param span the span to decorate
49+
* @param strAddress the hostname/address string
50+
* @param port the port number
51+
* @param ipGateway the resolved InetAddress (can be null)
52+
*/
53+
public AgentSpan onConnection(
54+
final AgentSpan span, final String strAddress, final int port, final InetAddress ipGateway) {
55+
if (strAddress != null) {
56+
span.setTag(Tags.PEER_HOSTNAME, strAddress);
57+
}
58+
59+
if (ipGateway != null) {
60+
onPeerConnection(span, ipGateway, false);
61+
}
62+
63+
if (port > 0) {
64+
setPeerPort(span, port);
65+
}
66+
67+
return span;
68+
}
69+
70+
/**
71+
* Converts ECI interaction verb code to string representation.
72+
*
73+
* @param verb the interaction verb code
74+
* @return string representation of the verb
75+
* @see <a
76+
* href="https://docs.oracle.com/javaee/6/api/constant-values.html#javax.resource.cci.InteractionSpec.SYNC_SEND">InteractionSpec
77+
* constants</a>
78+
*/
79+
private String getInteractionVerbString(final int verb) {
80+
switch (verb) {
81+
case 0:
82+
return "SYNC_SEND";
83+
case 1:
84+
return "SYNC_SEND_RECEIVE";
85+
case 2:
86+
return "SYNC_RECEIVE";
87+
default:
88+
return "UNKNOWN_" + verb;
89+
}
90+
}
91+
92+
public AgentSpan onECIInteraction(final AgentSpan span, final ECIInteractionSpec spec) {
93+
final String interactionVerb = getInteractionVerbString(spec.getInteractionVerb());
94+
final String functionName = spec.getFunctionName();
95+
final String tranName = spec.getTranName();
96+
final String tpnName = spec.getTPNName();
97+
98+
span.setResourceName(interactionVerb + " " + functionName);
99+
span.setTag("cics.interaction", interactionVerb);
100+
101+
if (functionName != null) {
102+
span.setTag("rpc.method", functionName);
103+
}
104+
if (tranName != null) {
105+
span.setTag("cics.tran", tranName);
106+
}
107+
if (tpnName != null) {
108+
span.setTag("cics.tpn", tpnName);
109+
}
110+
111+
return span;
112+
}
113+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package datadog.trace.instrumentation.cics;
2+
3+
import static java.util.Arrays.asList;
4+
5+
import com.google.auto.service.AutoService;
6+
import datadog.trace.agent.tooling.Instrumenter;
7+
import datadog.trace.agent.tooling.InstrumenterModule;
8+
import java.util.List;
9+
10+
@AutoService(InstrumenterModule.class)
11+
public class CicsModule extends InstrumenterModule.Tracing {
12+
public CicsModule() {
13+
super("cics");
14+
}
15+
16+
@Override
17+
public String[] helperClassNames() {
18+
return new String[] {packageName + ".CicsDecorator"};
19+
}
20+
21+
@Override
22+
public List<Instrumenter> typeInstrumentations() {
23+
return asList(new ECIInteractionInstrumentation(), new JavaGatewayInterfaceInstrumentation());
24+
}
25+
}

0 commit comments

Comments
 (0)