|  | 
|  | 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 | +} | 
0 commit comments