diff --git a/Examples/apps/watchOSExample/watchOSExample WatchKit Extension/ExtensionDelegate.swift b/Examples/apps/watchOSExample/watchOSExample WatchKit Extension/ExtensionDelegate.swift index 9a20f3f5..63341a66 100644 --- a/Examples/apps/watchOSExample/watchOSExample WatchKit Extension/ExtensionDelegate.swift +++ b/Examples/apps/watchOSExample/watchOSExample WatchKit Extension/ExtensionDelegate.swift @@ -18,7 +18,6 @@ class ExtensionDelegate: NSObject, WKExtensionDelegate { .flushInterval(10) analytics = Analytics(configuration: configuration) - analytics?.add(plugin: ConsoleLogger(name: "consoleLogger")) analytics?.add(plugin: NotificationTracking()) } diff --git a/Examples/apps/watchOSExample/watchOSExample.xcodeproj/project.pbxproj b/Examples/apps/watchOSExample/watchOSExample.xcodeproj/project.pbxproj index f40b98f0..629cff69 100644 --- a/Examples/apps/watchOSExample/watchOSExample.xcodeproj/project.pbxproj +++ b/Examples/apps/watchOSExample/watchOSExample.xcodeproj/project.pbxproj @@ -3,11 +3,10 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ - 465879B22685058800180335 /* ConsoleLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 465879B12685058800180335 /* ConsoleLogger.swift */; }; 465879B4268641B900180335 /* SomeScreenController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 465879B3268641B900180335 /* SomeScreenController.swift */; }; 469ECD4D2684F9080028BE9A /* watchOSExample WatchKit App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 469ECD4C2684F9080028BE9A /* watchOSExample WatchKit App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 469ECD532684F9080028BE9A /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 469ECD512684F9080028BE9A /* Interface.storyboard */; }; @@ -65,7 +64,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 465879B12685058800180335 /* ConsoleLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConsoleLogger.swift; path = ../../../other_plugins/ConsoleLogger.swift; sourceTree = ""; }; 465879B3268641B900180335 /* SomeScreenController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SomeScreenController.swift; sourceTree = ""; }; 469ECD482684F9080028BE9A /* watchOSExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = watchOSExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 469ECD4C2684F9080028BE9A /* watchOSExample WatchKit App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "watchOSExample WatchKit App.app"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -129,7 +127,6 @@ 469ECD5F2684F9090028BE9A /* watchOSExample WatchKit Extension */ = { isa = PBXGroup; children = ( - 465879B12685058800180335 /* ConsoleLogger.swift */, 469ECD602684F9090028BE9A /* InterfaceController.swift */, 465879B3268641B900180335 /* SomeScreenController.swift */, 469ECD622684F9090028BE9A /* ExtensionDelegate.swift */, @@ -291,7 +288,6 @@ 469ECD672684F9090028BE9A /* ComplicationController.swift in Sources */, 469ECD632684F9090028BE9A /* ExtensionDelegate.swift in Sources */, 46E73DA626F5389E0021042C /* NotificationTracking.swift in Sources */, - 465879B22685058800180335 /* ConsoleLogger.swift in Sources */, 469ECD612684F9090028BE9A /* InterfaceController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Sources/Segment/Utilities/Telemetry.swift b/Sources/Segment/Utilities/Telemetry.swift index 031d4a34..63a0578d 100644 --- a/Sources/Segment/Utilities/Telemetry.swift +++ b/Sources/Segment/Utilities/Telemetry.swift @@ -68,8 +68,8 @@ public class Telemetry: Subscriber { internal var session: any HTTPSession internal var host: String = HTTPClient.getDefaultAPIHost() - var sampleRate: Double = 0.10 - private var flushTimer: Int = 30 * 1000 + var sampleRate: Double = 1.0 // inital sample rate should be 1.0, will be downsampled on start + private var flushTimer: Double = 30.0 internal var maxQueueSize: Int = 20 var errorLogSizeMax: Int = 4000 @@ -87,6 +87,7 @@ public class Telemetry: Subscriber { internal var started = false private var rateLimitEndTime: TimeInterval = 0 private var telemetryQueue = DispatchQueue(label: "telemetryQueue") + private var updateQueue = DispatchQueue(label: "updateQueue") private var telemetryTimer: Timer? /// Starts the Telemetry send loop. Requires both `enable` to be set and a configuration to be retrieved from Segment. @@ -96,14 +97,24 @@ public class Telemetry: Subscriber { if Double.random(in: 0...1) > sampleRate { resetQueue() + } else { + telemetryQueue.async { + self.queue = self.queue.map { var metric = $0 + metric.value = Int(Double(metric.value) / self.sampleRate) + return metric + } + } } - telemetryTimer = Timer.scheduledTimer(withTimeInterval: TimeInterval(flushTimer) / 1000.0, repeats: true) { [weak self] _ in + DispatchQueue.main.async { + self.telemetryTimer = Timer.scheduledTimer(withTimeInterval: self.flushTimer, repeats: true) { [weak self] _ in if (!(self?.enable ?? false)) { self?.started = false self?.telemetryTimer?.invalidate() } self?.flush() + } + self.telemetryTimer?.tolerance = self.flushTimer / 10.0 // 10% tolerance } } @@ -121,10 +132,12 @@ public class Telemetry: Subscriber { /// - metric: The metric name. /// - buildTags: A closure to build the tags dictionary. func increment(metric: String, buildTags: (inout [String: String]) -> Void) { + guard enable, sampleRate > 0.0 && sampleRate <= 1.0, metric.hasPrefix(Telemetry.METRICS_BASE_TAG), queueHasSpace() else { return } + var tags = [String: String]() buildTags(&tags) + guard !tags.isEmpty else { return } - guard enable, sampleRate > 0.0 && sampleRate <= 1.0, metric.hasPrefix(Telemetry.METRICS_BASE_TAG), !tags.isEmpty, queueHasSpace() else { return } if Double.random(in: 0...1) > sampleRate { return } addRemoteMetric(metric: metric, tags: tags) @@ -136,10 +149,11 @@ public class Telemetry: Subscriber { /// - log: The log data. /// - buildTags: A closure to build the tags dictionary. func error(metric: String, log: String, buildTags: (inout [String: String]) -> Void) { + guard enable, sampleRate > 0.0 && sampleRate <= 1.0, metric.hasPrefix(Telemetry.METRICS_BASE_TAG), queueHasSpace() else { return } + var tags = [String: String]() buildTags(&tags) - - guard enable, sampleRate > 0.0 && sampleRate <= 1.0, metric.hasPrefix(Telemetry.METRICS_BASE_TAG), !tags.isEmpty, queueHasSpace() else { return } + guard !tags.isEmpty else { return } var filteredTags = tags if (!sendWriteKeyOnError) { @@ -248,8 +262,8 @@ public class Telemetry: Subscriber { let fullTags = tags.merging(additionalTags) { (_, new) in new } telemetryQueue.sync { - if var found = queue.first(where: { $0.metric == metric && $0.tags == fullTags }) { - found.value += value + if let index = queue.firstIndex(where: { $0.metric == metric && $0.tags == fullTags }) { + queue[index].value += value return } @@ -275,7 +289,7 @@ public class Telemetry: Subscriber { public func subscribe(_ store: Store) { store.subscribe(self, initialState: true, - queue: telemetryQueue, + queue: updateQueue, handler: systemUpdate ) }