17
17
import os. signpost
18
18
19
19
private extension OSLog {
20
+ /// Logging will use this log handle when enabled
20
21
static let workflow = OSLog ( subsystem: " com.squareup.Workflow " , category: " Workflow " )
22
+
23
+ /// The active log handle to use when logging. Defaults to the shared `.disabled` handle.
24
+ static var active : OSLog = . disabled
25
+ }
26
+
27
+ // MARK: -
28
+
29
+ /// Namespace for specifying logging configuration data.
30
+ public enum WorkflowLogging { }
31
+
32
+ extension WorkflowLogging {
33
+ public struct Config {
34
+ /// Configuration options to control logging during a render pass.
35
+ public enum RenderLoggingMode {
36
+ /// No data will be recorded for WorkflowNode render timings.
37
+ case none
38
+
39
+ /// Render timings will only be recorded for root nodes in a Workflow tree.
40
+ case rootsOnly
41
+
42
+ /// Render timings will be recorded for all nodes in a Workflow tree.
43
+ /// N.B. performance may be noticeably impacted when using this option.
44
+ case allNodes
45
+ }
46
+
47
+ public var renderLoggingMode : RenderLoggingMode = . allNodes
48
+
49
+ /// When `true`, the interval spanning a WorkflowNode's lifetime will be recorded.
50
+ public var logLifetimes = true
51
+
52
+ /// When `true`, action events will be recorded.
53
+ public var logActions = true
54
+ }
55
+
56
+ /// Global setting to enable or disable logging.
57
+ /// Note, this is independent of the specified `config` value, and simply governs whether
58
+ /// the runtime should emit any logs.
59
+ ///
60
+ /// To enable logging, at a minimum you must set:
61
+ /// `WorkflowLogging.enabled = true`
62
+ ///
63
+ /// If you wish for more control over what the runtime will log, you may additionally specify
64
+ /// a custom value for `WorkflowLogging.config`.
65
+ public static var enabled : Bool {
66
+ get { OSLog . active === OSLog . workflow }
67
+ set { OSLog . active = newValue ? . workflow : . disabled }
68
+ }
69
+
70
+ /// Configuration options used to determine which activities are logged.
71
+ public static var config : Config = . rootRendersAndActions
72
+ }
73
+
74
+ extension WorkflowLogging . Config {
75
+ /// Logging config that will output the most information.
76
+ /// Will also have the most noticeable effect on performance.
77
+ public static let debug : Self = . init( renderLoggingMode: . allNodes, logLifetimes: true , logActions: true )
78
+
79
+ /// Logging config that will record render timings for root nodes as well as action events.
80
+ /// This provides a reasonable performance tradeoff if you're interested in the runtime's behavior
81
+ /// but don't wan to pay the price of logging everything.
82
+ public static let rootRendersAndActions : Self = . init( renderLoggingMode: . rootsOnly, logLifetimes: false , logActions: true )
21
83
}
22
84
23
85
// MARK: -
@@ -32,10 +94,12 @@ final class WorkflowLogger {
32
94
33
95
static func logWorkflowStarted< WorkflowType> ( ref: WorkflowNode < WorkflowType > ) {
34
96
if #available( iOS 12 . 0 , macOS 10 . 14 , * ) {
35
- let signpostID = OSSignpostID ( log: . workflow, object: ref)
97
+ guard WorkflowLogging . config. logLifetimes else { return }
98
+
99
+ let signpostID = OSSignpostID ( log: . active, object: ref)
36
100
os_signpost (
37
101
. begin,
38
- log: . workflow ,
102
+ log: . active ,
39
103
name: " Alive " ,
40
104
signpostID: signpostID,
41
105
" Workflow: %{public}@ " ,
@@ -46,17 +110,21 @@ final class WorkflowLogger {
46
110
47
111
static func logWorkflowFinished< WorkflowType> ( ref: WorkflowNode < WorkflowType > ) {
48
112
if #available( iOS 12 . 0 , macOS 10 . 14 , * ) {
49
- let signpostID = OSSignpostID ( log: . workflow, object: ref)
50
- os_signpost ( . end, log: . workflow, name: " Alive " , signpostID: signpostID)
113
+ guard WorkflowLogging . config. logLifetimes else { return }
114
+
115
+ let signpostID = OSSignpostID ( log: . active, object: ref)
116
+ os_signpost ( . end, log: . active, name: " Alive " , signpostID: signpostID)
51
117
}
52
118
}
53
119
54
120
static func logSinkEvent< Action: WorkflowAction > ( ref: AnyObject , action: Action ) {
55
121
if #available( iOS 12 . 0 , macOS 10 . 14 , * ) {
56
- let signpostID = OSSignpostID ( log: . workflow, object: ref)
122
+ guard WorkflowLogging . config. logActions else { return }
123
+
124
+ let signpostID = OSSignpostID ( log: . active, object: ref)
57
125
os_signpost (
58
126
. event,
59
- log: . workflow ,
127
+ log: . active ,
60
128
name: " Sink Event " ,
61
129
signpostID: signpostID,
62
130
" Event for workflow: %{public}@ " ,
@@ -67,12 +135,20 @@ final class WorkflowLogger {
67
135
68
136
// MARK: Rendering
69
137
70
- static func logWorkflowStartedRendering< WorkflowType> ( ref: WorkflowNode < WorkflowType > ) {
138
+ static func logWorkflowStartedRendering< WorkflowType> (
139
+ ref: WorkflowNode < WorkflowType > ,
140
+ isRootNode: Bool
141
+ ) {
71
142
if #available( iOS 12 . 0 , macOS 10 . 14 , * ) {
72
- let signpostID = OSSignpostID ( log: . workflow, object: ref)
143
+ guard shouldLogRenderTimingsForMode (
144
+ WorkflowLogging . config. renderLoggingMode,
145
+ isRootNode: isRootNode
146
+ ) else { return }
147
+
148
+ let signpostID = OSSignpostID ( log: . active, object: ref)
73
149
os_signpost (
74
150
. begin,
75
- log: . workflow ,
151
+ log: . active ,
76
152
name: " Render " ,
77
153
signpostID: signpostID,
78
154
" Render Workflow: %{public}@ " ,
@@ -81,10 +157,34 @@ final class WorkflowLogger {
81
157
}
82
158
}
83
159
84
- static func logWorkflowFinishedRendering< WorkflowType> ( ref: WorkflowNode < WorkflowType > ) {
160
+ static func logWorkflowFinishedRendering< WorkflowType> (
161
+ ref: WorkflowNode < WorkflowType > ,
162
+ isRootNode: Bool
163
+ ) {
85
164
if #available( iOS 12 . 0 , macOS 10 . 14 , * ) {
86
- let signpostID = OSSignpostID ( log: . workflow, object: ref)
87
- os_signpost ( . end, log: . workflow, name: " Render " , signpostID: signpostID)
165
+ guard shouldLogRenderTimingsForMode (
166
+ WorkflowLogging . config. renderLoggingMode,
167
+ isRootNode: isRootNode
168
+ ) else { return }
169
+
170
+ let signpostID = OSSignpostID ( log: . active, object: ref)
171
+ os_signpost ( . end, log: . active, name: " Render " , signpostID: signpostID)
172
+ }
173
+ }
174
+
175
+ // MARK: - Utilities
176
+
177
+ private static func shouldLogRenderTimingsForMode(
178
+ _ renderLoggingMode: WorkflowLogging . Config . RenderLoggingMode ,
179
+ isRootNode: Bool
180
+ ) -> Bool {
181
+ switch WorkflowLogging . config. renderLoggingMode {
182
+ case . none:
183
+ return false
184
+ case . rootsOnly where !isRootNode:
185
+ return false
186
+ default :
187
+ return true
88
188
}
89
189
}
90
190
}
0 commit comments