Skip to content

Commit 5ea7756

Browse files
committed
[feat]: external logging API
1 parent 235cfc0 commit 5ea7756

File tree

3 files changed

+84
-4
lines changed

3 files changed

+84
-4
lines changed

Diff for: Workflow/Sources/ExternalLogging.swift

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import Foundation
2+
3+
/// Namespace for logging API used to propagate internal Workflow-related logging to external consumers
4+
public enum ExternalLogging {}
5+
6+
extension ExternalLogging {
7+
/// Log level indicating 'severity' of the corresponding `LogEvent`
8+
public enum LogLevel {
9+
case info
10+
case error
11+
}
12+
13+
/// A log event
14+
public struct LogEvent {
15+
public let message: String
16+
public let level: LogLevel
17+
}
18+
19+
/// Wrapper that allows for propagating log events to outside consumers.
20+
internal struct ExternalLogger {
21+
private let implementation: (LogEvent) -> Void
22+
23+
internal init(_ implementation: @escaping (LogEvent) -> Void) {
24+
self.implementation = implementation
25+
}
26+
27+
internal func log(_ payload: LogEvent) { implementation(payload) }
28+
}
29+
30+
/// Shared external logger variable
31+
internal static var logger: ExternalLogger?
32+
33+
/// External logging bootstrapping method.
34+
/// Call once with the desired log handler.
35+
/// - Parameter logHandler: Callback to handle logging events.
36+
public static func configure(
37+
_ logHandler: @escaping (LogEvent) -> Void
38+
) {
39+
assert(
40+
logger == nil,
41+
"Workflow external logger already configured."
42+
)
43+
44+
logger = ExternalLogger(logHandler)
45+
}
46+
}
47+
48+
extension ExternalLogging.LogEvent {
49+
/// Convenience to create an info-level `LogEvent`
50+
static func info(_ message: String) -> Self {
51+
.init(message: message, level: .info)
52+
}
53+
54+
/// Convenience to create an error-level `LogEvent`
55+
static func error(_ message: String) -> Self {
56+
.init(message: message, level: .error)
57+
}
58+
}
59+
60+
extension ExternalLogging {
61+
// Logs an info message via the global logger (if set)
62+
static func logInfo(_ message: @autoclosure () -> String) {
63+
logger?.log(.info(message()))
64+
}
65+
66+
// Logs an error message via the global logger (if set)
67+
static func logError(_ message: @autoclosure () -> String) {
68+
logger?.log(.error(message()))
69+
}
70+
}

Diff for: Workflow/Sources/RenderContext.swift

+7-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,13 @@ public class RenderContext<WorkflowType: Workflow>: RenderContextType {
134134
}
135135

136136
private func assertStillValid() {
137-
assert(isValid, "A `RenderContext` instance was used outside of the workflow's `render` method. It is a programmer error to capture a context in a closure or otherwise cause it to be used outside of the `render` method.")
137+
guard isValid else {
138+
ExternalLogging.logError("""
139+
Detected an attempt to use an invalidated RenderContext for a workflow of type \(WorkflowType.self).
140+
""")
141+
assertionFailure("A `RenderContext` instance for a workflow of type \(WorkflowType.self) was used outside of the workflow's `render` method. It is a programmer error to capture a context in a closure or otherwise cause it to be used outside of the `render` method.")
142+
return
143+
}
138144
}
139145
}
140146
}

Diff for: Workflow/Sources/SubtreeManager.swift

+7-3
Original file line numberDiff line numberDiff line change
@@ -373,9 +373,13 @@ extension WorkflowNode.SubtreeManager {
373373
// If we're invalid and this is the first time `handle()` has
374374
// been called, then it's likely we've somehow been inadvertently
375375
// retained from the 'outside world'. Fail more loudly in this case.
376-
assert(isReentrantCall, """
377-
[\(WorkflowType.self)]: Sink sent an action after it was invalidated. This action will be ignored.
378-
""")
376+
if !isReentrantCall {
377+
var message: String {
378+
"[\(WorkflowType.self)]: Sink sent an action after it was invalidated. This action will be ignored."
379+
}
380+
ExternalLogging.logError(message)
381+
assertionFailure(message)
382+
}
379383
}
380384
}
381385

0 commit comments

Comments
 (0)