SwiftyBeaver.swift 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. //
  2. // SwiftyBeaver.swift
  3. // SwiftyBeaver
  4. //
  5. // Created by Sebastian Kreutzberger (Twitter @skreutzb) on 28.11.15.
  6. // Copyright © 2015 Sebastian Kreutzberger
  7. // Some rights reserved: http://opensource.org/licenses/MIT
  8. //
  9. import Foundation
  10. open class SwiftyBeaver {
  11. /// version string of framework
  12. public static let version = "1.9.4" // UPDATE ON RELEASE!
  13. /// build number of framework
  14. public static let build = 1940 // version 1.6.2 -> 1620, UPDATE ON RELEASE!
  15. public enum Level: Int {
  16. case verbose = 0
  17. case debug = 1
  18. case info = 2
  19. case warning = 3
  20. case error = 4
  21. }
  22. // a set of active destinations
  23. public private(set) static var destinations = Set<BaseDestination>()
  24. // MARK: Destination Handling
  25. /// returns boolean about success
  26. @discardableResult
  27. open class func addDestination(_ destination: BaseDestination) -> Bool {
  28. if destinations.contains(destination) {
  29. return false
  30. }
  31. destinations.insert(destination)
  32. return true
  33. }
  34. /// returns boolean about success
  35. @discardableResult
  36. open class func removeDestination(_ destination: BaseDestination) -> Bool {
  37. if destinations.contains(destination) == false {
  38. return false
  39. }
  40. destinations.remove(destination)
  41. return true
  42. }
  43. /// if you need to start fresh
  44. open class func removeAllDestinations() {
  45. destinations.removeAll()
  46. }
  47. /// returns the amount of destinations
  48. open class func countDestinations() -> Int {
  49. return destinations.count
  50. }
  51. /// returns the current thread name
  52. class func threadName() -> String {
  53. #if os(Linux)
  54. // on 9/30/2016 not yet implemented in server-side Swift:
  55. // > import Foundation
  56. // > Thread.isMainThread
  57. return ""
  58. #else
  59. if Thread.isMainThread {
  60. return ""
  61. } else {
  62. let name = __dispatch_queue_get_label(nil)
  63. return String(cString: name, encoding: .utf8) ?? Thread.current.description
  64. }
  65. #endif
  66. }
  67. // MARK: Levels
  68. /// log something generally unimportant (lowest priority)
  69. open class func verbose(_ message: @autoclosure () -> Any, _
  70. file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) {
  71. #if swift(>=5)
  72. custom(level: .verbose, message: message(), file: file, function: function, line: line, context: context)
  73. #else
  74. custom(level: .verbose, message: message, file: file, function: function, line: line, context: context)
  75. #endif
  76. }
  77. /// log something which help during debugging (low priority)
  78. open class func debug(_ message: @autoclosure () -> Any, _
  79. file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) {
  80. #if swift(>=5)
  81. custom(level: .debug, message: message(), file: file, function: function, line: line, context: context)
  82. #else
  83. custom(level: .debug, message: message, file: file, function: function, line: line, context: context)
  84. #endif
  85. }
  86. /// log something which you are really interested but which is not an issue or error (normal priority)
  87. open class func info(_ message: @autoclosure () -> Any, _
  88. file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) {
  89. #if swift(>=5)
  90. custom(level: .info, message: message(), file: file, function: function, line: line, context: context)
  91. #else
  92. custom(level: .info, message: message, file: file, function: function, line: line, context: context)
  93. #endif
  94. }
  95. /// log something which may cause big trouble soon (high priority)
  96. open class func warning(_ message: @autoclosure () -> Any, _
  97. file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) {
  98. #if swift(>=5)
  99. custom(level: .warning, message: message(), file: file, function: function, line: line, context: context)
  100. #else
  101. custom(level: .warning, message: message, file: file, function: function, line: line, context: context)
  102. #endif
  103. }
  104. /// log something which will keep you awake at night (highest priority)
  105. open class func error(_ message: @autoclosure () -> Any, _
  106. file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) {
  107. #if swift(>=5)
  108. custom(level: .error, message: message(), file: file, function: function, line: line, context: context)
  109. #else
  110. custom(level: .error, message: message, file: file, function: function, line: line, context: context)
  111. #endif
  112. }
  113. /// custom logging to manually adjust values, should just be used by other frameworks
  114. open class func custom(level: SwiftyBeaver.Level, message: @autoclosure () -> Any,
  115. file: String = #file, function: String = #function, line: Int = #line, context: Any? = nil) {
  116. #if swift(>=5)
  117. dispatch_send(level: level, message: message(), thread: threadName(),
  118. file: file, function: function, line: line, context: context)
  119. #else
  120. dispatch_send(level: level, message: message, thread: threadName(),
  121. file: file, function: function, line: line, context: context)
  122. #endif
  123. }
  124. /// internal helper which dispatches send to dedicated queue if minLevel is ok
  125. class func dispatch_send(level: SwiftyBeaver.Level, message: @autoclosure () -> Any,
  126. thread: String, file: String, function: String, line: Int, context: Any?) {
  127. var resolvedMessage: String?
  128. for dest in destinations {
  129. guard let queue = dest.queue else {
  130. continue
  131. }
  132. resolvedMessage = resolvedMessage == nil && dest.hasMessageFilters() ? "\(message())" : resolvedMessage
  133. if dest.shouldLevelBeLogged(level, path: file, function: function, message: resolvedMessage) {
  134. // try to convert msg object to String and put it on queue
  135. let msgStr = resolvedMessage == nil ? "\(message())" : resolvedMessage!
  136. let f = stripParams(function: function)
  137. if dest.asynchronously {
  138. queue.async {
  139. _ = dest.send(level, msg: msgStr, thread: thread, file: file, function: f, line: line, context: context)
  140. }
  141. } else {
  142. queue.sync {
  143. _ = dest.send(level, msg: msgStr, thread: thread, file: file, function: f, line: line, context: context)
  144. }
  145. }
  146. }
  147. }
  148. }
  149. /**
  150. DEPRECATED & NEEDS COMPLETE REWRITE DUE TO SWIFT 3 AND GENERAL INCORRECT LOGIC
  151. Flush all destinations to make sure all logging messages have been written out
  152. Returns after all messages flushed or timeout seconds
  153. - returns: true if all messages flushed, false if timeout or error occurred
  154. */
  155. public class func flush(secondTimeout: Int64) -> Bool {
  156. /*
  157. guard let grp = dispatch_group_create() else { return false }
  158. for dest in destinations {
  159. if let queue = dest.queue {
  160. dispatch_group_enter(grp)
  161. queue.asynchronously(execute: {
  162. dest.flush()
  163. grp.leave()
  164. })
  165. }
  166. }
  167. let waitUntil = DispatchTime.now(dispatch_time_t(DISPATCH_TIME_NOW), secondTimeout * 1000000000)
  168. return dispatch_group_wait(grp, waitUntil) == 0
  169. */
  170. return true
  171. }
  172. /// removes the parameters from a function because it looks weird with a single param
  173. class func stripParams(function: String) -> String {
  174. var f = function
  175. if let indexOfBrace = f.find("(") {
  176. #if swift(>=4.0)
  177. f = String(f[..<indexOfBrace])
  178. #else
  179. f = f.substring(to: indexOfBrace)
  180. #endif
  181. }
  182. f += "()"
  183. return f
  184. }
  185. }