55
66namespace OpenTelemetry \Contrib \Sampler \Xray ;
77
8- use DateTimeImmutable ;
98use Exception ;
9+ use OpenTelemetry \API \Common \Time \Clock ;
10+ use OpenTelemetry \API \Common \Time \ClockInterface ;
1011use OpenTelemetry \Context \ContextInterface ;
1112use OpenTelemetry \SDK \Common \Attribute \AttributesInterface ;
1213use OpenTelemetry \SDK \Resource \ResourceInfo ;
1718/** @psalm-suppress UnusedClass */
1819class AWSXRayRemoteSampler implements SamplerInterface
1920{
21+ // 5 minute default sampling rules polling interval
22+ private const DEFAULT_RULES_POLLING_INTERVAL_SECONDS = 5 * 60 ;
23+ // Default endpoint for awsproxy : https://aws-otel.github.io/docs/getting-started/remote-sampling#enable-awsproxy-extension
24+ private const DEFAULT_AWS_PROXY_ENDPOINT = 'http://localhost:2000 ' ;
25+
2026 private SamplerInterface $ root ;
27+
28+ /**
29+ * @param ResourceInfo $resource
30+ * Must contain attributes like service.name, cloud.platform, etc.
31+ * @param string $host
32+ * X-Ray host, e.g. "xray.us-west-2.amazonaws.com"
33+ * @param int $pollingInterval
34+ * Base interval (seconds) between rule fetches (will be jittered).
35+ */
2136 public function __construct (
2237 ResourceInfo $ resource ,
23- string $ host ,
24- int $ rulePollingIntervalMillis = 60
38+ string $ host = self :: DEFAULT_AWS_PROXY_ENDPOINT ,
39+ int $ pollingInterval = self :: DEFAULT_RULES_POLLING_INTERVAL_SECONDS
2540 ) {
26- $ this ->root = new ParentBased (new _AWSXRayRemoteSampler ($ resource , $ host , $ rulePollingIntervalMillis ));
41+ // pollingInterval shouldn't be less than 10 seconds
42+ if ($ pollingInterval < 10 ) {
43+ $ pollingInterval = self ::DEFAULT_RULES_POLLING_INTERVAL_SECONDS ;
44+ }
45+
46+ $ this ->root = new ParentBased (new _AWSXRayRemoteSampler ($ resource , $ host , $ pollingInterval ));
2747 }
2848
2949 public function shouldSample (
@@ -48,24 +68,20 @@ public function getDescription(): string
4868
4969class _AWSXRayRemoteSampler implements SamplerInterface
5070{
51- // 5 minute default sampling rules polling interval
52- private const DEFAULT_RULES_POLLING_INTERVAL_SECONDS = 5 * 60 ;
53- // Default endpoint for awsproxy : https://aws-otel.github.io/docs/getting-started/remote-sampling#enable-awsproxy-extension
54- private const DEFAULT_AWS_PROXY_ENDPOINT = 'http://localhost:2000 ' ;
55-
56- private Clock $ clock ;
5771 private RulesCache $ rulesCache ;
5872 private FallbackSampler $ fallback ;
5973 private AWSXRaySamplerClient $ client ;
6074
61- private int $ rulePollingIntervalMillis ;
75+ private int $ rulePollingIntervalNanos ;
6276 /** @psalm-suppress UnusedProperty */
63- private int $ targetPollingIntervalMillis ;
64- private DateTimeImmutable $ nextRulesFetchTime ;
65- private DateTimeImmutable $ nextTargetFetchTime ;
77+ private int $ targetPollingIntervalNanos ;
78+
79+ // the times below are in nanoseconds
80+ private int $ nextRulesFetchTime ;
81+ private int $ nextTargetFetchTime ;
6682
67- private int $ rulePollingJitterMillis ;
68- private int $ targetPollingJitterMillis ;
83+ private int $ rulePollingJitterNanos ;
84+ private int $ targetPollingJitterNanos ;
6985
7086 private string $ awsProxyEndpoint ;
7187
@@ -79,23 +95,21 @@ class _AWSXRayRemoteSampler implements SamplerInterface
7995 */
8096 public function __construct (
8197 ResourceInfo $ resource ,
82- string $ awsProxyEndpoint = self :: DEFAULT_AWS_PROXY_ENDPOINT ,
83- int $ pollingInterval = self :: DEFAULT_RULES_POLLING_INTERVAL_SECONDS
98+ string $ awsProxyEndpoint ,
99+ int $ pollingInterval
84100 ) {
85- $ this ->clock = new Clock ();
86101 $ this ->fallback = new FallbackSampler ();
87102 $ this ->rulesCache = new RulesCache (
88- $ this ->clock ,
89103 bin2hex (random_bytes (12 )),
90104 $ resource ,
91105 $ this ->fallback
92106 );
93107
94- $ this ->rulePollingIntervalMillis = $ pollingInterval * 1000 ;
95- $ this ->rulePollingJitterMillis = rand (1 , 5000 );
108+ $ this ->rulePollingIntervalNanos = $ pollingInterval * ClockInterface:: NANOS_PER_SECOND ;
109+ $ this ->rulePollingJitterNanos = rand (1 , 5000 ) * ClockInterface:: NANOS_PER_MILLISECOND ;
96110
97- $ this ->targetPollingIntervalMillis = $ this ->rulesCache ::DEFAULT_TARGET_INTERVAL_SEC * 1000 ;
98- $ this ->targetPollingJitterMillis = rand (1 , 100 );
111+ $ this ->targetPollingIntervalNanos = $ this ->rulesCache ::DEFAULT_TARGET_INTERVAL_SEC * ClockInterface:: NANOS_PER_SECOND ;
112+ $ this ->targetPollingJitterNanos = rand (1 , 100 ) * ClockInterface:: NANOS_PER_MILLISECOND ;
99113
100114 $ this ->awsProxyEndpoint = $ awsProxyEndpoint ;
101115
@@ -110,9 +124,9 @@ public function __construct(
110124 }
111125
112126 // 2) Schedule next fetch times with jitter
113- $ now = $ this -> clock ->now ();
114- $ this ->nextRulesFetchTime = $ now-> modify ( ' + ' . ($ this ->rulePollingJitterMillis + $ this ->rulePollingIntervalMillis ) . ' milliseconds ' );
115- $ this ->nextTargetFetchTime = $ now-> modify ( ' + ' . ($ this ->targetPollingJitterMillis + $ this ->targetPollingIntervalMillis ) . ' milliseconds ' );
127+ $ now = Clock:: getDefault () ->now ();
128+ $ this ->nextRulesFetchTime = $ now + ($ this ->rulePollingJitterNanos + $ this ->rulePollingIntervalNanos );
129+ $ this ->nextTargetFetchTime = $ now + ($ this ->targetPollingJitterNanos + $ this ->targetPollingIntervalNanos );
116130 }
117131
118132 /**
@@ -126,7 +140,7 @@ public function shouldSample(
126140 AttributesInterface $ attributes ,
127141 array $ links ,
128142 ): SamplingResult {
129- $ now = $ this -> clock ->now ();
143+ $ now = Clock:: getDefault () ->now ();
130144
131145 // 1) Refresh rules if needed
132146 if ($ now >= $ this ->nextRulesFetchTime ) {
@@ -151,7 +165,7 @@ public function shouldSample(
151165 $ this ->rulesCache ->updateTargets ($ map );
152166
153167 if (isset ($ resp ->LastRuleModification ) && $ resp ->LastRuleModification > 0 ) {
154- if ($ resp ->LastRuleModification > $ this ->rulesCache ->getUpdatedAt ()-> getTimestamp ()) {
168+ if (( $ resp ->LastRuleModification * ClockInterface:: NANOS_PER_SECOND ) > $ this ->rulesCache ->getUpdatedAt ()) {
155169 $ this ->getAndUpdateRules ($ now );
156170 }
157171 }
@@ -161,15 +175,11 @@ public function shouldSample(
161175 }
162176
163177 $ nextTargetFetchTime = $ this ->rulesCache ->nextTargetFetchTime ();
164- $ nextTargetFetchInterval = $ nextTargetFetchTime-> getTimestamp () - $ this -> clock -> now ()->getTimestamp ();
178+ $ nextTargetFetchInterval = $ nextTargetFetchTime - Clock:: getDefault ()->now ();
165179 if ($ nextTargetFetchInterval < 0 ) {
166- $ nextTargetFetchInterval = $ this ->rulesCache ::DEFAULT_TARGET_INTERVAL_SEC ;
180+ $ nextTargetFetchInterval = $ this ->rulesCache ::DEFAULT_TARGET_INTERVAL_SEC * ClockInterface:: NANOS_PER_SECOND ;
167181 }
168-
169- $ nextTargetFetchInterval = $ nextTargetFetchInterval * 1000 ;
170-
171- $ this ->nextTargetFetchTime = $ now ->modify ('+ ' . ($ this ->targetPollingJitterMillis + $ nextTargetFetchInterval ) . ' milliseconds ' );
172-
182+ $ this ->nextTargetFetchTime = $ now + ($ this ->targetPollingJitterNanos + $ nextTargetFetchInterval );
173183 }
174184
175185 // 3) Delegate decision to rulesCache or fallback
@@ -182,23 +192,23 @@ public function shouldSample(
182192 return $ this ->rulesCache ->shouldSample ($ parentContext , $ traceId , $ spanName , $ spanKind , $ attributes , $ links );
183193 }
184194
185- private function getAndUpdateRules (DateTimeImmutable $ now )
195+ private function getAndUpdateRules (int $ now )
186196 {
187197 try {
188198 $ rules = $ this ->client ->getSamplingRules ();
189199 $ this ->rulesCache ->updateRules ($ rules );
190200 } catch (Exception $ e ) {
191201 // ignore error
192202 }
193- $ this ->nextRulesFetchTime = $ now-> modify ( ' + ' . ($ this ->rulePollingJitterMillis + $ this ->rulePollingIntervalMillis ) . ' milliseconds ' );
203+ $ this ->nextRulesFetchTime = $ now + ($ this ->rulePollingJitterNanos + $ this ->rulePollingIntervalNanos );
194204 }
195205
196206 public function getDescription (): string
197207 {
198208 return sprintf (
199- '_AWSXRayRemoteSampler{awsProxyEndpoint=%s,rulePollingIntervalMillis =%ds} ' ,
209+ '_AWSXRayRemoteSampler{awsProxyEndpoint=%s,rulePollingIntervalNanos =%ds} ' ,
200210 $ this ->awsProxyEndpoint ,
201- $ this ->rulePollingIntervalMillis
211+ $ this ->rulePollingIntervalNanos
202212 );
203213 }
204214}
0 commit comments