Skip to content

Commit 036e210

Browse files
committed
Merge with master
2 parents b19e7ef + b24d153 commit 036e210

File tree

269 files changed

+5527
-3507
lines changed

Some content is hidden

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

269 files changed

+5527
-3507
lines changed

.circleci/config.continue.yml.j2

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ instrumentation_modules: &instrumentation_modules "dd-java-agent/instrumentation
3636
debugger_modules: &debugger_modules "dd-java-agent/agent-debugger|dd-java-agent/agent-bootstrap|dd-java-agent/agent-builder|internal-api|communication|dd-trace-core"
3737
profiling_modules: &profiling_modules "dd-java-agent/agent-profiling"
3838

39-
default_system_tests_commit: &default_system_tests_commit 2cb5033072c1813eccdce332153a378607e73d85
39+
default_system_tests_commit: &default_system_tests_commit c706e333ef06800b866ac300e4b6cdb7566cc5e5
4040

4141
parameters:
4242
nightly:

.github/workflows/update-docker-build-image.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
tag:
1010
description: 'The tag to use for the Docker build image'
1111
required: true
12-
default: 'vYY.MM-base'
12+
default: 'vYY.MM'
1313

1414
jobs:
1515
update-docker-build-image:
@@ -46,7 +46,7 @@ jobs:
4646
08|09|10) TAG_DATE="${CURRENT_YEAR}.07" ;;
4747
11|12) TAG_DATE="${CURRENT_YEAR}.10" ;;
4848
esac
49-
TAG="v${TAG_DATE}-base"
49+
TAG="v${TAG_DATE}"
5050
fi
5151
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
5252
echo "::notice::Using Docker build image tag: ${TAG}"
@@ -55,7 +55,7 @@ jobs:
5555
sed -i 's|DOCKER_IMAGE_VERSION=.*|DOCKER_IMAGE_VERSION="${{ steps.define-tag.outputs.tag }}"|' .circleci/render_config.py
5656
- name: Update the Docker build image in GitLab CI config
5757
run: |
58-
sed -i 's|image: ghcr.io/datadog/dd-trace-java-docker-build:.*|image: ghcr.io/datadog/dd-trace-java-docker-build:${{ steps.define-tag.outputs.tag }}|' .gitlab-ci.yml
58+
sed -i 's|image: ghcr.io/datadog/dd-trace-java-docker-build:.*|image: ghcr.io/datadog/dd-trace-java-docker-build:${{ steps.define-tag.outputs.tag }}-base|' .gitlab-ci.yml
5959
- name: Commit and push changes
6060
env:
6161
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

.gitlab-ci.yml

+33-22
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,34 @@ stages:
2020
variables:
2121
REGISTRY: 486234852809.dkr.ecr.us-east-1.amazonaws.com
2222
BUILD_JOB_NAME: "build"
23+
DEPENDENCY_CACHE_POLICY: pull
24+
BUILD_CACHE_POLICY: pull
25+
GRADLE_VERSION: "8.4" # must match gradle-wrapper.properties
2326

24-
.common: &common
25-
tags: [ "runner:main", "size:large" ]
27+
default:
28+
tags: [ "arch:amd64" ]
2629

2730
.gradle_build: &gradle_build
28-
<<: *common
29-
image: ghcr.io/datadog/dd-trace-java-docker-build:v23.10-base
31+
image: ghcr.io/datadog/dd-trace-java-docker-build:v24.10-base
3032
variables:
3133
GRADLE_OPTS: "-Dorg.gradle.jvmargs='-Xmx2560M -Xms2560M'"
32-
GRADLE_ARGS: " -PskipTests --build-cache --stacktrace --no-daemon --parallel --max-workers=8"
34+
GRADLE_ARGS: " -PskipTests --build-cache --stacktrace --no-daemon --parallel --max-workers=2"
3335
KUBERNETES_CPU_REQUEST: 8
34-
KUBERNETES_MEMORY_REQUEST: 4Gi
35-
cache: &default_cache
36-
key: '$CI_SERVER_VERSION' # Reset the cache every time gitlab is upgraded. ~Every couple months
37-
paths:
38-
- .gradle/wrapper
39-
- .gradle/caches
40-
policy: pull
36+
KUBERNETES_MEMORY_REQUEST: 6Gi
37+
cache:
38+
- key: '$CI_SERVER_VERSION-v2' # Dependencies cache. Reset the cache every time gitlab is upgraded. ~Every couple months
39+
paths:
40+
# Cached dependencies and wrappers for gradle
41+
- .gradle/wrapper
42+
- .gradle/caches
43+
- .gradle/notifications
44+
policy: $DEPENDENCY_CACHE_POLICY
45+
- key: $CI_PIPELINE_ID # Incremental build cache. Shared by all jobs in the pipeline
46+
paths:
47+
- .gradle/caches/$GRADLE_VERSION
48+
- .gradle/$GRADLE_VERSION/executionHistory
49+
- workspace
50+
policy: $BUILD_CACHE_POLICY
4151
before_script:
4252
- export GRADLE_USER_HOME=`pwd`/.gradle
4353
# for weird reasons, gradle will always "chmod 700" the .gradle folder
@@ -49,9 +59,12 @@ variables:
4959
- mv .gradle-copy .gradle
5060
- ls -la
5161

52-
build: &build
53-
<<: *gradle_build
62+
build:
63+
extends: .gradle_build
5464
stage: build
65+
variables:
66+
BUILD_CACHE_POLICY: push
67+
DEPENDENCY_CACHE_POLICY: pull
5568
script:
5669
- ./gradlew clean :dd-java-agent:shadowJar :dd-trace-api:jar :dd-trace-ot:shadowJar $GRADLE_ARGS
5770
- echo UPSTREAM_TRACER_VERSION=$(java -jar workspace/dd-java-agent/build/libs/*.jar) >> upstream.env
@@ -66,16 +79,16 @@ build: &build
6679
reports:
6780
dotenv: build.env
6881

69-
build_with_cache:
70-
<<: *build
82+
build_and_populate_dep_cache:
83+
extends: build
84+
variables:
85+
BUILD_CACHE_POLICY: push
86+
DEPENDENCY_CACHE_POLICY: push
7187
rules:
7288
- if: '$POPULATE_CACHE'
7389
when: on_success
7490
- when: manual
7591
allow_failure: true
76-
cache:
77-
<<: *default_cache
78-
policy: push
7992

8093
deploy_to_profiling_backend:
8194
stage: publish
@@ -149,7 +162,7 @@ deploy_to_di_backend:manual:
149162
UPSTREAM_COMMIT_SHORT_SHA: $CI_COMMIT_SHORT_SHA
150163

151164
deploy_to_sonatype:
152-
<<: *gradle_build
165+
extends: .gradle_build
153166
stage: publish
154167
needs: [ build ]
155168
rules:
@@ -177,7 +190,6 @@ deploy_to_sonatype:
177190
deploy_artifacts_to_github:
178191
stage: publish
179192
image: registry.ddbuild.io/github-cli:v27480869-eafb11d-2.43.0
180-
tags: [ "arch:amd64" ]
181193
rules:
182194
- if: '$POPULATE_CACHE'
183195
when: never
@@ -234,7 +246,6 @@ create_key:
234246
stage: generate-signing-key
235247
when: manual
236248
needs: [ ]
237-
tags: [ "arch:amd64", "size:large" ]
238249
variables:
239250
PROJECT_NAME: "dd-trace-java"
240251
EXPORT_TO_KEYSERVER: "true"

communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java

+9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import datadog.remoteconfig.DefaultConfigurationPoller;
1212
import datadog.trace.api.Config;
1313
import datadog.trace.util.AgentTaskScheduler;
14+
import java.security.Security;
1415
import java.util.ArrayList;
1516
import java.util.List;
1617
import java.util.concurrent.TimeUnit;
@@ -59,6 +60,7 @@ public void createRemaining(Config config) {
5960
}
6061
}
6162

63+
/** Registers a callback to be called when remote communications resume. */
6264
public void whenReady(Runnable callback) {
6365
if (paused) {
6466
synchronized (pausedComponents) {
@@ -71,8 +73,15 @@ public void whenReady(Runnable callback) {
7173
callback.run(); // not paused, run immediately
7274
}
7375

76+
/** Resumes remote communications including any paused callbacks. */
7477
public void resume() {
7578
paused = false;
79+
// attempt discovery first to avoid potential race condition on IBM Java8
80+
if (null != featuresDiscovery) {
81+
featuresDiscovery.discoverIfOutdated();
82+
} else {
83+
Security.getProviders(); // fallback to preloading provider extensions
84+
}
7685
synchronized (pausedComponents) {
7786
for (Runnable callback : pausedComponents) {
7887
try {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
package datadog.context;
2+
3+
import static java.lang.Math.max;
4+
import static java.util.Arrays.copyOfRange;
5+
import static java.util.Objects.requireNonNull;
6+
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
import java.util.function.BinaryOperator;
10+
11+
/**
12+
* Static helpers to manipulate context collections.
13+
*
14+
* <p>Typical usages include:
15+
*
16+
* <pre>{@code
17+
* // Finding a context value from multiple sources:
18+
* Span span = findFirst(spanKey, message, request, CURRENT)
19+
* // Find all context values from different sources:
20+
* List<Error> errors = findAll(errorKey, message, request, CURRENT)
21+
* // Capture multiple contexts in a single one:
22+
* Context aggregate = combine(message, request, CURRENT)
23+
* // Combine multiple contexts into a single one using custom merge rules:
24+
* Context combined = combine(
25+
* (current, next) -> {
26+
* var metric = current.get(metricKey);
27+
* var nextMetric = next.get(metricKey);
28+
* return current.with(metricKey, metric.add(nextMetric));
29+
* }, message, request, CURRENT);
30+
* }</pre>
31+
*
32+
* where {@link #CURRENT} denotes a carrier with the current context.
33+
*/
34+
public final class ContextHelpers {
35+
/** A helper object carrying the {@link Context#current()} context. */
36+
public static final Object CURRENT = new Object();
37+
38+
private ContextHelpers() {}
39+
40+
/**
41+
* Find the first context value from given context carriers.
42+
*
43+
* @param key The key used to store the value.
44+
* @param carriers The carrier to get context and value from.
45+
* @param <T> The type of the value to look for.
46+
* @return The first context value found, {@code null} if not found.
47+
*/
48+
public static <T> T findFirst(ContextKey<T> key, Object... carriers) {
49+
requireNonNull(key, "key cannot be null");
50+
for (Object carrier : carriers) {
51+
requireNonNull(carrier, "carrier cannot be null");
52+
Context context = carrier == CURRENT ? Context.current() : Context.from(carrier);
53+
T value = context.get(key);
54+
if (value != null) {
55+
return value;
56+
}
57+
}
58+
return null;
59+
}
60+
61+
/**
62+
* Find all the context values from the given context carriers.
63+
*
64+
* @param key The key used to store the value.
65+
* @param carriers The carriers to get context and value from.
66+
* @param <T> The type of the values to look for.
67+
* @return A list of all values found, in context order.
68+
*/
69+
public static <T> List<T> findAll(ContextKey<T> key, Object... carriers) {
70+
requireNonNull(key, "key cannot be null");
71+
List<T> values = new ArrayList<>(carriers.length);
72+
for (Object carrier : carriers) {
73+
requireNonNull(carrier, "carrier cannot be null");
74+
Context context = carrier == CURRENT ? Context.current() : Context.from(carrier);
75+
T value = context.get(key);
76+
if (value != null) {
77+
values.add(value);
78+
}
79+
}
80+
return values;
81+
}
82+
83+
/**
84+
* Combine contexts and their values, keeping the first founds.
85+
*
86+
* @param contexts The contexts to combine.
87+
* @return A context containing all the values from all the given context, keeping the first value
88+
* found for a given key.
89+
*/
90+
public static Context combine(Context... contexts) {
91+
return combine(ContextHelpers::combineKeepingFirst, contexts);
92+
}
93+
94+
/**
95+
* Combine multiple contexts into a single one.
96+
*
97+
* @param combiner The context combiner, taking already combined context as first parameter, any
98+
* following one as second parameter, and returning the combined context.
99+
* @param contexts The contexts to combine.
100+
* @return The combined context.
101+
*/
102+
public static Context combine(BinaryOperator<Context> combiner, Context... contexts) {
103+
requireNonNull(combiner, "combiner cannot be null");
104+
Context result = new IndexedContext(new Object[0]);
105+
for (Context context : contexts) {
106+
requireNonNull(context, "context cannot be null");
107+
result = combiner.apply(result, context);
108+
}
109+
return result;
110+
}
111+
112+
private static Context combineKeepingFirst(Context current, Context next) {
113+
if (!(current instanceof IndexedContext)) {
114+
throw new IllegalStateException("Left context is supposed to be an IndexedContext");
115+
}
116+
IndexedContext currentIndexed = (IndexedContext) current;
117+
if (next instanceof EmptyContext) {
118+
return current;
119+
} else if (next instanceof SingletonContext) {
120+
SingletonContext nextSingleton = (SingletonContext) next;
121+
// Check if the single next value is already define in current so next context can be skipped
122+
if (nextSingleton.index < currentIndexed.store.length
123+
&& currentIndexed.store[nextSingleton.index] != null) {
124+
return current;
125+
}
126+
// Always store next value otherwise
127+
Object[] store =
128+
copyOfRange(
129+
currentIndexed.store, 0, max(currentIndexed.store.length, nextSingleton.index + 1));
130+
store[nextSingleton.index] = nextSingleton.value;
131+
return new IndexedContext(store);
132+
} else if (next instanceof IndexedContext) {
133+
IndexedContext nextIndexed = (IndexedContext) next;
134+
// Don't prematurely allocate store. Only allocate if:
135+
// * nextIndexed has more values that currentIndexed,
136+
// so the additional values will always be kept
137+
// * nextIndexed has values that currentIndexed do not have
138+
Object[] store = null;
139+
// Allocate store if nextIndexed has more elements than currentIndexed
140+
if (nextIndexed.store.length > currentIndexed.store.length) {
141+
store = copyOfRange(currentIndexed.store, 0, nextIndexed.store.length);
142+
}
143+
// Apply nextIndexed values if not set in currentIndexed
144+
for (int i = 0; i < currentIndexed.store.length; i++) {
145+
Object nextValue = nextIndexed.store[i];
146+
if (nextValue != null && currentIndexed.store[i] == null) {
147+
if (store == null) {
148+
store = copyOfRange(currentIndexed.store, 0, currentIndexed.store.length);
149+
}
150+
store[i] = nextValue;
151+
}
152+
}
153+
// Apply any additional values from nextIndexed if any
154+
for (int i = currentIndexed.store.length; i < nextIndexed.store.length; i++) {
155+
Object nextValue = nextIndexed.store[i];
156+
if (nextValue != null) {
157+
store[i] = nextValue;
158+
}
159+
}
160+
// If store was not allocated, no value from nextIndexed was taken
161+
return store == null ? current : new IndexedContext(store);
162+
}
163+
throw new IllegalStateException("Unsupported context type: " + next.getClass().getName());
164+
}
165+
}

components/context/src/main/java/datadog/context/EmptyContext.java

+5
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,9 @@ public <T> Context with(ContextKey<T> key, @Nullable T value) {
2424
}
2525
return new SingletonContext(key.index, value);
2626
}
27+
28+
@Override
29+
public String toString() {
30+
return "EmptyContext{}";
31+
}
2732
}

components/context/src/main/java/datadog/context/IndexedContext.java

+10-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
/** {@link Context} containing many values. */
1212
@ParametersAreNonnullByDefault
1313
final class IndexedContext implements Context {
14-
private final Object[] store;
14+
final Object[] store;
1515

1616
IndexedContext(Object[] store) {
1717
this.store = store;
@@ -23,14 +23,14 @@ final class IndexedContext implements Context {
2323
public <T> T get(ContextKey<T> key) {
2424
requireNonNull(key, "Context key cannot be null");
2525
int index = key.index;
26-
return index < store.length ? (T) store[index] : null;
26+
return index < this.store.length ? (T) this.store[index] : null;
2727
}
2828

2929
@Override
3030
public <T> Context with(ContextKey<T> key, @Nullable T value) {
3131
requireNonNull(key, "Context key cannot be null");
3232
int index = key.index;
33-
Object[] newStore = copyOfRange(store, 0, max(store.length, index + 1));
33+
Object[] newStore = copyOfRange(this.store, 0, max(this.store.length, index + 1));
3434
newStore[index] = value;
3535
return new IndexedContext(newStore);
3636
}
@@ -40,13 +40,18 @@ public boolean equals(Object o) {
4040
if (this == o) return true;
4141
if (o == null || getClass() != o.getClass()) return false;
4242
IndexedContext that = (IndexedContext) o;
43-
return Arrays.equals(store, that.store);
43+
return Arrays.equals(this.store, that.store);
4444
}
4545

4646
@Override
4747
public int hashCode() {
4848
int result = 31;
49-
result = 31 * result + Arrays.hashCode(store);
49+
result = 31 * result + Arrays.hashCode(this.store);
5050
return result;
5151
}
52+
53+
@Override
54+
public String toString() {
55+
return "IndexedContext{store=" + Arrays.toString(this.store) + '}';
56+
}
5257
}

0 commit comments

Comments
 (0)