11import Foundation
22import Sovran
3+ #if os(Linux) || os(Windows)
4+ import FoundationNetworking
5+ #endif
36
47public struct RemoteMetric : Codable {
58 let type : String
@@ -68,8 +71,8 @@ public class Telemetry: Subscriber {
6871
6972 internal var session : any HTTPSession
7073 internal 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
7376 internal var maxQueueSize : Int = 20
7477 var errorLogSizeMax : Int = 4000
7578
@@ -87,7 +90,8 @@ public class Telemetry: Subscriber {
8790 internal var started = false
8891 private var rateLimitEndTime : TimeInterval = 0
8992 private 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.
9397 func start( ) {
@@ -96,20 +100,27 @@ public class Telemetry: Subscriber {
96100
97101 if Double . random ( in: 0 ... 1 ) > sampleRate {
98102 resetQueue ( )
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
102113 if ( !( self ? . enable ?? false ) ) {
103114 self ? . started = false
104- self ? . telemetryTimer? . invalidate ( )
115+ self ? . telemetryTimer? . suspend ( )
105116 }
106117 self ? . flush ( )
107118 }
108119 }
109120
110121 /// Resets the telemetry state, including the queue and seen errors.
111122 func reset( ) {
112- telemetryTimer? . invalidate ( )
123+ telemetryTimer? . suspend ( )
113124 resetQueue ( )
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.
123134 func 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+
124137 var tags = [ String: String] ( )
125138 buildTags ( & tags)
139+ guard !tags. isEmpty else { return }
126140
127- guard enable, sampleRate > 0.0 && sampleRate <= 1.0 , metric. hasPrefix ( Telemetry . METRICS_BASE_TAG) , !tags. isEmpty, queueHasSpace ( ) else { return }
128141 if Double . random ( in: 0 ... 1 ) > sampleRate { return }
129142
130143 addRemoteMetric ( 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.
138151 func 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+
139154 var tags = [ String: String] ( )
140155 buildTags ( & 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. isEmpty else { return }
143157
144158 var filteredTags = tags
145159 if ( !sendWriteKeyOnError) {
@@ -248,8 +262,8 @@ public class Telemetry: Subscriber {
248262 let 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
253267 return
254268 }
255269
@@ -275,7 +289,7 @@ public class Telemetry: Subscriber {
275289 public func subscribe( _ store: Store ) {
276290 store. subscribe ( self ,
277291 initialState: true ,
278- queue: telemetryQueue ,
292+ queue: updateQueue ,
279293 handler: systemUpdate
280294 )
281295 }
0 commit comments