@@ -29,15 +29,17 @@ import {
29
29
import {
30
30
ParentBasedSampler ,
31
31
Sampler ,
32
- SamplingDecision ,
33
32
SamplingResult ,
34
33
} from '@opentelemetry/sdk-trace-base' ;
35
34
import { AWSXRaySamplingClient } from './aws-xray-sampling-client' ;
35
+ import { FallbackSampler } from './fallback-sampler' ;
36
36
import {
37
37
AWSXRayRemoteSamplerConfig ,
38
38
GetSamplingRulesResponse ,
39
39
SamplingRuleRecord ,
40
40
} from './types' ;
41
+ import { RuleCache } from './rule-cache' ;
42
+
41
43
import { SamplingRuleApplier } from './sampling-rule-applier' ;
42
44
43
45
// 5 minute default sampling rules polling interval
@@ -50,12 +52,14 @@ const DEFAULT_AWS_PROXY_ENDPOINT = 'http://localhost:2000';
50
52
export class AWSXRayRemoteSampler implements Sampler {
51
53
private _root : ParentBasedSampler ;
52
54
private internalXraySampler : _AWSXRayRemoteSampler ;
55
+
53
56
constructor ( samplerConfig : AWSXRayRemoteSamplerConfig ) {
54
57
this . internalXraySampler = new _AWSXRayRemoteSampler ( samplerConfig ) ;
55
58
this . _root = new ParentBasedSampler ( {
56
59
root : this . internalXraySampler ,
57
60
} ) ;
58
61
}
62
+
59
63
public shouldSample (
60
64
context : Context ,
61
65
traceId : string ,
@@ -91,8 +95,11 @@ export class AWSXRayRemoteSampler implements Sampler {
91
95
export class _AWSXRayRemoteSampler implements Sampler {
92
96
private rulePollingIntervalMillis : number ;
93
97
private awsProxyEndpoint : string ;
98
+ private ruleCache : RuleCache ;
99
+ private fallbackSampler : FallbackSampler ;
94
100
private samplerDiag : DiagLogger ;
95
101
private rulePoller : NodeJS . Timeout | undefined ;
102
+ private clientId : string ;
96
103
private rulePollingJitterMillis : number ;
97
104
private samplingClient : AWSXRaySamplingClient ;
98
105
@@ -117,6 +124,10 @@ export class _AWSXRayRemoteSampler implements Sampler {
117
124
this . awsProxyEndpoint = samplerConfig . endpoint
118
125
? samplerConfig . endpoint
119
126
: DEFAULT_AWS_PROXY_ENDPOINT ;
127
+ this . fallbackSampler = new FallbackSampler ( ) ;
128
+ // TODO: Use clientId for retrieving Sampling Targets
129
+ this . clientId = _AWSXRayRemoteSampler . generateClientId ( ) ;
130
+ this . ruleCache = new RuleCache ( samplerConfig . resource ) ;
120
131
121
132
this . samplingClient = new AWSXRaySamplingClient (
122
133
this . awsProxyEndpoint ,
@@ -137,8 +148,51 @@ export class _AWSXRayRemoteSampler implements Sampler {
137
148
attributes : Attributes ,
138
149
links : Link [ ]
139
150
) : SamplingResult {
140
- // Implementation to be added
141
- return { decision : SamplingDecision . NOT_RECORD } ;
151
+ if ( this . ruleCache . isExpired ( ) ) {
152
+ this . samplerDiag . debug (
153
+ 'Rule cache is expired, so using fallback sampling strategy'
154
+ ) ;
155
+ return this . fallbackSampler . shouldSample (
156
+ context ,
157
+ traceId ,
158
+ spanName ,
159
+ spanKind ,
160
+ attributes ,
161
+ links
162
+ ) ;
163
+ }
164
+
165
+ try {
166
+ const matchedRule : SamplingRuleApplier | undefined =
167
+ this . ruleCache . getMatchedRule ( attributes ) ;
168
+ if ( matchedRule ) {
169
+ return matchedRule . shouldSample (
170
+ context ,
171
+ traceId ,
172
+ spanName ,
173
+ spanKind ,
174
+ attributes ,
175
+ links
176
+ ) ;
177
+ }
178
+ } catch ( e : unknown ) {
179
+ this . samplerDiag . debug (
180
+ 'Unexpected error occurred when trying to match or applying a sampling rule' ,
181
+ e
182
+ ) ;
183
+ }
184
+
185
+ this . samplerDiag . debug (
186
+ 'Using fallback sampler as no rule match was found. This is likely due to a bug, since default rule should always match'
187
+ ) ;
188
+ return this . fallbackSampler . shouldSample (
189
+ context ,
190
+ traceId ,
191
+ spanName ,
192
+ spanKind ,
193
+ attributes ,
194
+ links
195
+ ) ;
142
196
}
143
197
144
198
public toString ( ) : string {
@@ -180,13 +234,37 @@ export class _AWSXRayRemoteSampler implements Sampler {
180
234
}
181
235
}
182
236
) ;
183
-
184
- // TODO: pass samplingRules to rule cache, temporarily logging the samplingRules array
185
- this . samplerDiag . debug ( 'sampling rules: ' , samplingRules ) ;
237
+ this . ruleCache . updateRules ( samplingRules ) ;
186
238
} else {
187
239
this . samplerDiag . error (
188
240
'SamplingRuleRecords from GetSamplingRules request is not defined'
189
241
) ;
190
242
}
191
243
}
244
+
245
+ private static generateClientId ( ) : string {
246
+ const hexChars : string [ ] = [
247
+ '0' ,
248
+ '1' ,
249
+ '2' ,
250
+ '3' ,
251
+ '4' ,
252
+ '5' ,
253
+ '6' ,
254
+ '7' ,
255
+ '8' ,
256
+ '9' ,
257
+ 'a' ,
258
+ 'b' ,
259
+ 'c' ,
260
+ 'd' ,
261
+ 'e' ,
262
+ 'f' ,
263
+ ] ;
264
+ const clientIdArray : string [ ] = [ ] ;
265
+ for ( let _ = 0 ; _ < 24 ; _ += 1 ) {
266
+ clientIdArray . push ( hexChars [ Math . floor ( Math . random ( ) * hexChars . length ) ] ) ;
267
+ }
268
+ return clientIdArray . join ( '' ) ;
269
+ }
192
270
}
0 commit comments