@@ -265,7 +265,7 @@ index 00000000..dc5b7a01
265265+ }
266266+ }
267267diff --git a/aws-xray/src/main/java/io/opentelemetry/contrib/awsxray/AwsXrayRemoteSampler.java b/aws-xray/src/main/java/io/opentelemetry/contrib/awsxray/AwsXrayRemoteSampler.java
268- index ad9b72a2..b99d2a48 100644
268+ index ad9b72a2..7864f358 100644
269269--- a/aws-xray/src/main/java/io/opentelemetry/contrib/awsxray/AwsXrayRemoteSampler.java
270270+++ b/aws-xray/src/main/java/io/opentelemetry/contrib/awsxray/AwsXrayRemoteSampler.java
271271@@ -9,16 +9,22 @@ import io.opentelemetry.api.common.Attributes;
@@ -292,9 +292,9 @@ index ad9b72a2..b99d2a48 100644
292292 import java.util.Iterator;
293293 import java.util.List;
294294@@ -43,6 +49,9 @@ public final class AwsXrayRemoteSampler implements Sampler, Closeable {
295-
295+
296296 private static final Logger logger = Logger.getLogger(AwsXrayRemoteSampler.class.getName());
297-
297+
298298+ // Default batch size to be same as OTel BSP default
299299+ private static final int maxExportBatchSize = 512;
300300+
@@ -304,7 +304,7 @@ index ad9b72a2..b99d2a48 100644
304304@@ -59,6 +68,9 @@ public final class AwsXrayRemoteSampler implements Sampler, Closeable {
305305 @Nullable private volatile XrayRulesSampler internalXrayRulesSampler;
306306 private volatile Sampler sampler;
307-
307+
308308+ @Nullable private AwsXrayAdaptiveSamplingConfig adaptiveSamplingConfig;
309309+ @Nullable private BatchSpanProcessor bsp;
310310+
@@ -314,15 +314,15 @@ index ad9b72a2..b99d2a48 100644
314314@@ -120,6 +132,40 @@ public final class AwsXrayRemoteSampler implements Sampler, Closeable {
315315 return "AwsXrayRemoteSampler{" + sampler.getDescription() + "}";
316316 }
317-
317+
318318+ public void setAdaptiveSamplingConfig(AwsXrayAdaptiveSamplingConfig config) {
319319+ if (this.adaptiveSamplingConfig != null) {
320320+ throw new IllegalStateException("Programming bug - Adaptive sampling config is already set");
321321+ } else if (config != null && this.adaptiveSamplingConfig == null) {
322322+ // Save here and also pass to XrayRulesSampler directly as it already exists
323323+ this.adaptiveSamplingConfig = config;
324- + if (sampler instanceof XrayRulesSampler ) {
325- + ((XrayRulesSampler) sampler) .setAdaptiveSamplingConfig(config);
324+ + if (internalXrayRulesSampler != null ) {
325+ + internalXrayRulesSampler .setAdaptiveSamplingConfig(config);
326326+ }
327327+ }
328328+ }
@@ -344,8 +344,8 @@ index ad9b72a2..b99d2a48 100644
344344+ throw new IllegalStateException(
345345+ "Programming bug - BatchSpanProcessor is null while trying to adapt sampling");
346346+ }
347- + if (sampler instanceof XrayRulesSampler ) {
348- + ((XrayRulesSampler) sampler) .adaptSampling(span, spanData, this.bsp::onEnd);
347+ + if (internalXrayRulesSampler != null ) {
348+ + internalXrayRulesSampler .adaptSampling(span, spanData, this.bsp::onEnd);
349349+ }
350350+ }
351351+
@@ -388,7 +388,7 @@ index ad9b72a2..b99d2a48 100644
388388 statistics.stream()
389389 .map(SamplingStatisticsDocument::getRuleName)
390390 .collect(Collectors.toSet());
391-
391+
392392- GetSamplingTargetsResponse response =
393393- client.getSamplingTargets(GetSamplingTargetsRequest.create(statistics));
394394+ GetSamplingTargetsRequest req = GetSamplingTargetsRequest.create(statistics, boostStatistics);
@@ -418,11 +418,11 @@ index dca930d5..01835dc2 100644
418418+ version,
419419+ samplingRateBoost);
420420 }
421-
421+
422422 abstract Map<String, String> getAttributes();
423423@@ -106,5 +108,23 @@ abstract class GetSamplingRulesResponse {
424424 abstract String getUrlPath();
425-
425+
426426 abstract int getVersion();
427427+
428428+ @Nullable
@@ -451,19 +451,19 @@ index 7d1fb7b7..9404f73e 100644
451451@@ -15,14 +15,20 @@ import java.util.List;
452452 @JsonSerialize(as = GetSamplingTargetsRequest.class)
453453 abstract class GetSamplingTargetsRequest {
454-
454+
455455- static GetSamplingTargetsRequest create(List<SamplingStatisticsDocument> documents) {
456456- return new AutoValue_GetSamplingTargetsRequest(documents);
457457+ static GetSamplingTargetsRequest create(
458458+ List<SamplingStatisticsDocument> documents,
459459+ List<SamplingBoostStatisticsDocument> boostDocuments) {
460460+ return new AutoValue_GetSamplingTargetsRequest(documents, boostDocuments);
461461 }
462-
462+
463463 // Limit of 25 items
464464 @JsonProperty("SamplingStatisticsDocuments")
465465 abstract List<SamplingStatisticsDocument> getDocuments();
466-
466+
467467+ // Limit of 25 items
468468+ @JsonProperty("SamplingBoostStatisticsDocuments")
469469+ abstract List<SamplingBoostStatisticsDocument> getBoostDocuments();
@@ -536,18 +536,18 @@ index c1e178f5..406f07e2 100644
536536- lastRuleModification, documents, unprocessedStatistics);
537537+ lastRuleModification, documents, unprocessedStatistics, unprocessedBoostStatistics);
538538 }
539-
539+
540540 abstract Date getLastRuleModification();
541541@@ -30,6 +32,9 @@ abstract class GetSamplingTargetsResponse {
542-
542+
543543 abstract List<UnprocessedStatistics> getUnprocessedStatistics();
544-
544+
545545+ @Nullable
546546+ abstract List<UnprocessedStatistics> getUnprocessedBoostStatistics();
547547+
548548 @AutoValue
549549 abstract static class SamplingTargetDocument {
550-
550+
551551@@ -39,9 +44,10 @@ abstract class GetSamplingTargetsResponse {
552552 @JsonProperty("Interval") @Nullable Integer intervalSecs,
553553 @JsonProperty("ReservoirQuota") @Nullable Integer reservoirQuota,
@@ -558,20 +558,20 @@ index c1e178f5..406f07e2 100644
558558- fixedRate, intervalSecs, reservoirQuota, reservoirQuotaTtl, ruleName);
559559+ fixedRate, intervalSecs, reservoirQuota, reservoirQuotaTtl, samplingBoost, ruleName);
560560 }
561-
561+
562562 abstract double getFixedRate();
563563@@ -57,6 +63,9 @@ abstract class GetSamplingTargetsResponse {
564564 @Nullable
565565 abstract Date getReservoirQuotaTtl();
566-
566+
567567+ @Nullable
568568+ abstract SamplingBoost getSamplingBoost();
569569+
570570 abstract String getRuleName();
571571 }
572-
572+
573573@@ -78,4 +87,18 @@ abstract class GetSamplingTargetsResponse {
574-
574+
575575 abstract String getRuleName();
576576 }
577577+
@@ -608,7 +608,7 @@ index 1d97c4ae..6462c7f3 100644
608608 import io.opentelemetry.sdk.trace.samplers.Sampler;
609609 import io.opentelemetry.sdk.trace.samplers.SamplingDecision;
610610@@ -76,12 +79,20 @@ final class SamplingRuleApplier {
611-
611+
612612 private final String clientId;
613613 private final String ruleName;
614614+ private final String serviceName;
@@ -618,7 +618,7 @@ index 1d97c4ae..6462c7f3 100644
618618+ private final double fixedRate;
619619 private final Sampler fixedRateSampler;
620620 private final boolean borrowing;
621-
621+
622622+ // Adaptive sampling related configs
623623+ private final boolean hasBoost;
624624+ private final double boostedFixedRate;
@@ -629,9 +629,9 @@ index 1d97c4ae..6462c7f3 100644
629629 private final Matcher urlPathMatcher;
630630 private final Matcher serviceNameMatcher;
631631@@ -94,7 +105,11 @@ final class SamplingRuleApplier {
632-
632+
633633 private final long nextSnapshotTimeNanos;
634-
634+
635635- SamplingRuleApplier(String clientId, GetSamplingRulesResponse.SamplingRule rule, Clock clock) {
636636+ SamplingRuleApplier(
637637+ String clientId,
@@ -644,12 +644,12 @@ index 1d97c4ae..6462c7f3 100644
644644@@ -108,6 +123,8 @@ final class SamplingRuleApplier {
645645 }
646646 this.ruleName = ruleName;
647-
647+
648648+ this.serviceName = serviceName == null ? "default" : serviceName;
649649+
650650 // We don't have a SamplingTarget so are ready to report a snapshot right away.
651651 nextSnapshotTimeNanos = clock.nanoTime();
652-
652+
653653@@ -124,7 +141,15 @@ final class SamplingRuleApplier {
654654 reservoirSampler = Sampler.alwaysOff();
655655 borrowing = false;
@@ -664,7 +664,7 @@ index 1d97c4ae..6462c7f3 100644
664664+ boostedFixedRate = fixedRate;
665665+ boostedFixedRateSampler = createFixedRate(fixedRate);
666666+ boostEndTimeNanos = clock.nanoTime();
667-
667+
668668 if (rule.getAttributes().isEmpty()) {
669669 attributeMatchers = Collections.emptyMap();
670670@@ -147,11 +172,16 @@ final class SamplingRuleApplier {
@@ -707,7 +707,7 @@ index 1d97c4ae..6462c7f3 100644
707707 this.nextSnapshotTimeNanos = nextSnapshotTimeNanos;
708708+ this.boostedFixedRateSampler = createFixedRate(this.boostedFixedRate);
709709 }
710-
710+
711711 @SuppressWarnings("deprecation") // TODO
712712@@ -273,45 +309,84 @@ final class SamplingRuleApplier {
713713 statistics.sampled.increment();
@@ -731,7 +731,7 @@ index 1d97c4ae..6462c7f3 100644
731731 }
732732 return result;
733733 }
734-
734+
735735+ void countTrace() {
736736+ statistics.traces.increment();
737737+ }
@@ -789,11 +789,11 @@ index 1d97c4ae..6462c7f3 100644
789789+ .build();
790790+ return new SamplingRuleStatisticsSnapshot(samplingStatistics, boostDoc);
791791 }
792-
792+
793793 long getNextSnapshotTimeNanos() {
794794 return nextSnapshotTimeNanos;
795795 }
796-
796+
797797- SamplingRuleApplier withTarget(SamplingTargetDocument target, Date now) {
798798+ // currentNanoTime is passed in to ensure all uses of withTarget are used with the same baseline
799799+ // time reference
@@ -832,7 +832,7 @@ index 1d97c4ae..6462c7f3 100644
832832+ .toNanos();
833833+ }
834834+ }
835-
835+
836836 return new SamplingRuleApplier(
837837 clientId,
838838 ruleName,
@@ -869,7 +869,7 @@ index 1d97c4ae..6462c7f3 100644
869869@@ -364,6 +464,15 @@ final class SamplingRuleApplier {
870870 return ruleName;
871871 }
872-
872+
873873+ // For testing
874874+ String getServiceName() {
875875+ return serviceName;
@@ -914,13 +914,13 @@ index 1d97c4ae..6462c7f3 100644
914914 }
915915 }
916916diff --git a/aws-xray/src/main/java/io/opentelemetry/contrib/awsxray/XrayRulesSampler.java b/aws-xray/src/main/java/io/opentelemetry/contrib/awsxray/XrayRulesSampler.java
917- index 75977dc0..96cd61a0 100644
917+ index 75977dc0..9620ba2b 100644
918918--- a/aws-xray/src/main/java/io/opentelemetry/contrib/awsxray/XrayRulesSampler.java
919919+++ b/aws-xray/src/main/java/io/opentelemetry/contrib/awsxray/XrayRulesSampler.java
920920@@ -5,42 +5,79 @@
921-
921+
922922 package io.opentelemetry.contrib.awsxray;
923-
923+
924924+ import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE;
925925+ import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_NAME;
926926+
@@ -957,11 +957,11 @@ index 75977dc0..96cd61a0 100644
957957 import java.util.logging.Logger;
958958 import java.util.stream.Collectors;
959959+ import javax.annotation.Nullable;
960-
960+
961961 final class XrayRulesSampler implements Sampler {
962-
962+
963963 private static final Logger logger = Logger.getLogger(XrayRulesSampler.class.getName());
964-
964+
965965+ public static final AttributeKey<String> AWS_XRAY_SAMPLING_RULE =
966966+ AttributeKey.stringKey("aws.xray.sampling_rule");
967967+
@@ -986,7 +986,7 @@ index 75977dc0..96cd61a0 100644
986986+
987987+ @Nullable private AwsXrayAdaptiveSamplingConfig adaptiveSamplingConfig;
988988+ @Nullable private RateLimiter anomalyCaptureRateLimiter;
989-
989+
990990 XrayRulesSampler(
991991 String clientId,
992992 Resource resource,
@@ -1018,7 +1018,7 @@ index 75977dc0..96cd61a0 100644
10181018+ .expireAfterWrite(Duration.ofMinutes(10))
10191019+ .build());
10201020 }
1021-
1021+
10221022 private XrayRulesSampler(
10231023@@ -58,12 +106,36 @@ final class XrayRulesSampler implements Sampler {
10241024 Resource resource,
@@ -1056,7 +1056,7 @@ index 75977dc0..96cd61a0 100644
10561056+ new RateLimiter(anomalyTracesPerSecond, anomalyTracesPerSecond, clock);
10571057+ }
10581058 }
1059-
1059+
10601060 @Override
10611061@@ -74,10 +146,36 @@ final class XrayRulesSampler implements Sampler {
10621062 SpanKind spanKind,
@@ -1096,11 +1096,11 @@ index 75977dc0..96cd61a0 100644
10961096+ return AwsSamplingResult.create(result.getDecision(), result.getAttributes(), hashedRule);
10971097 }
10981098 }
1099-
1100- @@ -96,7 +194,185 @@ final class XrayRulesSampler implements Sampler {
1099+
1100+ @@ -96,7 +194,184 @@ final class XrayRulesSampler implements Sampler {
11011101 return "XrayRulesSampler{" + Arrays.toString(ruleAppliers) + "}";
11021102 }
1103-
1103+
11041104- List<GetSamplingTargetsRequest.SamplingStatisticsDocument> snapshot(Date now) {
11051105+ void setAdaptiveSamplingConfig(AwsXrayAdaptiveSamplingConfig config) {
11061106+ if (this.adaptiveSamplingConfig != null) {
@@ -1244,7 +1244,6 @@ index 75977dc0..96cd61a0 100644
12441244+ ruleToReportTo = matchedRule;
12451245+ }
12461246+ }
1247- +
12481247+ if (shouldBoostSampling
12491248+ && ruleToReportTo != null
12501249+ && ruleToReportTo.hasBoost()
@@ -1284,7 +1283,7 @@ index 75977dc0..96cd61a0 100644
12841283 return Arrays.stream(ruleAppliers)
12851284 .map(rule -> rule.snapshot(now))
12861285 .filter(Objects::nonNull)
1287- @@ -115,15 +391 ,16 @@ final class XrayRulesSampler implements Sampler {
1286+ @@ -115,15 +390 ,16 @@ final class XrayRulesSampler implements Sampler {
12881287 Map<String, SamplingTargetDocument> ruleTargets,
12891288 Set<String> requestedTargetRuleNames,
12901289 Date now) {
@@ -1303,7 +1302,7 @@ index 75977dc0..96cd61a0 100644
13031302 }
13041303 if (requestedTargetRuleNames.contains(rule.getRuleName())) {
13051304 // In practice X-Ray should return a target for any rule we requested but
1306- @@ -135,6 +412 ,92 @@ final class XrayRulesSampler implements Sampler {
1305+ @@ -135,6 +411 ,92 @@ final class XrayRulesSampler implements Sampler {
13071306 return rule;
13081307 })
13091308 .toArray(SamplingRuleApplier[]::new);
0 commit comments