Last active
November 12, 2018 13:27
-
-
Save daehn/b13e01162cb1ae4f3c9bd1dfa24766e9 to your computer and use it in GitHub Desktop.
Lightweight logging class supporting different topics
This file contains 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 | |
final class Log: NSObject { | |
enum Topic: String { | |
case network, app | |
} | |
private enum Level: String { | |
case info = "" | |
case warn = "❌" | |
} | |
var isEnabled: Bool { | |
return Environment.current.logTopics.contains(topic) | |
} | |
static var dateFormatter: DateFormatter = { | |
let formatter = DateFormatter() | |
formatter.timeStyle = .medium | |
formatter.dateStyle = .short | |
return formatter | |
}() | |
private let topic: Topic | |
init(topic: Topic) { | |
self.topic = topic | |
} | |
private func log( | |
level: Level, | |
message: String, | |
file: String = #file, | |
function: String = #function, | |
line: Int = #line | |
) { | |
guard isEnabled else { return } | |
let fileUrl = URL(fileURLWithPath: file) | |
let fileExtension = fileUrl.pathExtension | |
let fileName = fileUrl.deletingPathExtension().lastPathComponent | |
let date = Log.dateFormatter.string(from: .init()) | |
let source = "\(fileName).\(fileExtension):\(line) \(function)" | |
var output = "\(date) [\(topic.rawValue.uppercased())] \(source): \(message)" | |
if !level.rawValue.isEmpty { | |
output = "\(level.rawValue) \(output)" | |
} | |
// FIXME: Using `print` is probably not the best choice here, in theory it would be best to | |
// use os_log as seen here: https://github.com/jaredsinclair/etcetera/blob/master/OSLog.swift. | |
print(output) | |
} | |
func info( | |
_ message: String, | |
file: String = #file, | |
function: String = #function, | |
line: Int = #line | |
) { | |
log(level: .info, message: message, file: file, function: function, line: line) | |
} | |
func warn( | |
_ message: String, | |
file: String = #file, | |
function: String = #function, | |
line: Int = #line | |
) { | |
log(level: .warn, message: message, file: file, function: function, line: line) | |
} | |
} | |
// MARK: - Environment | |
struct Environment { | |
static let current = Environment() | |
/// Add cases here to use them in Scheme (⌘ ⇧ ,) → Run → Environment Variables | |
private enum Keys: String { | |
case logTopics = "LogTopics" | |
case runningTests = "XCTestConfigurationFilePath" | |
} | |
enum Configuration: String { | |
case debug, release | |
} | |
let isRunningTests: Bool | |
let logTopics: Set<Log.Topic> | |
private init() { | |
let env = ProcessInfo.processInfo.environment | |
isRunningTests = nil != env[Keys.runningTests] | |
switch (Environment.buildConfiguration, isRunningTests) { | |
case (.release, _), (.debug, true): | |
// Disable logs when running in release configuration or when running tests. | |
logTopics = [] | |
case (.debug, false): | |
let topics = env[Keys.logTopics]?.components(separatedBy: ",") ?? [] | |
logTopics = Set(topics.compactMap { Log.Topic(rawValue: $0.lowercased()) }) | |
} | |
} | |
static var buildConfiguration: Configuration { | |
#if RELEASE | |
return .release | |
#else | |
return .debug | |
#endif | |
} | |
} | |
// MARK: - CustomStringConvertible | |
extension Environment: CustomStringConvertible { | |
var description: String { | |
let configuration = Environment.buildConfiguration.rawValue.uppercased() | |
let logs = "Enabled log topics: \(logTopics.map { "\"\($0)\"" }.joined(separator: ", "))" | |
return "Configuration: \(configuration). \(logs).\n" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment