From e2c63278469347cccfa7ac83a86ef98fe58da5d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Fri, 1 Nov 2024 10:44:04 +0100 Subject: [PATCH 1/2] Add support for providing default signal name prefix and parameters --- Sources/TelemetryDeck/TelemetryClient.swift | 8 ++++++++ Sources/TelemetryDeck/TelemetryDeck.swift | 7 +++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Sources/TelemetryDeck/TelemetryClient.swift b/Sources/TelemetryDeck/TelemetryClient.swift index 89a7fe1..0f37f03 100644 --- a/Sources/TelemetryDeck/TelemetryClient.swift +++ b/Sources/TelemetryDeck/TelemetryClient.swift @@ -41,6 +41,14 @@ public struct TelemetryManagerConfiguration: Sendable { /// Instead it is used to create a hash, which is included in your signal to allow you to count distinct users. public var defaultUser: String? + /// Specify this if you want us to prefix all your signals with a specific text. + /// For example, if you are already adding `AppName.` in front of every signal, just specify it here and no need to repeat over and over again. + public var defaultSignalPrefix: String? + + /// Specify this if you want to attach some parameters globally to all signals you're sending. + /// For example, this could be useful to report your users' paid status or their user preferences to be able to filter by these fields in various insights. + public var defaultParameters: @Sendable () -> [String: String] = { [:] } + /// If `true`, sends a "newSessionBegan" Signal on each app foreground or cold launch /// /// Defaults to true. Set to false to prevent automatically sending this signal. diff --git a/Sources/TelemetryDeck/TelemetryDeck.swift b/Sources/TelemetryDeck/TelemetryDeck.swift index 61ef54f..558b39c 100644 --- a/Sources/TelemetryDeck/TelemetryDeck.swift +++ b/Sources/TelemetryDeck/TelemetryDeck.swift @@ -36,9 +36,12 @@ public enum TelemetryDeck { // make sure to not send any signals when run by Xcode via SwiftUI previews guard !configuration.swiftUIPreviewMode, !configuration.analyticsDisabled else { return } + let combinedSignalName = (configuration.defaultSignalPrefix ?? "") + signalName + let combinedParameters = configuration.defaultParameters().merging(parameters) { $1 } + manager.signalManager.processSignal( - signalName, - parameters: parameters, + combinedSignalName, + parameters: combinedParameters, floatValue: floatValue, customUserID: customUserID, configuration: configuration From 2634b2ca842954bb60001a0d8d086371b8824b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Fri, 1 Nov 2024 10:55:35 +0100 Subject: [PATCH 2/2] Add defaultParameterPrefix global option for prefixing parameters, too --- .../TelemetryDeck/Helpers/DictionaryExt.swift | 27 +++++++++++++++++++ Sources/TelemetryDeck/TelemetryClient.swift | 6 +++++ Sources/TelemetryDeck/TelemetryDeck.swift | 4 ++- 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 Sources/TelemetryDeck/Helpers/DictionaryExt.swift diff --git a/Sources/TelemetryDeck/Helpers/DictionaryExt.swift b/Sources/TelemetryDeck/Helpers/DictionaryExt.swift new file mode 100644 index 0000000..03f0712 --- /dev/null +++ b/Sources/TelemetryDeck/Helpers/DictionaryExt.swift @@ -0,0 +1,27 @@ +import Foundation + +// Source: https://github.com/FlineDev/HandySwift/blob/main/Sources/HandySwift/Extensions/DictionaryExt.swift + +extension Dictionary { + /// Transforms the keys of the dictionary using the given closure, returning a new dictionary with the transformed keys. + /// + /// - Parameter transform: A closure that takes a key from the dictionary as its argument and returns a new key. + /// - Returns: A dictionary with keys transformed by the `transform` closure and the same values as the original dictionary. + /// - Throws: Rethrows any error thrown by the `transform` closure. + /// + /// - Warning: If the `transform` closure produces duplicate keys, the values of earlier keys will be overridden by the values of later keys in the resulting dictionary. + /// + /// - Example: + /// ``` + /// let originalDict = ["one": 1, "two": 2, "three": 3] + /// let transformedDict = originalDict.mapKeys { $0.uppercased() } + /// // transformedDict will be ["ONE": 1, "TWO": 2, "THREE": 3] + /// ``` + func mapKeys(_ transform: (Key) throws -> K) rethrows -> [K: Value] { + var transformedDict: [K: Value] = [:] + for (key, value) in self { + transformedDict[try transform(key)] = value + } + return transformedDict + } +} diff --git a/Sources/TelemetryDeck/TelemetryClient.swift b/Sources/TelemetryDeck/TelemetryClient.swift index 0f37f03..78493a8 100644 --- a/Sources/TelemetryDeck/TelemetryClient.swift +++ b/Sources/TelemetryDeck/TelemetryClient.swift @@ -45,8 +45,14 @@ public struct TelemetryManagerConfiguration: Sendable { /// For example, if you are already adding `AppName.` in front of every signal, just specify it here and no need to repeat over and over again. public var defaultSignalPrefix: String? + /// Specify this if you want us to prefix all your signal parameters with a specific text. + /// For example, if you are already adding `AppName.` in front of every parameter name, just specify it here and no need to repeat over and over again. + public var defaultParameterPrefix: String? + /// Specify this if you want to attach some parameters globally to all signals you're sending. /// For example, this could be useful to report your users' paid status or their user preferences to be able to filter by these fields in various insights. + /// + /// - NOTE: If you are using ``defaultParameterPrefix``, note that it applies even here, so no need to add your prefix in all the default parameters. public var defaultParameters: @Sendable () -> [String: String] = { [:] } /// If `true`, sends a "newSessionBegan" Signal on each app foreground or cold launch diff --git a/Sources/TelemetryDeck/TelemetryDeck.swift b/Sources/TelemetryDeck/TelemetryDeck.swift index 558b39c..75a1506 100644 --- a/Sources/TelemetryDeck/TelemetryDeck.swift +++ b/Sources/TelemetryDeck/TelemetryDeck.swift @@ -37,7 +37,9 @@ public enum TelemetryDeck { guard !configuration.swiftUIPreviewMode, !configuration.analyticsDisabled else { return } let combinedSignalName = (configuration.defaultSignalPrefix ?? "") + signalName - let combinedParameters = configuration.defaultParameters().merging(parameters) { $1 } + let combinedParameters = configuration.defaultParameters() + .merging(parameters) { $1 } + .mapKeys { (configuration.defaultParameterPrefix ?? "") + $0 } manager.signalManager.processSignal( combinedSignalName,