Created
February 8, 2017 19:23
-
-
Save zwaldowski/08135f6a579e79a241db9ed85d667533 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
/// A type representing an concrete part of an application, such that it can be | |
/// identified in logs. | |
/// | |
/// A typical use is as a nested type: | |
/// | |
/// extension MyViewController { | |
/// enum Log: Error { | |
/// case user | |
/// case network | |
/// } | |
/// | |
/// @IBAction func userTappedButton(_ sender: Any) { | |
/// Log.user.debug("They tapped the button!") | |
/// } | |
/// | |
/// func requestFailed(error: Error) { | |
/// Log.network.error("Could not log in: %@", error) | |
/// } | |
/// } | |
/// | |
protocol LogSubsystem { | |
/// The name of a subsystem, such as "com.myapp.networking". | |
/// | |
/// By default, the fully-qualified name of `self`. | |
static var name: String { get } | |
/// A stage or grouping for a subsystem, such as "setup" or "teardown". | |
/// | |
/// By default, the description of `self`. | |
var categoryName: String { get } | |
/// Whether to print `debug` messages. | |
static var isDebugEnabled: Bool { get } | |
/// Whether to print `info` messages. | |
static var isInfoEnabled: Bool { get } | |
} | |
/// A type with a customized log representation. | |
/// | |
/// Types that conform to the `CustomLogStringConvertible` protocol can provide | |
/// their own representation to be used when logging using a `LogSubsystem`. | |
/// | |
/// Accessing a type's `logDescription` property directly is discouraged. | |
protocol CustomLogStringConvertible { | |
/// A console log representation of `self`. | |
var logDescription: String { get } | |
} | |
extension String { | |
/// Creates a console log representing the given value. | |
init<Subject>(logging value: Subject) { | |
if let subject = value as? CustomLogStringConvertible { | |
self = String(describing: subject.logDescription) | |
} else { | |
self = String(describing: value) | |
} | |
} | |
} | |
extension LogSubsystem { | |
static var name: String { | |
return String(reflecting: self) | |
} | |
var categoryName: String { | |
return String(describing: self) | |
} | |
static var isDebugEnabled: Bool { | |
return false | |
} | |
static var isInfoEnabled: Bool { | |
return false | |
} | |
} | |
extension LogSubsystem { | |
/// Logging shim. This was intended to be backed by `os_log`, but as of | |
/// Xcode 8.2 that unconditionally mirrors to `stderr`, which completely | |
/// defeats the point. | |
/// | |
/// When a future Xcode fixes this (probably the next one, see link below), | |
/// the prototypes below could be changed to something a la: | |
/// | |
/// func log(_ message: StaticString, dso: UnsafeRawPointer?, level: OSLogType, _ arguments: [Any]) | |
/// | |
/// And encoding the `os_log` buffer from there. | |
/// | |
/// - see: https://github.com/apple/swift-lldb/blob/swift-3.1-branch/docs/structured_data/DarwinLog.md | |
private func log(_ message: StaticString, _ arguments: [Any]) { | |
let cArguments = arguments.map { (argument) -> CVarArg in | |
switch argument { | |
case let value as CustomLogStringConvertible: | |
return value.logDescription as NSString | |
case let value as CVarArg: | |
return value | |
default: | |
return String(describing: argument) as NSString | |
} | |
} | |
withVaList(cArguments) { | |
NSLogv("[\(categoryName)] \(message)", $0) | |
} | |
} | |
func debug(_ message: StaticString, _ arguments: Any...) { | |
guard Self.isDebugEnabled else { return } | |
log(message, arguments) | |
} | |
func info(_ message: StaticString, _ arguments: Any...) { | |
guard Self.isInfoEnabled else { return } | |
log(message, arguments) | |
} | |
func show(_ message: StaticString, _ arguments: Any...) { | |
log(message, arguments) | |
} | |
func error(_ message: StaticString, _ arguments: Any...) { | |
log(message, arguments) | |
} | |
func fault(_ message: StaticString, _ arguments: Any...) { | |
log(message, arguments) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment