Skip to content

Commit 7c0782c

Browse files
authored
Merge pull request #30 from k-kohey/add_code_document
Add code document
2 parents 030fc07 + 39bc820 commit 7c0782c

15 files changed

+119
-84
lines changed

Sources/Parchment/AnyLoggable.swift

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ public struct AnyLoggable: Loggable {
3636
self.parameters = parameters
3737
}
3838

39+
/// Recursively searches for the instance `base` used to initialize this type and checks
40+
/// for the existence of an instance of the type passed as an argument.
41+
///
42+
/// This is useful for checking for lost type information, since type information is lost in conversions using `Parchment.Mutation`.
3943
@AnyLoggableActor
4044
public func isBased<T: Loggable>(_ type: T.Type) -> Bool {
4145
if findCache[id]?["\(T.self)"] == true {

Sources/Parchment/BufferFlowController.swift

+21
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,28 @@
66
//
77
import Foundation
88

9+
/// Helps in managing the flow of logs between LoggerBundler and LogBuffer.
10+
/// It provides functions for input and output operations on logs in a LogBuffer.
911
public protocol BufferFlowController: Sendable {
12+
/// Saves the given Payload to LogBuffer.
13+
///
14+
/// Depending on the LogBuffer implementation, it may be better to store a certain number of payloads at once.
15+
/// In such cases, this function can delay saving until a certain number of payloads are stored.
16+
///
17+
/// - Parameters:
18+
/// - _: The array of Payload objects to be saved.
19+
/// - buffer: The LogBuffer where the Payload objects will be saved.
1020
func input<T: LogBuffer>(_: [Payload], with buffer: T) async throws
21+
22+
/// Asynchronously read Payload from LogBuffer based on certain conditions
23+
///
24+
/// Read an arbitrary number of Logs from Buffer at an arbitrary timing
25+
/// using polling, observer patterns, etc., and send them to AsyncStream.
26+
///
27+
/// Note that if no events flow into the return value AsyncStream,
28+
/// the LoggerBundler will not be able to retrieve the buffered log from the LogBuffer.
29+
///
30+
/// - Parameter _: The LogBuffer from which the Payload objects will be loaded.
31+
/// - Returns: Stream for LoggerBundler to subscribe and send Log to LoggerComponent
1132
func output<T: LogBuffer>(with: T) async -> AsyncThrowingStream<[Payload], Error>
1233
}

Sources/Parchment/Configuration.swift

-35
This file was deleted.

Sources/Parchment/LogBuffer.swift

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// LogBuffer.swift
3+
//
4+
//
5+
// Created by k-kohey on 2021/12/29.
6+
//
7+
8+
import Foundation
9+
10+
/// `LogBuffer` represents a protocol for managing Payload objects.
11+
///
12+
/// By implementing this Protocol, Log can be buffered to an arbitrary location such as a text file or database.
13+
public protocol LogBuffer: Sendable {
14+
func enqueue(_ event: [Payload]) async throws
15+
func dequeue(limit: Int?) async throws -> [Payload]
16+
func count() async throws -> Int
17+
}
18+
19+
public extension LogBuffer {
20+
func load() async throws -> [Payload] {
21+
try await dequeue(limit: nil)
22+
}
23+
}

Sources/Parchment/LoggerBundler.swift

+24-15
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,13 @@ public final actor LoggerBundler {
1111
private let buffer: LogBuffer
1212
private let bufferFlowController: BufferFlowController
1313

14-
public var configMap: [LoggerComponentID: Configuration] = [:]
1514
private(set) var transform: Transform
1615

17-
private var loggingTask: Task<Void, Never>?
18-
1916
public init(
2017
components: [any LoggerComponent],
2118
buffer: some LogBuffer,
2219
bufferFlowController: some BufferFlowController,
23-
mutations: [Mutation] = []
20+
mutations: [any Mutation] = []
2421
) {
2522
self.components = components
2623
self.buffer = buffer
@@ -33,7 +30,9 @@ public final actor LoggerBundler {
3330
}
3431

3532
public func add(mutations: [Mutation]) {
36-
transform = [transform, mutations.composed()].composed()
33+
transform = [
34+
transform, mutations.composed()
35+
].composed()
3736
}
3837

3938
/// Sends a Log to the retained LoggerComponents.
@@ -90,6 +89,8 @@ public final actor LoggerBundler {
9089
}
9190
}
9291

92+
/// Dequeue Log from Buffer and start sending Log to LoggerComponent.
93+
/// The number and timing of Log dequeues are determined by BufferFlowController.
9394
@discardableResult
9495
public func startLogging() -> Task<Void, Error> {
9596
Task {
@@ -115,16 +116,34 @@ public final actor LoggerBundler {
115116
}
116117

117118
public extension LoggerBundler {
119+
/// Log sending timing
118120
enum LoggingPolicy: Sendable {
121+
/// requires the log o be sent to LoggerComponent immediately without storing it in the buffer.
122+
/// When this is specified, logs can be sent ignoring the waiting order of buffer.
119123
case immediately
120124
case bufferingFirst
121125
}
122126

127+
/// Scope of sending logs
128+
///
129+
/// If specified as follows, Logs are sent only to the LoggerComponent
130+
/// whose LoggerComponentID is defined as myLogger.
131+
///
132+
/// extension LoggerComponentID {
133+
/// static var myLogger: LoggerComponentID = { .init("myLogger") }
134+
/// }
135+
///
136+
/// await logger.send(
137+
/// event,
138+
/// with: .init(scope: .only(.myLogger))
139+
/// )
123140
enum LoggerScope: Sendable {
124141
case only([LoggerComponentID])
125142
case exclude([LoggerComponentID])
126143
}
127144

145+
/// Settings on how logs are sent
146+
/// The default settings sends logs to all LoggerComponents after first storing them in a buffer
128147
struct LoggingOption: Sendable {
129148
let policy: LoggingPolicy
130149
let scope: LoggerScope?
@@ -139,16 +158,6 @@ public extension LoggerBundler {
139158
}
140159
}
141160

142-
public extension LoggerBundler {
143-
struct Configuration {
144-
let allowBuffering: Bool
145-
146-
public init(allowBuffering: Bool) {
147-
self.allowBuffering = allowBuffering
148-
}
149-
}
150-
}
151-
152161
public extension LoggerBundler {
153162
func send(event: TrackingEvent, with option: LoggingOption = .init()) async {
154163
await send(event, with: option)

Sources/Parchment/LoggerComponent.swift

+9
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,17 @@ public protocol LoggerSendable: Sendable {
1919
var timestamp: Date { get }
2020
}
2121

22+
/// Sending logs to your server or SDK such as Firebase.
2223
public protocol LoggerComponent: Sendable {
24+
25+
/// A unique identifier.
26+
/// This definition allows the user to specify an id when sending logs.
2327
static var id: LoggerComponentID { get }
28+
29+
/// Sends an array of `LoggerSendable` objects asynchronously.
30+
///
31+
/// - Parameter _: The array of `LoggerSendable` objects to send.
32+
/// - Returns: A boolean indicating whether the operation was successful.
2433
func send(_: [any LoggerSendable]) async -> Bool
2534
}
2635

Sources/Parchment/Mutation.swift

+18-1
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,25 @@ import Foundation
99

1010
typealias Transform = @Sendable @AnyLoggableActor (Loggable, LoggerComponentID) -> AnyLoggable
1111

12+
/// Transform a given log into another log.
13+
///
14+
/// If there are parameters that should be inserted for all logs, such as UserID and Timestamp,
15+
/// `Mutation` can be used to implement this.
16+
///
17+
/// The example below illustrates how to use `Mutation` to insert a UserID into the parameters of a log.
18+
/// By implementing it in this way, it saves the effort of inserting this into each individual log.
19+
///
20+
/// struct UserIDMutation: Mutation {
21+
/// let userID: ID
22+
///
23+
/// func transform(_ e: Loggable, id: LoggerComponentID) -> AnyLoggable {
24+
/// var e = AnyLoggable(e)
25+
/// e.parameters["userID"] = userID
26+
/// return e
27+
/// }
28+
/// }
1229
public protocol Mutation: Sendable {
13-
@AnyLoggableActor
30+
@AnyLoggableActor
1431
func transform(_: any Loggable, id: LoggerComponentID) -> AnyLoggable
1532
}
1633

Sources/Parchment/Tracked.swift

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77

88
import Foundation
99

10+
/// Logs changes to a value.
11+
///
12+
/// Mark the properties for which you wish to log changes as follows.
13+
///
14+
/// @Tracked(name: "age", with: logger) var age: Int
15+
/// @Tracked(name: "age", with: logger, scope: \.age) var state: State
1016
@propertyWrapper
1117
public struct Tracked<Value: Sendable, ScopeValue: Sendable> {
1218
private let logger: LoggerBundler

Sources/Parchment/TrackingEventBuffer.swift

-20
This file was deleted.

Sources/Parchment/View+track.swift

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ private struct Impletion: ViewModifier {
3636
}
3737

3838
public extension View {
39+
/// Hook onAppear to send ImpletionEvent
3940
func track(
4041
screen name: String,
4142
with logger: LoggerBundler,

Sources/ParchmentDefault/DefaultBufferFlowController.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public final class DefaultBufferFlowController: BufferFlowController, Sendable {
3434
_ events: [Payload], with buffer: T
3535
) async throws {
3636
@Sendable @MainActor func save() async throws {
37-
try await buffer.save(inputAccumulationPayloads)
37+
try await buffer.enqueue(inputAccumulationPayloads)
3838
inputAccumulationPayloads = []
3939
}
4040

Sources/ParchmentDefault/SQLiteBuffer.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public final actor SQLiteBuffer: LogBuffer {
4141
)
4242
}
4343

44-
public func save(_ e: [Payload]) throws {
44+
public func enqueue(_ e: [Payload]) throws {
4545
try db.run(
4646
try events.insertMany(
4747
e.map {
@@ -58,7 +58,7 @@ public final actor SQLiteBuffer: LogBuffer {
5858
)
5959
}
6060

61-
public func load(limit: Int?) throws -> [Payload] {
61+
public func dequeue(limit: Int?) throws -> [Payload] {
6262
let target = events.order(Column.timestamp).limit(limit)
6363
let entities = try db.prepare(target)
6464
.map { $0[Column.event] }

Tests/ParchmentDefaultTests/DefaultBufferFlowControllerTests.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ import XCTest
1313
final class EventQueueMock: LogBuffer, @unchecked Sendable {
1414
private var records: [Payload] = []
1515

16-
func save(_ e: [Payload]) {
16+
func enqueue(_ e: [Payload]) {
1717
records += e
1818
}
1919

20-
func load(limit: Int?) async throws -> [Parchment.Payload] {
20+
func dequeue(limit: Int?) async throws -> [Parchment.Payload] {
2121
let count: Int
2222
if let limit {
2323
count = limit
@@ -115,7 +115,7 @@ class RegularlyPollingSchedulerTests: XCTestCase {
115115
return
116116
}
117117
}
118-
buffer.save([.init(destination: "hoge", event: event, timestamp: Date())])
118+
buffer.enqueue([.init(destination: "hoge", event: event, timestamp: Date())])
119119

120120
while outputEvent == nil {
121121
await Task.yield()

Tests/ParchmentDefaultTests/SQLiteBufferTests.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ final class SQLiteBufferTests: XCTestCase {
3131
)
3232
]
3333

34-
try await db.save(records)
34+
try await db.enqueue(records)
3535
let results = try await db.load()
3636

3737
XCTAssertEqual(
@@ -68,7 +68,7 @@ final class SQLiteBufferTests: XCTestCase {
6868
XCTAssertEqual(initalState, 0)
6969

7070
do {
71-
try await db.save(records)
71+
try await db.enqueue(records)
7272
let result = try await db.count()
7373
XCTAssertEqual(result, 3)
7474
}
@@ -104,8 +104,8 @@ final class SQLiteBufferTests: XCTestCase {
104104
)
105105
]
106106

107-
try await db.save(records)
108-
let result = try await db.load(limit: 2)
107+
try await db.enqueue(records)
108+
let result = try await db.dequeue(limit: 2)
109109

110110
let count = try await db.count()
111111
XCTAssertEqual(count, 1)

Tests/ParchmentTests/Stub.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ final class LoggerB: LoggerComponent, @unchecked Sendable {
3535
final class EventQueueMock: LogBuffer, @unchecked Sendable {
3636
private var records: [Payload] = []
3737

38-
func save(_ e: [Payload]) {
38+
func enqueue(_ e: [Payload]) {
3939
records += e
4040
}
4141

42-
func load(limit: Int?) async throws -> [Parchment.Payload] {
42+
func dequeue(limit: Int?) async throws -> [Parchment.Payload] {
4343
let count: Int
4444
if let limit {
4545
count = limit
@@ -71,7 +71,7 @@ final class BufferedEventFlushStrategyMock: BufferFlowController, @unchecked Sen
7171
private var continuation: AsyncThrowingStream<[Payload], Error>.Continuation?
7272

7373
func input<T: LogBuffer>(_ payloads: [Payload], with buffer: T) async throws {
74-
try await buffer.save(payloads)
74+
try await buffer.enqueue(payloads)
7575
}
7676

7777
func output<T: LogBuffer>(with buffer: T) async -> AsyncThrowingStream<[Payload], Error> {

0 commit comments

Comments
 (0)