Last active
June 13, 2024 02:00
-
-
Save wata/00b243a57590e95e81f7d21c0004a9c1 to your computer and use it in GitHub Desktop.
os_log と Crashlytics を使ったロガークラス
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 | |
import os.log | |
import FirebaseCrashlytics | |
extension OSLogType: CustomStringConvertible { | |
public var description: String { | |
switch self { | |
case OSLogType.debug: return "🔹🔹🔹" | |
case OSLogType.info: return "ℹ️ℹ️ℹ️" | |
case OSLogType.error: return "‼️‼️‼️" | |
case OSLogType.fault: return "😱😱😱" | |
default: return "DEFAULT" | |
} | |
} | |
} | |
// https://github.com/mono0926/mono-kit/blob/master/Lib/Logger.swift | |
// https://gist.github.com/yoichitgy/8806a7da3a52d8e6f5207e6a1a11b5a8 | |
// https://developer.apple.com/reference/os/logging | |
struct Logger { | |
private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "default") | |
fileprivate init() {} | |
/// Log something at the Debug log level for debug info. | |
/// ✅ Console | |
/// ❌ CLSLogv | |
/// ❌ recordError | |
/// ❌ assertionFailure | |
func debug(_ message: @autoclosure () -> Any?, | |
functionName: CustomStringConvertible = #function, | |
fileName: CustomStringConvertible = #file, | |
lineNumber: Int = #line) { | |
doLog(message(), logType: .debug, functionName: functionName, fileName: fileName, lineNumber: lineNumber) | |
} | |
/// Log something at the Info log level for trace info. | |
/// ✅ Console | |
/// ✅ CLSLogv | |
/// ❌ recordError | |
/// ❌ assertionFailure | |
func info(_ message: @autoclosure () -> Any?, | |
functionName: CustomStringConvertible = #function, | |
fileName: CustomStringConvertible = #file, | |
lineNumber: Int = #line) { | |
doLog(message(), logType: .info, functionName: functionName, fileName: fileName, lineNumber: lineNumber) | |
doCLSLog(message(), logType: .info, functionName: functionName, fileName: fileName, lineNumber: lineNumber) | |
} | |
/// Log something at the Error log level for handleable error. | |
/// ✅ Console | |
/// ✅ CLSLogv | |
/// ❌ recordError | |
/// ❌ assertionFailure | |
func error(_ message: @autoclosure () -> Any?, | |
functionName: CustomStringConvertible = #function, | |
fileName: CustomStringConvertible = #file, | |
lineNumber: Int = #line) { | |
doLog(message(), logType: .error, functionName: functionName, fileName: fileName, lineNumber: lineNumber) | |
doCLSLog(message(), logType: .info, functionName: functionName, fileName: fileName, lineNumber: lineNumber) | |
} | |
/// Log something at the Fault log level for unexpected error. | |
/// ✅ Console | |
/// ❌ CLSLogv | |
/// ✅ recordError | |
/// ✅ assertionFailure | |
func fault(_ message: @autoclosure () -> Any?, | |
functionName: CustomStringConvertible = #function, | |
fileName: CustomStringConvertible = #file, | |
lineNumber: Int = #line) { | |
doLog(message(), logType: .fault, functionName: functionName, fileName: fileName, lineNumber: lineNumber) | |
doCLSRecordError(message(), functionName: functionName, fileName: fileName, lineNumber: lineNumber) | |
doAssertionFailure(message()) | |
} | |
func `default`(_ message: @autoclosure () -> Any?, | |
functionName: CustomStringConvertible = #function, | |
fileName: CustomStringConvertible = #file, | |
lineNumber: Int = #line) { | |
doLog(message(), logType: .default, functionName: functionName, fileName: fileName, lineNumber: lineNumber) | |
} | |
fileprivate func doLog(_ message: @autoclosure () -> Any?, | |
logType: OSLogType, | |
functionName: CustomStringConvertible, | |
fileName: CustomStringConvertible, | |
lineNumber: Int) { | |
let staticSelf = type(of: self) | |
let log = staticSelf.log | |
guard log.isEnabled(type: logType) else { return } | |
guard let output = staticSelf.buildOutput(message(), | |
logType: logType, | |
functionName: functionName, | |
fileName: fileName, | |
lineNumber: lineNumber) else { return } | |
os_log("%@", log: log, type: logType, output) | |
} | |
fileprivate func doCLSLog(_ message: @autoclosure () -> Any?, | |
logType: OSLogType, | |
functionName: CustomStringConvertible, | |
fileName: CustomStringConvertible, | |
lineNumber: Int) { | |
let staticSelf = type(of: self) | |
guard let output = staticSelf.buildOutput(message(), | |
logType: logType, | |
functionName: functionName, | |
fileName: fileName, | |
lineNumber: lineNumber) else { return } | |
Crashlytics.crashlytics().log(output) | |
} | |
fileprivate func doCLSRecordError(_ message: @autoclosure () -> Any?, | |
functionName: CustomStringConvertible, | |
fileName: CustomStringConvertible, | |
lineNumber: Int) { | |
let staticSelf = type(of: self) | |
guard let error = staticSelf.buildError(message(), | |
functionName: functionName, | |
fileName: fileName, | |
lineNumber: lineNumber) else { return } | |
Crashlytics.crashlytics().record(error: error) | |
} | |
fileprivate func doAssertionFailure(_ message: @autoclosure () -> Any?) { | |
guard let message = message() else { return } | |
assertionFailure(String(describing: message)) | |
} | |
static func buildOutput(_ message: @autoclosure () -> Any?, | |
logType: OSLogType, | |
functionName: CustomStringConvertible, | |
fileName: CustomStringConvertible, | |
lineNumber: Int) -> String? { | |
guard let message = message() else { return nil } | |
return "[\(logType)] [\(threadName)] [\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber)] \(functionName) > \(message)" | |
} | |
static func buildError(_ message: @autoclosure () -> Any?, | |
functionName: CustomStringConvertible, | |
fileName: CustomStringConvertible, | |
lineNumber: Int) -> Error? { | |
guard let message = message() else { return nil } | |
return NSError(domain: "\(fileName):\(functionName)", code: lineNumber, userInfo: ["message": message]) | |
} | |
private static var threadName: String { | |
if Thread.isMainThread { | |
return "main" | |
} | |
if let threadName = Thread.current.name, !threadName.isEmpty { | |
return threadName | |
} | |
if let queueName = DispatchQueue.currentQueueLabel, !queueName.isEmpty { | |
return queueName | |
} | |
return String(format: "[%p] ", Thread.current) | |
} | |
} | |
extension DispatchQueue { | |
static var currentQueueLabel: String? { | |
return String(validatingUTF8: __dispatch_queue_get_label(nil)) | |
} | |
} | |
let log = Logger() |
updated: 2020-05-07
Fabric SDK => Firebase Crashlytics SDK
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
.debug
.info
.error
.fault