Skip to content
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

Extract AWS payload tags #7811

Merged
merged 66 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
5e19b41
AWS Payload observability PoC
ygree Jul 3, 2024
ff8cdc7
Exclude json-smart transitive dependency by implementing JsonProvider…
ygree Jul 12, 2024
c74f6df
Pass tagPrefix as a param
ygree Sep 5, 2024
87e8ced
Fix code quality violations
ygree Sep 6, 2024
61840ca
Exclude jsonpath's transitive dependency to avoid conflicts with the …
ygree Sep 6, 2024
60bb6d8
Exclude MoshiMappingProvider from coverage check
ygree Sep 6, 2024
cea1c4a
Fix native image build for excluded net.minidev
ygree Sep 6, 2024
1a0a8a6
Reduce unnecessary String allocation while traversing JSON for tag ex…
ygree Sep 9, 2024
1301ada
Introduce TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING & TRACE_CLOUD_RESPONSE_…
ygree Sep 10, 2024
6cb69c6
Remove JsonPath defaults that didn't fix native build issue
ygree Sep 11, 2024
8acaf53
Replace Json Tag Extraction implementation. Migrate from jayway.jsonp…
ygree Sep 12, 2024
75a38b5
Completely rewrite Json payload tag extraction.
ygree Sep 24, 2024
6d4f0d9
Separate JsonTagsCollector and JsonStreamTraversal
ygree Sep 25, 2024
eb2b5be
Add more test for Json tag extractor functionality
ygree Sep 26, 2024
1ec0515
Minor clean up and code improvements
ygree Sep 26, 2024
76d9187
Renaming. Split copy and match logic among JsonPath Segment classes.
ygree Sep 26, 2024
7e413d8
More renaming
ygree Sep 26, 2024
84b04e2
Separate JsonPointer from JsonPath
ygree Sep 27, 2024
bf8460a
Introduce config settings TRACE_CLOUD_PAYLOAD_TAGGING_MAX_DEPTH and T…
ygree Sep 27, 2024
d5c7a2c
Clean up visitor naming and logic
ygree Sep 27, 2024
8f59128
More clean up
ygree Sep 27, 2024
a13e2f6
Merge branch 'master' into ygree/aws-payload-tagging
ygree Sep 27, 2024
ee673c2
Use Okio Buffers for AWS SDK response capturing
ygree Oct 1, 2024
0aef3d1
Add some default (AWD SNS only) redaction rules
ygree Oct 1, 2024
49d4937
Merge branch 'master' into ygree/aws-payload-tagging
ygree Oct 1, 2024
20b733b
Revert "Use Okio Buffers for AWS SDK response capturing"
ygree Oct 1, 2024
e1cca99
Improve ResponseBodyStreamWrapper by avoid copying buffer data for co…
ygree Oct 1, 2024
92f6be5
Merge branch 'master' into ygree/aws-payload-tagging
ygree Oct 1, 2024
bdfbb0f
Fix muzzle issue. Add buffering limit
ygree Oct 1, 2024
15a3056
Do not parse payload if it doesn't start with '{' or '['
ygree Oct 1, 2024
0066ca1
Enable payload tagging only for AWS ApiGateway, EventBridge, Sqs, Sns…
ygree Oct 3, 2024
ac3f316
Add PayloadTaggingTest
ygree Oct 3, 2024
44155cb
Merge branch 'master' into ygree/aws-payload-tagging
ygree Oct 3, 2024
61a45cd
Remove debug statement for disabled services
ygree Oct 3, 2024
7d4607d
Move payloadTaggingTest into a separate module to avoid dependency co…
ygree Oct 4, 2024
8358c9a
Merge branch 'master' into ygree/aws-payload-tagging
ygree Oct 4, 2024
e992726
Add RedactionRulesExtractor. Add generated default redaction rules.
ygree Oct 5, 2024
3105869
Merge branch 'master' into ygree/aws-payload-tagging
ygree Oct 15, 2024
b3785d5
Remove unnecessary dependsOn "payloadTaggingTest" because :instrument…
ygree Oct 17, 2024
317f2fb
[WIP] Rework AWS SDK payload tagging to two-stage processing by trave…
ygree Oct 18, 2024
3f9630d
Merge branch 'master' into ygree/aws-payload-tagging-2
ygree Oct 28, 2024
4df20c4
Fix muzzle check
ygree Oct 28, 2024
7aca81d
Add proper PayloadTaggingTest for all supported types of services
ygree Oct 29, 2024
ccf4a40
Add PayloadTagsProcessor only if enabled.
ygree Oct 29, 2024
edd76fe
Rework PathCursor
ygree Oct 30, 2024
c137fff
Add PayloadTagsProcessor test
ygree Oct 30, 2024
4ebcd26
Improve error reporting. Add some comments
ygree Oct 30, 2024
d6fb7ba
JSON parsing. Add comments, some tests, renaming, and TODOs.
ygree Oct 30, 2024
390e7f1
Split PathCursor to two PathAndValue and PathCursor
ygree Oct 30, 2024
d7306eb
Split PathCursor to two PathAndValue and PathCursor
ygree Oct 30, 2024
681b6df
Clean up JsonStreamParser visitor interface
ygree Oct 30, 2024
cff78f3
JsonStreamParser separate visitor method for each supported primitive…
ygree Oct 30, 2024
a4279a2
Proper integration tests for pre-processor tag collection in collectP…
ygree Oct 31, 2024
98f2d3f
Add proper max-depth control. Add PayloadTaggingMaxDepthForkedTest.
ygree Oct 31, 2024
83b0cac
Add proper max-depth control. Add PayloadTaggingMaxDepthForkedTest.
ygree Nov 1, 2024
20026c0
Limit number of payload tags by setting
ygree Nov 1, 2024
6cc930d
Remove duplications in collectPayloadTags by using a JsonStreamParser…
ygree Nov 1, 2024
63fafdf
Clean up PayloadTagsData to bare minimum that doesn't need a separate…
ygree Nov 1, 2024
4f6b406
Clean up PayloadTaggingTest
ygree Nov 1, 2024
a4e52ad
PayloadTagsProcessorTest
ygree Nov 1, 2024
6679d8c
Merge branch 'master' into ygree/aws-payload-tagging-2
ygree Nov 1, 2024
049b008
Trying to fix s3 localstack payload tagging test failing on CI.
ygree Nov 1, 2024
79ea353
Merge branch 'master' into ygree/aws-payload-tagging-2
ygree Nov 1, 2024
cc6fcb6
Exclude io.lettuce-lettuce-core-6.5.0.RELEASE from muzzle check
ygree Nov 1, 2024
81937db
Merge branch 'master' into ygree/aws-payload-tagging-2
ygree Nov 1, 2024
b49f9a4
Minor clean up
ygree Nov 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions dd-java-agent/instrumentation/aws-java-sdk-2.2/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ addTestSuiteExtendingForDir('dsmForkedTest', 'dsmTest', 'dsmTest')
addTestSuiteForDir('latestDsmTest', 'dsmTest')
addTestSuiteExtendingForDir('latestDsmForkedTest', 'latestDsmTest', 'dsmTest')

addTestSuite('payloadTaggingTest')
addTestSuiteExtendingForDir('payloadTaggingForkedTest', 'payloadTaggingTest', 'payloadTaggingTest')
addTestSuiteForDir('latestPayloadTaggingTest', 'payloadTaggingTest')
addTestSuiteExtendingForDir('latestPayloadTaggingForkedTest', 'latestPayloadTaggingTest', 'payloadTaggingTest')

def fixedSdkVersion = '2.20.33' // 2.20.34 is missing and breaks IDEA import

dependencies {
Expand All @@ -40,6 +45,8 @@ dependencies {
testImplementation group: 'org.eclipse.jetty.http2', name: 'http2-server', version: '9.4.56.v20240826'


testImplementation group: 'org.testcontainers', name: 'localstack', version: libs.versions.testcontainers.get()

// First version where dsm traced operations have required StreamARN parameter for kinesis
// and publishBatch is available for SNS
dsmTestImplementation group: 'software.amazon.awssdk', name: 'apache-client', version: '2.18.40'
Expand All @@ -49,10 +56,25 @@ dependencies {
latestDsmTestImplementation group: 'software.amazon.awssdk', name: 'kinesis', version: '+'
latestDsmTestImplementation group: 'software.amazon.awssdk', name: 'sns', version: '+'

payloadTaggingTestImplementation group: 'software.amazon.awssdk', name: 'apigateway', version: '2.19.0'
payloadTaggingTestImplementation group: 'software.amazon.awssdk', name: 'eventbridge', version: '2.7.4'
payloadTaggingTestImplementation group: 'software.amazon.awssdk', name: 'sqs', version: '2.18.40'
payloadTaggingTestImplementation group: 'software.amazon.awssdk', name: 'sns', version: '2.18.40'
payloadTaggingTestImplementation group: 'software.amazon.awssdk', name: 's3', version: '2.18.40'
payloadTaggingTestImplementation group: 'software.amazon.awssdk', name: 'kinesis', version: '2.18.40'
latestPayloadTaggingTestImplementation group: 'software.amazon.awssdk', name: 'apigateway', version: '2.25.40'
latestPayloadTaggingTestImplementation group: 'software.amazon.awssdk', name: 'eventbridge', version: '2.25.40'
latestPayloadTaggingTestImplementation group: 'software.amazon.awssdk', name: 'sqs', version: '2.25.40'
latestPayloadTaggingTestImplementation group: 'software.amazon.awssdk', name: 'sns', version: '2.25.40'
latestPayloadTaggingTestImplementation group: 'software.amazon.awssdk', name: 's3', version: '2.18.40'
latestPayloadTaggingTestImplementation group: 'software.amazon.awssdk', name: 'kinesis', version: '2.18.40'

latestDepTestImplementation project(':dd-java-agent:instrumentation:apache-httpclient-4')
latestDepTestImplementation project(':dd-java-agent:instrumentation:netty-4.1')

latestDepTestImplementation group: 'software.amazon.awssdk', name: 'apache-client', version: fixedSdkVersion
latestDepTestImplementation group: 'software.amazon.awssdk', name: 'apigateway', version: fixedSdkVersion
latestDepTestImplementation group: 'software.amazon.awssdk', name: 'eventbridge', version: fixedSdkVersion
latestDepTestImplementation group: 'software.amazon.awssdk', name: 's3', version: fixedSdkVersion
latestDepTestImplementation group: 'software.amazon.awssdk', name: 'rds', version: fixedSdkVersion
latestDepTestImplementation group: 'software.amazon.awssdk', name: 'ec2', version: fixedSdkVersion
Expand All @@ -61,3 +83,7 @@ dependencies {
latestDepTestImplementation group: 'software.amazon.awssdk', name: 'dynamodb', version: fixedSdkVersion
latestDepTestImplementation group: 'software.amazon.awssdk', name: 'kinesis', version: fixedSdkVersion
}

tasks.withType(Test).configureEach {
usesService(testcontainersLimit)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static datadog.trace.core.datastreams.TagsProcessor.TYPE_TAG;

import datadog.trace.api.Config;
import datadog.trace.api.ConfigDefaults;
import datadog.trace.api.DDTags;
import datadog.trace.api.cache.DDCache;
import datadog.trace.api.cache.DDCaches;
Expand All @@ -23,16 +24,22 @@
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
import datadog.trace.bootstrap.instrumentation.decorator.HttpClientDecorator;
import datadog.trace.core.datastreams.TagsProcessor;
import datadog.trace.payloadtags.PayloadTagsData;
import java.net.URI;
import java.time.Instant;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nonnull;
import software.amazon.awssdk.awscore.AwsResponse;
import software.amazon.awssdk.core.SdkBytes;
import software.amazon.awssdk.core.SdkField;
import software.amazon.awssdk.core.SdkPojo;
import software.amazon.awssdk.core.SdkRequest;
Expand Down Expand Up @@ -115,6 +122,12 @@ public AgentSpan onSdkRequest(
final String awsOperationName = attributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME);
onOperation(span, awsServiceName, awsOperationName);

Config config = Config.get();
if (config.isCloudRequestPayloadTaggingEnabled()
&& config.isCloudPayloadTaggingEnabledFor(awsServiceName)) {
awsPojoToTags(span, ConfigDefaults.DEFAULT_TRACE_CLOUD_PAYLOAD_REQUEST_TAG, request);
}

// S3
request.getValueForField("Bucket", String.class).ifPresent(name -> setBucketName(span, name));
if ("s3".equalsIgnoreCase(awsServiceName) && span.traceConfig().isDataStreamsEnabled()) {
Expand Down Expand Up @@ -295,6 +308,14 @@ public AgentSpan onSdkResponse(
final SdkResponse response,
final SdkHttpResponse httpResponse,
final ExecutionAttributes attributes) {

Config config = Config.get();
String serviceName = attributes.getAttribute(SdkExecutionAttribute.SERVICE_NAME);
if (config.isCloudResponsePayloadTaggingEnabled()
&& config.isCloudPayloadTaggingEnabledFor(serviceName)) {
awsPojoToTags(span, ConfigDefaults.DEFAULT_TRACE_CLOUD_PAYLOAD_RESPONSE_TAG, response);
}

if (response instanceof AwsResponse) {
span.setTag(
InstrumentationTags.AWS_REQUEST_ID,
Expand Down Expand Up @@ -437,4 +458,48 @@ protected String getRequestHeader(SdkHttpRequest request, String headerName) {
protected String getResponseHeader(SdkHttpResponse response, String headerName) {
return response.firstMatchingHeader(headerName).orElse(null);
}

private void awsPojoToTags(AgentSpan span, String tagsPrefix, Object pojo) {
Collection<PayloadTagsData.PathAndValue> payloadTagsData = new ArrayList<>();
ArrayDeque<Object> path = new ArrayDeque<>();
collectPayloadTagsData(payloadTagsData, path, pojo);
span.setTag(
tagsPrefix,
new PayloadTagsData(payloadTagsData.toArray(new PayloadTagsData.PathAndValue[0])));
}

private void collectPayloadTagsData(
Collection<PayloadTagsData.PathAndValue> payloadTagsData,
ArrayDeque<Object> path,
Object object) {
if (object instanceof SdkPojo) {
SdkPojo pojo = (SdkPojo) object;
for (SdkField<?> field : pojo.sdkFields()) {
Object val = field.getValueOrDefault(pojo);
path.push(field.locationName());
collectPayloadTagsData(payloadTagsData, path, val);
path.pop();
}
} else if (object instanceof Collection) {
int index = 0;
for (Object value : (Collection<?>) object) {
path.push(index);
collectPayloadTagsData(payloadTagsData, path, value);
path.pop();
index++;
}
} else if (object instanceof Map) {
Map<?, ?> map = (Map<?, ?>) object;
for (Map.Entry<?, ?> entry : map.entrySet()) {
path.push(entry.getKey().toString());
collectPayloadTagsData(payloadTagsData, path, entry.getValue());
path.pop();
}
} else if (object instanceof SdkBytes) {
SdkBytes bytes = (SdkBytes) object;
payloadTagsData.add(new PayloadTagsData.PathAndValue(path.toArray(), bytes.asInputStream()));
} else {
payloadTagsData.add(new PayloadTagsData.PathAndValue(path.toArray(), object));
}
}
}
Loading