Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add debuglogger to confidence #144

Merged
merged 9 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct ConfidenceDemoApp: App {
var body: some Scene {
WindowGroup {
let secret = ProcessInfo.processInfo.environment["CLIENT_SECRET"] ?? ""
let confidence = Confidence.Builder(clientSecret: secret)
let confidence = Confidence.Builder(clientSecret: secret, loggerLevel: .TRACE)
.withContext(initialContext: ["targeting_key": ConfidenceValue(string: UUID.init().uuidString)])
.withRegion(region: .europe)
.build()
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ To set context data to be appended to all tracked events, here as example:
confidence.putContext(context: ["os_version": ConfidenceValue(string: "17.0")])
```

### Logging
By default, the Confidence SDK will log errors and warnings. You can change the preferred log level by passing a `loggerLevel` to the `Confidence.Builder` constructor.

To turn off logging completely, you can pass `LoggingLevel.NONE` to the `Confidence.Builder`.

# OpenFeature Provider
If you want to use OpenFeature, an OpenFeature Provider for the [OpenFeature SDK](https://github.com/open-feature/kotlin-swift) is also available.

Expand Down
6 changes: 5 additions & 1 deletion Sources/Confidence/Apply/FlagApplierWithRetries.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,22 @@ final class FlagApplierWithRetries: FlagApplier {
private let options: ConfidenceClientOptions
private let cacheDataInteractor: CacheDataActor
private let metadata: ConfidenceMetadata
private let debugLogger: DebugLogger?

init(
httpClient: HttpClient,
storage: Storage,
options: ConfidenceClientOptions,
metadata: ConfidenceMetadata,
cacheDataInteractor: CacheDataActor? = nil,
triggerBatch: Bool = true
triggerBatch: Bool = true,
debugLogger: DebugLogger? = nil
) {
self.storage = storage
self.httpClient = httpClient
self.options = options
self.metadata = metadata
self.debugLogger = debugLogger

let storedData = try? storage.load(defaultValue: CacheData.empty())
self.cacheDataInteractor = cacheDataInteractor ?? CacheDataInteractor(cacheData: storedData ?? .empty())
Expand All @@ -48,6 +51,7 @@ final class FlagApplierWithRetries: FlagApplier {
return
}

debugLogger?.logFlags(action: "Apply", flag: flagName)
self.writeToFile(data: data)
await triggerBatch()
}
Expand Down
50 changes: 41 additions & 9 deletions Sources/Confidence/Confidence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class Confidence: ConfidenceEventSender {
private var storage: Storage
private var cancellables = Set<AnyCancellable>()
private var currentFetchTask: Task<(), Never>?
private let debugLogger: DebugLogger?

// Internal for testing
internal let remoteFlagResolver: ConfidenceResolveClient
Expand All @@ -31,7 +32,8 @@ public class Confidence: ConfidenceEventSender {
storage: Storage,
context: ConfidenceStruct = [:],
parent: ConfidenceEventSender? = nil,
visitorId: String? = nil
visitorId: String? = nil,
debugLogger: DebugLogger?
) {
self.eventSenderEngine = eventSenderEngine
self.clientSecret = clientSecret
Expand All @@ -42,6 +44,7 @@ public class Confidence: ConfidenceEventSender {
self.storage = storage
self.flagApplier = flagApplier
self.remoteFlagResolver = remoteFlagResolver
self.debugLogger = debugLogger
if let visitorId {
putContext(context: ["visitor_id": ConfidenceValue.init(string: visitorId)])
}
Expand All @@ -57,7 +60,10 @@ public class Confidence: ConfidenceEventSender {
try await self.fetchAndActivate()
self.contextReconciliatedChanges.send(context.hash())
} catch {
// TODO: Log errors for debugging
debugLogger?.logMessage(
message: "\(error)",
isWarning: true
)
}
}
}
Expand All @@ -70,6 +76,7 @@ public class Confidence: ConfidenceEventSender {
public func activate() throws {
let savedFlags = try storage.load(defaultValue: FlagResolution.EMPTY)
self.cache = savedFlags
debugLogger?.logFlags(action: "Activate", flag: "")
}

/**
Expand All @@ -82,7 +89,10 @@ public class Confidence: ConfidenceEventSender {
do {
try await internalFetch()
} catch {
// TODO: Log errors for debugging
debugLogger?.logMessage(
nickybondarenko marked this conversation as resolved.
Show resolved Hide resolved
message: "\(error)",
isWarning: true
)
}
try activate()
}
Expand All @@ -95,6 +105,7 @@ public class Confidence: ConfidenceEventSender {
flags: resolvedFlags.resolvedValues,
resolveToken: resolvedFlags.resolveToken ?? ""
)
debugLogger?.logFlags(action: "Fetch", flag: "")
try storage.save(data: resolution)
}

Expand All @@ -107,7 +118,10 @@ public class Confidence: ConfidenceEventSender {
do {
try await internalFetch()
} catch {
// TODO: Log errors for debugging
debugLogger?.logMessage(
nickybondarenko marked this conversation as resolved.
Show resolved Hide resolved
message: "\(error )",
isWarning: true
)
}
}
}
Expand Down Expand Up @@ -209,6 +223,7 @@ public class Confidence: ConfidenceEventSender {
var map = confidence.contextSubject.value
map[key] = value
confidence.contextSubject.value = map
confidence.debugLogger?.logContext(action: "PutContext", context: confidence.contextSubject.value)
}
}

Expand All @@ -219,6 +234,7 @@ public class Confidence: ConfidenceEventSender {
map.updateValue(entry.value, forKey: entry.key)
}
confidence.contextSubject.value = map
confidence.debugLogger?.logContext(action: "PutContext", context: confidence.contextSubject.value)
}
}

Expand All @@ -232,6 +248,7 @@ public class Confidence: ConfidenceEventSender {
map.updateValue(entry.value, forKey: entry.key)
}
confidence.contextSubject.value = map
confidence.debugLogger?.logContext(action: "PutContext", context: confidence.contextSubject.value)
}
}

Expand All @@ -241,6 +258,7 @@ public class Confidence: ConfidenceEventSender {
map.removeValue(forKey: key)
confidence.contextSubject.value = map
confidence.removedContextKeys.insert(key)
confidence.debugLogger?.logContext(action: "RemoveContext", context: confidence.contextSubject.value)
}
}

Expand All @@ -256,7 +274,8 @@ public class Confidence: ConfidenceEventSender {
remoteFlagResolver: remoteFlagResolver,
storage: storage,
context: context,
parent: self)
parent: self,
debugLogger: debugLogger)
}
}

Expand All @@ -266,6 +285,7 @@ extension Confidence {
internal let clientSecret: String
internal let eventStorage: EventStorage
internal let visitorId = VisitorUtil().getId()
internal let loggerLevel: LoggerLevel

// Can be configured
internal var region: ConfidenceRegion = .global
Expand All @@ -280,13 +300,14 @@ extension Confidence {
/**
Initializes the builder with the given credentails.
*/
public init(clientSecret: String) {
public init(clientSecret: String, loggerLevel: LoggerLevel = .WARN) {
self.clientSecret = clientSecret
do {
eventStorage = try EventStorageImpl()
} catch {
eventStorage = EventStorageInMemory()
}
self.loggerLevel = loggerLevel
}

internal func withFlagResolverClient(flagResolver: ConfidenceResolveClient) -> Builder {
Expand Down Expand Up @@ -320,6 +341,13 @@ extension Confidence {
}

public func build() -> Confidence {
var debugLogger: DebugLogger?
if loggerLevel != LoggerLevel.NONE {
debugLogger = DebugLoggerImpl(loggerLevel: loggerLevel)
debugLogger?.logContext(action: "InitialContext", context: initialContext)
} else {
debugLogger = nil
}
let options = ConfidenceClientOptions(
credentials: ConfidenceClientCredentials.clientSecret(secret: clientSecret),
region: region)
Expand All @@ -335,7 +363,8 @@ extension Confidence {
httpClient: httpClient,
storage: DefaultStorage(filePath: "confidence.flags.apply"),
options: options,
metadata: metadata
metadata: metadata,
debugLogger: debugLogger
)
let flagResolver = flagResolver ?? RemoteConfidenceResolveClient(
options: options,
Expand All @@ -345,7 +374,9 @@ extension Confidence {
let eventSenderEngine = EventSenderEngineImpl(
clientSecret: clientSecret,
uploader: uploader,
storage: eventStorage)
storage: eventStorage,
debugLogger: debugLogger
)
return Confidence(
clientSecret: clientSecret,
region: region,
Expand All @@ -355,7 +386,8 @@ extension Confidence {
storage: storage ?? DefaultStorage(filePath: "confidence.flags.resolve"),
context: initialContext,
parent: nil,
visitorId: visitorId
visitorId: visitorId,
debugLogger: debugLogger
)
}
}
Expand Down
69 changes: 69 additions & 0 deletions Sources/Confidence/DebugLogger.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import Foundation
import OSLog

internal protocol DebugLogger {
nickybondarenko marked this conversation as resolved.
Show resolved Hide resolved
func logEvent(action: String, event: ConfidenceEvent?)
func logMessage(message: String, isWarning: Bool)
func logFlags(action: String, flag: String)
func logContext(action: String, context: ConfidenceStruct)
}

private extension Logger {
private static var subsystem = Bundle.main.bundleIdentifier

static let confidence = Logger(subsystem: subsystem ?? "", category: "confidence")
}

internal class DebugLoggerImpl: DebugLogger {
private let loggerLevel: LoggerLevel

init(loggerLevel: LoggerLevel) {
self.loggerLevel = loggerLevel
}

func logMessage(message: String, isWarning: Bool = false) {
if isWarning {
log(messageLevel: .WARN, message: message)
} else {
log(messageLevel: .DEBUG, message: message)
}
}

func logEvent(action: String, event: ConfidenceEvent?) {
log(messageLevel: .DEBUG, message: "[\(action)] \(event?.name ?? "")")
}

func logFlags(action: String, flag: String) {
log(messageLevel: .TRACE, message: "[\(action)] \(flag)")
}

func logContext(action: String, context: ConfidenceStruct) {
log(messageLevel: .TRACE, message: "[\(action)] \(context)")
}

private func log(messageLevel: LoggerLevel, message: String) {
if messageLevel >= loggerLevel {
switch messageLevel {
case .TRACE:
Logger.confidence.trace("\(message)")
case .DEBUG:
Logger.confidence.debug("\(message)")
case .WARN:
Logger.confidence.warning("\(message)")
case .ERROR:
Logger.confidence.error("\(message)")
case .NONE:
// do nothing
break
}
}
}
}

public enum LoggerLevel: Comparable {
case TRACE
case DEBUG
case WARN
case ERROR
case NONE
}
29 changes: 22 additions & 7 deletions Sources/Confidence/EventSenderEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ protocol FlushPolicy {
}

protocol EventSenderEngine {
func emit(eventName: String, data: ConfidenceStruct, context: ConfidenceStruct) throws
func emit(
eventName: String,
data: ConfidenceStruct,
context: ConfidenceStruct
) throws
func shutdown()
func flush()
}
Expand All @@ -25,18 +29,21 @@ final class EventSenderEngineImpl: EventSenderEngine {
private let payloadMerger: PayloadMerger = PayloadMergerImpl()
private let semaphore = DispatchSemaphore(value: 1)
private let writeQueue: DispatchQueue
private let debugLogger: DebugLogger?

convenience init(
clientSecret: String,
uploader: ConfidenceClient,
storage: EventStorage
storage: EventStorage,
debugLogger: DebugLogger?
) {
self.init(
clientSecret: clientSecret,
uploader: uploader,
storage: storage,
flushPolicies: [SizeFlushPolicy(batchSize: 10)],
writeQueue: DispatchQueue(label: "ConfidenceWriteQueue")
writeQueue: DispatchQueue(label: "ConfidenceWriteQueue"),
debugLogger: debugLogger
)
}

Expand All @@ -45,13 +52,15 @@ final class EventSenderEngineImpl: EventSenderEngine {
uploader: ConfidenceClient,
storage: EventStorage,
flushPolicies: [FlushPolicy],
writeQueue: DispatchQueue
writeQueue: DispatchQueue,
debugLogger: DebugLogger?
) {
self.uploader = uploader
self.clientSecret = clientSecret
self.storage = storage
self.flushPolicies = flushPolicies + [ManualFlushPolicy()]
self.writeQueue = writeQueue
self.debugLogger = debugLogger

writeReqChannel
.receive(on: self.writeQueue)
Expand Down Expand Up @@ -119,16 +128,22 @@ final class EventSenderEngineImpl: EventSenderEngine {
semaphore.signal()
}

func emit(eventName: String, data: ConfidenceStruct, context: ConfidenceStruct) throws {
writeReqChannel.send(ConfidenceEvent(
func emit(
eventName: String,
data: ConfidenceStruct,
context: ConfidenceStruct
) throws {
let event = ConfidenceEvent(
name: eventName,
payload: try payloadMerger.merge(context: context, data: data),
eventTime: Date.backport.now)
)
writeReqChannel.send(event)
debugLogger?.logEvent(action: "Emitting event", event: event)
}

func flush() {
writeReqChannel.send(manualFlushEvent)
debugLogger?.logEvent(action: "Event flushed", event: nil)
}

func shutdown() {
Expand Down
Loading
Loading