11import Foundation
22import Sovran
3+ #if os(Linux) || os(Windows)
4+ import FoundationNetworking
5+ #endif
36
47public struct RemoteMetric : Codable {
58let type : String
@@ -68,8 +71,8 @@ public class Telemetry: Subscriber {
6871
6972internal var session : any HTTPSession
7073internal var host : String = HTTPClient . getDefaultAPIHost ( )
71- var sampleRate : Double = 0.10
72- private var flushTimer : Int = 30 * 1000
74+ var sampleRate : Double = 1.0 // inital sample rate should be 1.0, will be downsampled on start
75+ private var flushTimer : Int = 30
7376internal var maxQueueSize : Int = 20
7477var errorLogSizeMax : Int = 4000
7578
@@ -87,7 +90,8 @@ public class Telemetry: Subscriber {
8790internal var started = false
8891private var rateLimitEndTime : TimeInterval = 0
8992private var telemetryQueue = DispatchQueue ( label: " telemetryQueue " )
90- private var telemetryTimer : Timer ?
93+ private var updateQueue = DispatchQueue ( label: " updateQueue " )
94+ private var telemetryTimer : QueueTimer ?
9195
9296 /// Starts the Telemetry send loop. Requires both `enable` to be set and a configuration to be retrieved from Segment.
9397func start( ) {
@@ -96,20 +100,27 @@ public class Telemetry: Subscriber {
96100
97101if Double . random ( in: 0 ... 1 ) > sampleRate{
98102resetQueue ( )
103+ } else {
104+ telemetryQueue. async {
105+ self . queue= self . queue. map { var metric = $0
106+ metric. value= Int ( Double ( metric. value) / self . sampleRate)
107+ return metric
108+ }
109+ }
99110}
100111
101- telemetryTimer= Timer . scheduledTimer ( withTimeInterval : TimeInterval ( flushTimer) / 1000.0 , repeats : true ) { [ weak self] _ in
112+ self . telemetryTimer= QueueTimer ( interval : . seconds ( self . flushTimer) , queue : . main ) { [ weak self] in
102113if ( !( self ? . enable?? false ) ) {
103114self ? . started= false
104- self ? . telemetryTimer? . invalidate ( )
115+ self ? . telemetryTimer? . suspend ( )
105116}
106117self ? . flush ( )
107118}
108119}
109120
110121 /// Resets the telemetry state, including the queue and seen errors.
111122func reset( ) {
112- telemetryTimer? . invalidate ( )
123+ telemetryTimer? . suspend ( )
113124resetQueue ( )
114125 seenErrors. removeAll ( )
115126 started= false
@@ -121,10 +132,12 @@ public class Telemetry: Subscriber {
121132 /// - metric: The metric name.
122133 /// - buildTags: A closure to build the tags dictionary.
123134func increment( metric: String , buildTags: ( inout [ String : String ] ) -> Void ) {
135+ guard enable, sampleRate> 0.0 && sampleRate<= 1.0 , metric. hasPrefix ( Telemetry . METRICS_BASE_TAG) , queueHasSpace ( ) else { return }
136+
124137var tags = [ String: String] ( )
125138buildTags ( & tags)
139+ guard !tags. isEmptyelse { return }
126140
127- guard enable, sampleRate> 0.0 && sampleRate<= 1.0 , metric. hasPrefix ( Telemetry . METRICS_BASE_TAG) , !tags. isEmpty, queueHasSpace ( ) else { return }
128141if Double . random ( in: 0 ... 1 ) > sampleRate{ return }
129142
130143addRemoteMetric ( metric: metric, tags: tags)
@@ -136,10 +149,11 @@ public class Telemetry: Subscriber {
136149 /// - log: The log data.
137150 /// - buildTags: A closure to build the tags dictionary.
138151func error( metric: String , log: String , buildTags: ( inout [ String : String ] ) -> Void ) {
152+ guard enable, sampleRate> 0.0 && sampleRate<= 1.0 , metric. hasPrefix ( Telemetry . METRICS_BASE_TAG) , queueHasSpace ( ) else { return }
153+
139154var tags = [ String: String] ( )
140155buildTags ( & tags)
141-
142- guard enable, sampleRate> 0.0 && sampleRate<= 1.0 , metric. hasPrefix ( Telemetry . METRICS_BASE_TAG) , !tags. isEmpty, queueHasSpace ( ) else { return }
156+ guard !tags. isEmptyelse { return }
143157
144158var filteredTags = tags
145159if ( !sendWriteKeyOnError) {
@@ -248,8 +262,8 @@ public class Telemetry: Subscriber {
248262let fullTags = tags. merging ( additionalTags) { ( _, new) in new}
249263
250264 telemetryQueue. sync {
251- if var found = queue. first ( where: { $0. metric== metric && $0. tags== fullTags} ) {
252- found . value+= value
265+ if let index = queue. firstIndex ( where: { $0. metric== metric && $0. tags== fullTags} ) {
266+ queue [ index ] . value+= value
253267return
254268}
255269
@@ -275,7 +289,7 @@ public class Telemetry: Subscriber {
275289public func subscribe( _ store: Store ) {
276290 store. subscribe ( self ,
277291 initialState: true ,
278- queue: telemetryQueue ,
292+ queue: updateQueue ,
279293 handler: systemUpdate
280294)
281295}