@@ -14,6 +14,7 @@ import java.util.concurrent.ConcurrentLinkedQueue
14
14
import java.util.concurrent.Executors
15
15
import kotlin.math.min
16
16
import kotlin.math.roundToInt
17
+ import java.util.concurrent.atomic.AtomicBoolean
17
18
18
19
class MetricsRequestFactory : RequestFactory () {
19
20
override fun upload (apiHost : String ): HttpURLConnection {
@@ -76,7 +77,14 @@ object Telemetry: Subscriber {
76
77
var host: String = Constants .DEFAULT_API_HOST
77
78
// 1.0 is 100%, will get set by Segment setting before start()
78
79
// Values are adjusted by the sampleRate on send
79
- var sampleRate: Double = 1.0
80
+ @Volatile private var _sampleRate : Double = 1.0
81
+ var sampleRate: Double
82
+ get() = _sampleRate
83
+ set(value) {
84
+ synchronized(this ) {
85
+ _sampleRate = value
86
+ }
87
+ }
80
88
var flushTimer: Int = 30 * 1000 // 30s
81
89
var httpClient: HTTPClient = HTTPClient (" " , MetricsRequestFactory ())
82
90
var sendWriteKeyOnError: Boolean = true
@@ -93,9 +101,9 @@ object Telemetry: Subscriber {
93
101
94
102
private val queue = ConcurrentLinkedQueue <RemoteMetric >()
95
103
private var queueBytes = 0
96
- private var started = false
104
+ private var started = AtomicBoolean ( false )
97
105
private var rateLimitEndTime: Long = 0
98
- private var flushFirstError = true
106
+ private var flushFirstError = AtomicBoolean ( true )
99
107
private val exceptionHandler = CoroutineExceptionHandler { _, t ->
100
108
errorHandler?.let {
101
109
it( Exception (
@@ -113,8 +121,8 @@ object Telemetry: Subscriber {
113
121
* Called automatically when Telemetry.enable is set to true and when configuration data is received from Segment.
114
122
*/
115
123
fun start () {
116
- if (! enable || started || sampleRate == 0.0 ) return
117
- started = true
124
+ if (! enable || started.get() || sampleRate == 0.0 ) return
125
+ started.set( true )
118
126
119
127
// Everything queued was sampled at default 100%, downsample adjustment and send will adjust values
120
128
if (Math .random() > sampleRate) {
@@ -124,7 +132,7 @@ object Telemetry: Subscriber {
124
132
telemetryJob = telemetryScope.launch(telemetryDispatcher) {
125
133
while (isActive) {
126
134
if (! enable) {
127
- started = false
135
+ started.set( false )
128
136
return @launch
129
137
}
130
138
try {
@@ -148,7 +156,7 @@ object Telemetry: Subscriber {
148
156
fun reset () {
149
157
telemetryJob?.cancel()
150
158
resetQueue()
151
- started = false
159
+ started.set( false )
152
160
rateLimitEndTime = 0
153
161
}
154
162
@@ -202,8 +210,8 @@ object Telemetry: Subscriber {
202
210
203
211
addRemoteMetric(metric, filteredTags, log= logData)
204
212
205
- if (flushFirstError) {
206
- flushFirstError = false
213
+ if (flushFirstError.get() ) {
214
+ flushFirstError.set( false )
207
215
flush()
208
216
}
209
217
}
@@ -218,7 +226,6 @@ object Telemetry: Subscriber {
218
226
219
227
try {
220
228
send()
221
- queueBytes = 0
222
229
} catch (error: Throwable ) {
223
230
errorHandler?.invoke(error)
224
231
sampleRate = 0.0
@@ -227,16 +234,14 @@ object Telemetry: Subscriber {
227
234
228
235
private fun send () {
229
236
if (sampleRate == 0.0 ) return
230
- var queueCount = queue.size
231
- // Reset queue data size counter since all current queue items will be removed
232
- queueBytes = 0
233
- val sendQueue = mutableListOf<RemoteMetric >()
234
- while (queueCount-- > 0 && ! queue.isEmpty()) {
235
- val m = queue.poll()
236
- if (m != null ) {
237
- m.value = (m.value / sampleRate).roundToInt()
238
- sendQueue.add(m)
239
- }
237
+ val sendQueue: MutableList <RemoteMetric >
238
+ synchronized(queue) {
239
+ sendQueue = queue.toMutableList()
240
+ queue.clear()
241
+ queueBytes = 0
242
+ }
243
+ sendQueue.forEach { m ->
244
+ m.value = (m.value / sampleRate).roundToInt()
240
245
}
241
246
try {
242
247
// Json.encodeToString by default does not include default values
@@ -309,9 +314,11 @@ object Telemetry: Subscriber {
309
314
tags = fullTags
310
315
)
311
316
val newMetricSize = newMetric.toString().toByteArray().size
312
- if (queueBytes + newMetricSize <= maxQueueBytes) {
313
- queue.add(newMetric)
314
- queueBytes + = newMetricSize
317
+ synchronized(queue) {
318
+ if (queueBytes + newMetricSize <= maxQueueBytes) {
319
+ queue.add(newMetric)
320
+ queueBytes + = newMetricSize
321
+ }
315
322
}
316
323
}
317
324
@@ -338,7 +345,9 @@ object Telemetry: Subscriber {
338
345
}
339
346
340
347
private fun resetQueue () {
341
- queue.clear()
342
- queueBytes = 0
348
+ synchronized(queue) {
349
+ queue.clear()
350
+ queueBytes = 0
351
+ }
343
352
}
344
353
}
0 commit comments