Skip to content

Commit 6052f3c

Browse files
Add network logging support
1 parent bf1c952 commit 6052f3c

File tree

6 files changed

+166
-26
lines changed

6 files changed

+166
-26
lines changed

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
11
# Changelog
22

3+
## 1.4.0
4+
5+
* Added the ability to log PowerSync network requests.
6+
```swift
7+
struct InlineLogger: NetworkLogger {
8+
func log(_ message: String) {
9+
print("Network: \(message)")
10+
}
11+
}
12+
13+
try await db.connect(
14+
connector: connector,
15+
options: ConnectOptions(
16+
clientConfiguration: SyncClientConfiguration(
17+
networkLogger: NetworkLoggerConfig(
18+
logLevel: .headers,
19+
logger: InlineLogger()
20+
)
21+
)
22+
)
23+
)
24+
```
25+
326
## 1.3.0
427

528
* Use version `0.4.2` of the PowerSync core extension, which improves the reliability

Demo/PowerSyncExample/PowerSync/SystemManager.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ func getAttachmentsDirectoryPath() throws -> String {
1313

1414
let logTag = "SystemManager"
1515

16+
struct InlineLogger: NetworkLogger {
17+
func log(_ message: String) {
18+
print("Network: \(message)")
19+
}
20+
}
21+
1622
@Observable
1723
class SystemManager {
1824
let connector = SupabaseConnector()
@@ -70,7 +76,17 @@ class SystemManager {
7076

7177
func connect() async {
7278
do {
73-
try await db.connect(connector: connector)
79+
try await db.connect(
80+
connector: connector,
81+
options: ConnectOptions(
82+
clientConfiguration: SyncClientConfiguration(
83+
networkLogger: NetworkLoggerConfig(
84+
logLevel: .headers,
85+
logger: InlineLogger()
86+
)
87+
)
88+
)
89+
)
7490
try await attachments?.startSync()
7591
} catch {
7692
print("Unexpected error: \(error.localizedDescription)") // Catches any other error
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import PowerSyncKotlin
2+
3+
extension NetworkLogLevel {
4+
func toKotlin() -> SwiftNetworkLogLevel {
5+
switch self {
6+
case .all:
7+
return SwiftNetworkLogLevel.all
8+
case .headers:
9+
return SwiftNetworkLogLevel.headers
10+
case .body:
11+
return SwiftNetworkLogLevel.body
12+
case .info:
13+
return SwiftNetworkLogLevel.info
14+
case .none:
15+
return SwiftNetworkLogLevel.none
16+
}
17+
}
18+
}
19+
20+
extension NetworkLoggerConfig {
21+
func toKotlinConfig() -> SwiftNetworkLoggerConfig {
22+
return SwiftNetworkLoggerConfig(
23+
logLevel: self.logLevel.toKotlin(),
24+
log: { [logger] message in
25+
logger.log(message)
26+
}
27+
)
28+
}
29+
}

Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,6 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol {
5252
)
5353

5454
let resolvedOptions = options ?? ConnectOptions()
55-
let useWebsockets = switch (resolvedOptions.connectionMethod) {
56-
case .http: false
57-
case .webSocket: true
58-
}
5955

6056
try await kotlinDatabase.connect(
6157
connector: connectorAdapter,
@@ -64,8 +60,8 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol {
6460
params: resolvedOptions.params.mapValues { $0.toKotlinMap() },
6561
options: createSyncOptions(
6662
newClient: resolvedOptions.newClientImplementation,
67-
webSocket: useWebsockets,
68-
userAgent: "PowerSync Swift SDK"
63+
userAgent: "PowerSync Swift SDK",
64+
loggingConfig: resolvedOptions.clientConfiguration?.networkLogger?.toKotlinConfig()
6965
)
7066
)
7167
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/// A logger which handles PowerSync network request logs.
2+
///
3+
/// Implement this protocol to receive network logging messages at the level
4+
/// specified in `NetworkLoggerConfig`. The `log(_:)` method will be called
5+
/// for each network event that meets the configured logging criteria.
6+
public protocol NetworkLogger {
7+
/// Logs a network-related message.
8+
/// - Parameter message: The formatted log message to record
9+
func log(_ message: String)
10+
}
11+
12+
/// Level of logs to expose to a `NetworkLogger` handler.
13+
///
14+
/// Controls the verbosity of network logging for PowerSync HTTP requests.
15+
/// The log level is configured once during initialization and determines
16+
/// which network events will be logged throughout the session.
17+
public enum NetworkLogLevel {
18+
/// Log all network activity including headers, body, and info
19+
case all
20+
/// Log only request/response headers
21+
case headers
22+
/// Log only request/response body content
23+
case body
24+
/// Log basic informational messages about requests
25+
case info
26+
/// Disable all network logging
27+
case none
28+
}
29+
30+
/// Configuration for PowerSync HTTP request logging.
31+
///
32+
/// This configuration is set once during initialization and used throughout
33+
/// the PowerSync session. The `logLevel` determines which network events
34+
/// are logged, while the `logger` handles the actual log output.
35+
///
36+
/// - Note: The log level cannot be changed after initialization. A new call to `PowerSyncDatabase.connect` is required to change the level.
37+
public struct NetworkLoggerConfig {
38+
/// The logging level that determines which network events are logged.
39+
/// Set once during initialization and used throughout the session.
40+
public let logLevel: NetworkLogLevel
41+
42+
/// The logger instance that receives network log messages.
43+
/// Must conform to `NetworkLogger` protocol.
44+
public let logger: NetworkLogger
45+
46+
/// Creates a new network logger configuration.
47+
/// - Parameters:
48+
/// - logLevel: The `NetworkLogLevel` to use for filtering log messages
49+
/// - logger: A `NetworkLogger` instance to handle log output
50+
public init(logLevel: NetworkLogLevel, logger: NetworkLogger) {
51+
self.logLevel = logLevel
52+
self.logger = logger
53+
}
54+
}

Sources/PowerSync/Protocol/PowerSyncDatabaseProtocol.swift

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
11
import Foundation
22

3+
/// Configuration for the sync client used to connect to the PowerSync service.
4+
///
5+
/// Provides options to customize network behavior and logging for PowerSync
6+
/// HTTP requests and responses.
7+
public struct SyncClientConfiguration {
8+
/// Optional configuration for logging PowerSync HTTP requests.
9+
///
10+
/// When provided, network requests will be logged according to the
11+
/// specified `NetworkLogLevel`. The `logLevel` is set during initialization
12+
/// and remains constant throughout the PowerSync session.
13+
///
14+
/// Set to `nil` to disable network logging entirely.
15+
///
16+
/// - SeeAlso: `NetworkLoggerConfig` for configuration options
17+
public let networkLogger: NetworkLoggerConfig?
18+
19+
/// Creates a new sync client configuration.
20+
/// - Parameter networkLogger: Optional network logger configuration
21+
public init(networkLogger: NetworkLoggerConfig? = nil) {
22+
self.networkLogger = networkLogger
23+
}
24+
}
25+
326
/// Options for configuring a PowerSync connection.
427
///
528
/// Provides optional parameters to customize sync behavior such as throttling and retry policies.
@@ -41,31 +64,37 @@ public struct ConnectOptions {
4164
/// We encourage interested users to try the new client.
4265
@_spi(PowerSyncExperimental)
4366
public var newClientImplementation: Bool
44-
45-
/// The connection method used to connect to the Powersync service.
67+
68+
/// Configuration for the sync client used for PowerSync requests.
4669
///
47-
/// The default method is ``ConnectionMethod/http``. Using ``ConnectionMethod/webSocket(_:)`` can
48-
/// improve performance as a more efficient binary protocol is used. However, using the websocket connection method
49-
/// requires enabling ``ConnectOptions/newClientImplementation``.
50-
@_spi(PowerSyncExperimental)
51-
public var connectionMethod: ConnectionMethod
70+
/// Provides options to customize network behavior including logging of HTTP
71+
/// requests and responses. When `nil`, default HTTP client settings are used
72+
/// with no network logging.
73+
///
74+
/// Set this to configure network logging or other HTTP client behaviors
75+
/// specific to PowerSync operations.
76+
///
77+
/// - SeeAlso: `SyncClientConfiguration` for available configuration options
78+
public var clientConfiguration: SyncClientConfiguration?
5279

5380
/// Initializes a `ConnectOptions` instance with optional values.
5481
///
5582
/// - Parameters:
5683
/// - crudThrottle: TimeInterval between CRUD operations in milliseconds. Defaults to `1` second.
5784
/// - retryDelay: Delay TimeInterval between retry attempts in milliseconds. Defaults to `5` seconds.
5885
/// - params: Custom sync parameters to send to the server. Defaults to an empty dictionary.
86+
/// - clientConfiguration: Configuration for the HTTP client used to connect to PowerSync.
5987
public init(
6088
crudThrottle: TimeInterval = 1,
6189
retryDelay: TimeInterval = 5,
62-
params: JsonParam = [:]
90+
params: JsonParam = [:],
91+
clientConfiguration: SyncClientConfiguration? = nil
6392
) {
6493
self.crudThrottle = crudThrottle
6594
self.retryDelay = retryDelay
6695
self.params = params
6796
self.newClientImplementation = false
68-
self.connectionMethod = .http
97+
self.clientConfiguration = clientConfiguration
6998
}
7099

71100
/// Initializes a ``ConnectOptions`` instance with optional values, including experimental options.
@@ -75,22 +104,16 @@ public struct ConnectOptions {
75104
retryDelay: TimeInterval = 5,
76105
params: JsonParam = [:],
77106
newClientImplementation: Bool = false,
78-
connectionMethod: ConnectionMethod = .http
107+
clientConfiguration: SyncClientConfiguration? = nil
79108
) {
80109
self.crudThrottle = crudThrottle
81110
self.retryDelay = retryDelay
82111
self.params = params
83112
self.newClientImplementation = newClientImplementation
84-
self.connectionMethod = connectionMethod
113+
self.clientConfiguration = clientConfiguration
85114
}
86115
}
87116

88-
@_spi(PowerSyncExperimental)
89-
public enum ConnectionMethod {
90-
case http
91-
case webSocket
92-
}
93-
94117
/// A PowerSync managed database.
95118
///
96119
/// Use one instance per database file.
@@ -108,7 +131,6 @@ public protocol PowerSyncDatabaseProtocol: Queries {
108131
/// Wait for the first sync to occur
109132
func waitForFirstSync() async throws
110133

111-
112134
/// Replace the schema with a new version. This is for advanced use cases - typically the schema
113135
/// should just be specified once in the constructor.
114136
///
@@ -247,7 +269,7 @@ public extension PowerSyncDatabaseProtocol {
247269
}
248270

249271
func disconnectAndClear(clearLocal: Bool = true) async throws {
250-
try await self.disconnectAndClear(clearLocal: clearLocal)
272+
try await disconnectAndClear(clearLocal: clearLocal)
251273
}
252274

253275
func getCrudBatch(limit: Int32 = 100) async throws -> CrudBatch? {

0 commit comments

Comments
 (0)