Skip to content

Commit 1580762

Browse files
Improve loggers
1 parent dc2586b commit 1580762

File tree

6 files changed

+121
-106
lines changed

6 files changed

+121
-106
lines changed
Lines changed: 35 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,17 @@
11
import PowerSyncKotlin
22

3-
/// Maps a Kermit `Severity` level to a local `LogSeverity`.
4-
///
5-
/// - Parameter severity: The Kermit log severity value from Kotlin.
6-
/// - Returns: The corresponding `LogSeverity` used in Swift.
7-
private func mapKermitSeverity(_ severity: PowerSyncKotlin.Kermit_coreSeverity) -> LogSeverity {
8-
switch severity {
9-
case PowerSyncKotlin.Kermit_coreSeverity.verbose:
10-
return LogSeverity.debug
11-
case PowerSyncKotlin.Kermit_coreSeverity.debug:
12-
return LogSeverity.debug
13-
case PowerSyncKotlin.Kermit_coreSeverity.info:
14-
return LogSeverity.info
15-
case PowerSyncKotlin.Kermit_coreSeverity.warn:
16-
return LogSeverity.warning
17-
case PowerSyncKotlin.Kermit_coreSeverity.error:
18-
return LogSeverity.error
19-
case PowerSyncKotlin.Kermit_coreSeverity.assert:
20-
return LogSeverity.fault
21-
}
22-
}
23-
24-
/// Maps a local `LogSeverity` to a Kermit-compatible `Kermit_coreSeverity`.
25-
///
26-
/// - Parameter severity: The Swift-side `LogSeverity`.
27-
/// - Returns: The equivalent Kermit log severity.
28-
private func mapSeverity(_ severity: LogSeverity) -> PowerSyncKotlin.Kermit_coreSeverity {
29-
switch severity {
30-
case .debug:
31-
return PowerSyncKotlin.Kermit_coreSeverity.debug
32-
case .info:
33-
return PowerSyncKotlin.Kermit_coreSeverity.info
34-
case .warning:
35-
return PowerSyncKotlin.Kermit_coreSeverity.warn
36-
case .error:
37-
return PowerSyncKotlin.Kermit_coreSeverity.error
38-
case .fault:
39-
return PowerSyncKotlin.Kermit_coreSeverity.assert
40-
}
41-
}
42-
43-
/// Adapts a Swift `LogWritterProtocol` to Kermit's `LogWriter` interface.
3+
/// Adapts a Swift `LoggerProtocol` to Kermit's `LogWriter` interface.
444
///
455
/// This allows Kotlin logging (via Kermit) to call into the Swift logging implementation.
466
private class KermitLogWriterAdapter: Kermit_coreLogWriter {
477
/// The underlying Swift log writer to forward log messages to.
48-
var adapter: LogWriterProtocol
8+
let logger: any LoggerProtocol
499

5010
/// Initializes a new adapter.
5111
///
5212
/// - Parameter adapter: A Swift log writer that will handle log output.
53-
init(adapter: LogWriterProtocol) {
54-
self.adapter = adapter
13+
init(logger: any LoggerProtocol) {
14+
self.logger = logger
5515
super.init()
5616
}
5717

@@ -63,27 +23,42 @@ private class KermitLogWriterAdapter: Kermit_coreLogWriter {
6323
/// - tag: An optional string categorizing the log.
6424
/// - throwable: An optional Kotlin exception (ignored here).
6525
override func log(severity: Kermit_coreSeverity, message: String, tag: String, throwable: KotlinThrowable?) {
66-
adapter.log(
67-
severity: mapKermitSeverity(severity),
68-
message: message,
69-
tag: tag
70-
)
26+
switch severity {
27+
case PowerSyncKotlin.Kermit_coreSeverity.verbose:
28+
return logger.debug(message, tag: tag)
29+
case PowerSyncKotlin.Kermit_coreSeverity.debug:
30+
return logger.debug(message, tag: tag)
31+
case PowerSyncKotlin.Kermit_coreSeverity.info:
32+
return logger.info(message, tag: tag)
33+
case PowerSyncKotlin.Kermit_coreSeverity.warn:
34+
return logger.warning(message, tag: tag)
35+
case PowerSyncKotlin.Kermit_coreSeverity.error:
36+
return logger.error(message, tag: tag)
37+
case PowerSyncKotlin.Kermit_coreSeverity.assert:
38+
return logger.fault(message, tag: tag)
39+
}
7140
}
7241
}
7342

7443
/// A logger implementation that integrates with PowerSync's Kotlin backend using Kermit.
7544
///
7645
/// This class bridges Swift log writers with the Kotlin logging system and supports
7746
/// runtime configuration of severity levels and writer lists.
78-
public class DatabaseLogger: LoggerProtocol {
47+
internal class DatabaseLogger: LoggerProtocol {
7948
/// The underlying Kermit logger instance provided by the PowerSyncKotlin SDK.
80-
internal let kLogger = PowerSyncKotlin.generateLogger(logger: nil)
49+
public let kLogger = PowerSyncKotlin.generateLogger(logger: nil)
50+
public let logger: any LoggerProtocol
8151

8252
/// Initializes a new logger with an optional list of writers.
8353
///
8454
/// - Parameter writers: An array of Swift log writers. Defaults to an empty array.
85-
init(writers: [any LogWriterProtocol] = []) {
86-
setWriters(writers)
55+
init(_ logger: any LoggerProtocol) {
56+
self.logger = logger
57+
// Set to the lowest severity. The adapter downstream logger should filter by severity
58+
kLogger.mutableConfig.setMinSeverity(Kermit_coreSeverity.verbose)
59+
kLogger.mutableConfig.setLogWriterList(
60+
[KermitLogWriterAdapter(logger: logger)]
61+
)
8762
}
8863

8964
/// Sets the minimum severity level that will be logged.
@@ -92,9 +67,7 @@ public class DatabaseLogger: LoggerProtocol {
9267
///
9368
/// - Parameter severity: The minimum `LogSeverity` to allow through.
9469
public func setMinSeverity(_ severity: LogSeverity) {
95-
kLogger.mutableConfig.setMinSeverity(
96-
mapSeverity(severity)
97-
)
70+
logger.setMinSeverity(severity)
9871
}
9972

10073
/// Sets the list of log writers that will receive log messages.
@@ -103,33 +76,31 @@ public class DatabaseLogger: LoggerProtocol {
10376
///
10477
/// - Parameter writers: An array of Swift `LogWritterProtocol` implementations.
10578
public func setWriters(_ writers: [any LogWriterProtocol]) {
106-
kLogger.mutableConfig.setLogWriterList(
107-
writers.map { item in KermitLogWriterAdapter(adapter: item) }
108-
)
79+
logger.setWriters(writers)
10980
}
11081

11182
/// Logs a debug-level message.
11283
public func debug(_ message: String, tag: String) {
113-
kLogger.d(messageString: message, throwable: nil, tag: tag)
84+
logger.debug(message, tag: tag)
11485
}
11586

11687
/// Logs an info-level message.
11788
public func info(_ message: String, tag: String) {
118-
kLogger.i(messageString: message, throwable: nil, tag: tag)
89+
logger.info(message, tag: tag)
11990
}
12091

12192
/// Logs a warning-level message.
12293
public func warning(_ message: String, tag: String) {
123-
kLogger.w(messageString: message, throwable: nil, tag: tag)
94+
logger.warning(message, tag: tag)
12495
}
12596

12697
/// Logs an error-level message.
12798
public func error(_ message: String, tag: String) {
128-
kLogger.e(messageString: message, throwable: nil, tag: tag)
99+
logger.error(message, tag: tag)
129100
}
130101

131102
/// Logs a fault (assert-level) message, typically used for critical issues.
132103
public func fault(_ message: String, tag: String) {
133-
kLogger.a(messageString: message, throwable: nil, tag: tag)
104+
logger.fault(message, tag: tag)
134105
}
135106
}

Sources/PowerSync/Logger.swift

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import OSLog
22

3-
/// A log writer that bridges custom `LogSeverity` levels to Apple's unified `Logger` framework.
3+
/// A log writer which prints to the standard output
44
///
55
/// This writer uses `os.Logger` on iOS 14+ and falls back to `print` for earlier versions.
6-
/// Tags are optionally prefixed to messages in square brackets.
7-
public class SwiftLogWriter: LogWriterProtocol {
6+
public class PrintLogWriter: LogWriterProtocol {
87

98
/// Logs a message with a given severity and optional tag.
109
///
@@ -39,14 +38,54 @@ public class SwiftLogWriter: LogWriterProtocol {
3938
/// A default logger configuration that uses `SwiftLogWritter` and filters messages by minimum severity.
4039
///
4140
/// This logger integrates with your custom logging system and uses `os.Logger` under the hood.
42-
public class DefaultLogger: DatabaseLogger {
41+
public class DefaultLogger: LoggerProtocol {
42+
public var minSeverirty: LogSeverity
43+
public var writers: [any LogWriterProtocol]
4344

4445
/// Initializes the default logger with an optional minimum severity level.
4546
///
4647
/// - Parameter minSeverity: The minimum severity level to log. Defaults to `.debug`.
47-
public init(minSeverity: LogSeverity = .debug) {
48-
super.init()
49-
setMinSeverity(minSeverity)
50-
setWriters([SwiftLogWriter()])
48+
public init(minSeverity: LogSeverity = .debug, writers: [any LogWriterProtocol]? = nil ) {
49+
self.writers = writers ?? [ PrintLogWriter() ]
50+
self.minSeverirty = minSeverity
51+
}
52+
53+
public func setWriters(_ writters: [any LogWriterProtocol]) {
54+
self.writers = writters
55+
}
56+
57+
public func setMinSeverity(_ severity: LogSeverity) {
58+
self.minSeverirty = severity
59+
}
60+
61+
62+
public func debug(_ message: String, tag: String) {
63+
self.writeLog(message, tag: tag, severity: LogSeverity.debug)
64+
}
65+
66+
public func error(_ message: String, tag: String) {
67+
self.writeLog(message, tag: tag, severity: LogSeverity.error)
68+
}
69+
70+
public func info(_ message: String, tag: String) {
71+
self.writeLog(message, tag: tag, severity: LogSeverity.info)
72+
}
73+
74+
public func warning(_ message: String, tag: String) {
75+
self.writeLog(message, tag: tag, severity: LogSeverity.warning)
76+
}
77+
78+
public func fault(_ message: String, tag: String) {
79+
self.writeLog(message, tag: tag, severity: LogSeverity.fault)
80+
}
81+
82+
private func writeLog(_ message: String, tag: String, severity: LogSeverity) {
83+
if (severity.rawValue < self.minSeverirty.rawValue) {
84+
return
85+
}
86+
87+
for writer in self.writers {
88+
writer.log(severity: severity, message: message, tag: tag)
89+
}
5190
}
5291
}

Sources/PowerSync/LoggerProtocol.swift

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,34 @@
1-
/// Represents the severity level of a log message.
2-
public enum LogSeverity: String, CaseIterable {
3-
/// Informational messages that highlight the progress of the application.
4-
case info = "INFO"
5-
6-
/// Error events that might still allow the application to continue running.
7-
case error = "ERROR"
8-
1+
public enum LogSeverity: Int, CaseIterable {
92
/// Detailed information typically used for debugging.
10-
case debug = "DEBUG"
11-
3+
case debug = 0
4+
5+
/// Informational messages that highlight the progress of the application.
6+
case info = 1
7+
128
/// Potentially harmful situations that are not necessarily errors.
13-
case warning = "WARNING"
14-
9+
case warning = 2
10+
11+
/// Error events that might still allow the application to continue running.
12+
case error = 3
13+
1514
/// Serious errors indicating critical failures, often unrecoverable.
16-
case fault = "FAULT"
15+
case fault = 4
16+
17+
/// Map severity to its string representation
18+
public var stringValue: String {
19+
switch self {
20+
case .debug: return "DEBUG"
21+
case .info: return "INFO"
22+
case .warning: return "WARNING"
23+
case .error: return "ERROR"
24+
case .fault: return "FAULT"
25+
}
26+
}
27+
28+
/// Convert Int to String representation
29+
public static func string(from intValue: Int) -> String? {
30+
return LogSeverity(rawValue: intValue)?.stringValue
31+
}
1732
}
1833

1934
/// A protocol for writing log messages to a specific backend or output.

Sources/PowerSync/PowerSyncDatabase.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ public let DEFAULT_DB_FILENAME = "powersync.db"
1212
public func PowerSyncDatabase(
1313
schema: Schema,
1414
dbFilename: String = DEFAULT_DB_FILENAME,
15-
logger: DatabaseLogger = DefaultLogger()
15+
logger: (any LoggerProtocol)? = nil
1616
) -> PowerSyncDatabaseProtocol {
1717

1818
return KotlinPowerSyncDatabaseImpl(
1919
schema: schema,
2020
dbFilename: dbFilename,
21-
logger: logger
21+
logger: logger != nil ? DatabaseLogger(logger!) : nil
2222
)
2323
}

Tests/PowerSyncTests/Kotlin/KotlinPowerSyncDatabaseImplTests.swift

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ final class KotlinPowerSyncDatabaseImplTests: XCTestCase {
1717
database = KotlinPowerSyncDatabaseImpl(
1818
schema: schema,
1919
dbFilename: ":memory:",
20-
logger: DefaultLogger()
20+
logger: DatabaseLogger(DefaultLogger())
2121
)
2222
try await database.disconnectAndClear()
2323
}
@@ -472,17 +472,18 @@ final class KotlinPowerSyncDatabaseImplTests: XCTestCase {
472472
}
473473

474474
func testCustomLogger() async throws {
475-
let logger = TestLogger()
475+
let testWriter = TestLogWriterAdapter()
476+
let logger = DefaultLogger(minSeverity: LogSeverity.debug, writers: [testWriter])
476477

477478
let db2 = KotlinPowerSyncDatabaseImpl(
478479
schema: schema,
479480
dbFilename: ":memory:",
480-
logger: logger
481+
logger: DatabaseLogger(logger)
481482
)
482483

483484
try await db2.close()
484485

485-
let warningIndex = logger.logs.firstIndex(
486+
let warningIndex = testWriter.logs.firstIndex(
486487
where: { value in
487488
value.contains("warning: Multiple PowerSync instances for the same database have been detected")
488489
}
@@ -492,17 +493,18 @@ final class KotlinPowerSyncDatabaseImplTests: XCTestCase {
492493
}
493494

494495
func testMinimumSeverity() async throws {
495-
let logger = TestLogger(minSeverity: .error)
496+
let testWriter = TestLogWriterAdapter()
497+
let logger = DefaultLogger(minSeverity: LogSeverity.error, writers: [testWriter])
496498

497499
let db2 = KotlinPowerSyncDatabaseImpl(
498500
schema: schema,
499501
dbFilename: ":memory:",
500-
logger: logger
502+
logger: DatabaseLogger(logger)
501503
)
502504

503505
try await db2.close()
504506

505-
let warningIndex = logger.logs.firstIndex(
507+
let warningIndex = testWriter.logs.firstIndex(
506508
where: { value in
507509
value.contains("warning: Multiple PowerSync instances for the same database have been detected")
508510
}

Tests/PowerSyncTests/Kotlin/TestLogger.swift

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,3 @@ class TestLogWriterAdapter: LogWriterProtocol {
99
}
1010
}
1111

12-
class TestLogger: DefaultLogger {
13-
let writer = TestLogWriterAdapter()
14-
15-
public var logs: [String] {
16-
return writer.logs
17-
}
18-
19-
override init(minSeverity: LogSeverity = .debug) {
20-
super.init(minSeverity: minSeverity)
21-
setWriters([writer])
22-
}
23-
}

0 commit comments

Comments
 (0)